From 30dd7eee31428b46aef2f71d7edb95971d7d2d90 Mon Sep 17 00:00:00 2001 From: Bradford Wetmore Date: Tue, 23 Oct 2012 12:36:47 -0700 Subject: [PATCH 01/59] 7197071: Makefiles for various security providers aren't including the default manifest Reviewed-by: valeriep, mullan, katleman --- jdk/make/com/oracle/security/ucrypto/Makefile | 4 +- jdk/make/javax/crypto/Defs-jce.gmk | 4 +- jdk/make/sun/security/ec/Makefile | 4 +- jdk/make/sun/security/mscapi/Makefile | 4 +- jdk/make/sun/security/pkcs11/Makefile | 4 +- .../sanity/CheckManifestForRelease.java | 123 ++++++++++++++++++ 6 files changed, 133 insertions(+), 10 deletions(-) create mode 100644 jdk/test/javax/crypto/sanity/CheckManifestForRelease.java diff --git a/jdk/make/com/oracle/security/ucrypto/Makefile b/jdk/make/com/oracle/security/ucrypto/Makefile index f6545e89828..f779bf47170 100644 --- a/jdk/make/com/oracle/security/ucrypto/Makefile +++ b/jdk/make/com/oracle/security/ucrypto/Makefile @@ -198,9 +198,9 @@ ifndef OPENJDK # # Build ucrypto.jar. # - $(UNSIGNED_DIR)/ucrypto.jar: build + $(UNSIGNED_DIR)/ucrypto.jar: build $(JCE_MANIFEST_FILE) $(prep-target) - $(BOOT_JAR_CMD) cf $@ $(JAR_DIRS) \ + $(BOOT_JAR_CMD) cmf $(JCE_MANIFEST_FILE) $@ $(JAR_DIRS) \ $(BOOT_JAR_JFLAGS) @$(java-vm-cleanup) diff --git a/jdk/make/javax/crypto/Defs-jce.gmk b/jdk/make/javax/crypto/Defs-jce.gmk index 7aecdc0a754..6203129b17b 100644 --- a/jdk/make/javax/crypto/Defs-jce.gmk +++ b/jdk/make/javax/crypto/Defs-jce.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ include $(BUILDDIR)/common/Release.gmk JCE_MANIFEST_FILE = $(TEMPDIR)/manifest.mf $(JCE_MANIFEST_FILE): $(MAINMANIFEST) $(prep-target) - $(SED) -e "s#@@RELEASE@@#$(RELEASE)#" \ + $(SED) -e "s#@@RELEASE@@#$(JDK_VERSION)#" \ -e "s#@@COMPANY_NAME@@#$(COMPANY_NAME)#" \ $(MAINMANIFEST) >> $@ $(ECHO) "Extension-Name: javax.crypto" >> $@ diff --git a/jdk/make/sun/security/ec/Makefile b/jdk/make/sun/security/ec/Makefile index 660d8bbd0f8..f04ec0eec17 100644 --- a/jdk/make/sun/security/ec/Makefile +++ b/jdk/make/sun/security/ec/Makefile @@ -246,9 +246,9 @@ build-jar: $(UNSIGNED_DIR)/sunec.jar # # Build sunec.jar. # -$(UNSIGNED_DIR)/sunec.jar: build +$(UNSIGNED_DIR)/sunec.jar: build $(JCE_MANIFEST_FILE) $(prep-target) - $(BOOT_JAR_CMD) cf $@ $(JAR_DIRS) \ + $(BOOT_JAR_CMD) cmf $(JCE_MANIFEST_FILE) $@ $(JAR_DIRS) \ $(BOOT_JAR_JFLAGS) @$(java-vm-cleanup) diff --git a/jdk/make/sun/security/mscapi/Makefile b/jdk/make/sun/security/mscapi/Makefile index 1cd6024a9c4..d48a1819f74 100644 --- a/jdk/make/sun/security/mscapi/Makefile +++ b/jdk/make/sun/security/mscapi/Makefile @@ -209,9 +209,9 @@ build-jar: $(UNSIGNED_DIR)/sunmscapi.jar # # Build sunmscapi.jar. # -$(UNSIGNED_DIR)/sunmscapi.jar: build +$(UNSIGNED_DIR)/sunmscapi.jar: build $(JCE_MANIFEST_FILE) $(prep-target) - $(BOOT_JAR_CMD) cf $@ $(JAR_DIRS) \ + $(BOOT_JAR_CMD) cmf $(JCE_MANIFEST_FILE) $@ $(JAR_DIRS) \ $(BOOT_JAR_JFLAGS) @$(java-vm-cleanup) diff --git a/jdk/make/sun/security/pkcs11/Makefile b/jdk/make/sun/security/pkcs11/Makefile index ecdba0997da..cdf5b12b009 100644 --- a/jdk/make/sun/security/pkcs11/Makefile +++ b/jdk/make/sun/security/pkcs11/Makefile @@ -225,9 +225,9 @@ build-jar: $(UNSIGNED_DIR)/sunpkcs11.jar # # Build sunpkcs11.jar. # -$(UNSIGNED_DIR)/sunpkcs11.jar: build +$(UNSIGNED_DIR)/sunpkcs11.jar: build $(JCE_MANIFEST_FILE) $(prep-target) - $(BOOT_JAR_CMD) cf $@ $(JAR_DIRS) \ + $(BOOT_JAR_CMD) cmf $(JCE_MANIFEST_FILE) $@ $(JAR_DIRS) \ $(BOOT_JAR_JFLAGS) @$(java-vm-cleanup) diff --git a/jdk/test/javax/crypto/sanity/CheckManifestForRelease.java b/jdk/test/javax/crypto/sanity/CheckManifestForRelease.java new file mode 100644 index 00000000000..1d87575baa5 --- /dev/null +++ b/jdk/test/javax/crypto/sanity/CheckManifestForRelease.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 7197071 + * @summary Makefiles for various security providers aren't including + * the default manifest. + */ +import java.net.*; +import java.io.*; + +/** + * When the Java specification version is incremented, all of the providers + * must be recompiled with the proper implementation version to match. + */ +public class CheckManifestForRelease { + + /** + * @param args the command line arguments + */ + public static void main(String[] args) throws Exception { + checkFileManifests(); + } + + /* + * Iterate over the files of interest: JCE framework and providers + */ + static private void checkFileManifests() throws Exception { + System.out.println("============="); + String libDirName = System.getProperty("java.home", ".") + "/lib"; + String extDirName = libDirName + "/ext"; + + System.out.println("Checking Manifest in directory: \n " + + extDirName); + + /* + * Current list of JCE providers, all of which currently live in + * the extensions directory. Add if more are created. + */ + String[] providers = new String[]{ + "sunjce_provider.jar", + "sunec.jar", + "sunmscapi.jar", + "sunpkcs11.jar", + "ucrypto.jar" + }; + + checkManifest(libDirName, "jce.jar"); + for (String provider : providers) { + checkManifest(extDirName, provider); + } + System.out.println("Passed."); + } + + // Helper method to format the URL properly. + static private String formatURL(String dir, String file) { + return "jar:file:///" + dir + "/" + file + "!/"; + } + + static private String specVersion = + System.getProperty("java.specification.version"); + + /* + * Test the root cause, which is that there were no manifest values + * for many of the providers, and for those that had them, there was + * no test to make sure that the impl version was appropriate for + * the spec version. + */ + static private void checkManifest(String dir, String file) + throws Exception { + + System.out.println("Checking: " + file); + + String url = formatURL(dir, file); + JarURLConnection urlc = + (JarURLConnection) (new URL(url).openConnection()); + + String implVersion; + try { + implVersion = urlc.getManifest().getMainAttributes().getValue( + "Implementation-Version"); + } catch (FileNotFoundException e) { + /* + * If the file doesn't exist (e.g. mscapi on solaris), + * skip it. If there are other problems, fail out. + */ + System.out.println(" " + file + " not found, skipping..."); + return; + } + + if (implVersion == null) { + throw new Exception( + "Implementation-Version not found in Manifest"); + } + + if (!implVersion.startsWith(specVersion)) { + throw new Exception( + "Implementation-Version does not match " + + "Specification-Version"); + } + } +} From aff615b4d6e33211a28e5f45b72ad1544fc5b594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20=C3=96hrstr=C3=B6m?= Date: Tue, 23 Oct 2012 15:51:11 -0700 Subject: [PATCH 02/59] 8001419: Build the JCE portion of JDK-8000970 Original code done by Fredrik Ohrstrom, separated/pushed by wetmore Reviewed-by: wetmore --- .../com/sun/crypto/provider/KeyProtector.java | 33 +--------- .../provider/SealedObjectForKeyProtector.java | 61 +++++++++++++++++++ 2 files changed, 62 insertions(+), 32 deletions(-) create mode 100644 jdk/src/share/classes/com/sun/crypto/provider/SealedObjectForKeyProtector.java diff --git a/jdk/src/share/classes/com/sun/crypto/provider/KeyProtector.java b/jdk/src/share/classes/com/sun/crypto/provider/KeyProtector.java index 6d38a1f1e35..e30f90c1b6e 100644 --- a/jdk/src/share/classes/com/sun/crypto/provider/KeyProtector.java +++ b/jdk/src/share/classes/com/sun/crypto/provider/KeyProtector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -363,34 +363,3 @@ final class CipherForKeyProtector extends javax.crypto.Cipher { super(cipherSpi, provider, transformation); } } - -final class SealedObjectForKeyProtector extends javax.crypto.SealedObject { - - static final long serialVersionUID = -3650226485480866989L; - - SealedObjectForKeyProtector(Serializable object, Cipher c) - throws IOException, IllegalBlockSizeException { - super(object, c); - } - - SealedObjectForKeyProtector(SealedObject so) { - super(so); - } - - AlgorithmParameters getParameters() { - AlgorithmParameters params = null; - if (super.encodedParams != null) { - try { - params = AlgorithmParameters.getInstance("PBE", "SunJCE"); - params.init(super.encodedParams); - } catch (NoSuchProviderException nspe) { - // eat. - } catch (NoSuchAlgorithmException nsae) { - //eat. - } catch (IOException ioe) { - //eat. - } - } - return params; - } -} diff --git a/jdk/src/share/classes/com/sun/crypto/provider/SealedObjectForKeyProtector.java b/jdk/src/share/classes/com/sun/crypto/provider/SealedObjectForKeyProtector.java new file mode 100644 index 00000000000..33f7b9a2b5e --- /dev/null +++ b/jdk/src/share/classes/com/sun/crypto/provider/SealedObjectForKeyProtector.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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.crypto.provider; + +import java.io.*; +import java.security.*; +import javax.crypto.*; + +final class SealedObjectForKeyProtector extends SealedObject { + + static final long serialVersionUID = -3650226485480866989L; + + SealedObjectForKeyProtector(Serializable object, Cipher c) + throws IOException, IllegalBlockSizeException { + super(object, c); + } + + SealedObjectForKeyProtector(SealedObject so) { + super(so); + } + + AlgorithmParameters getParameters() { + AlgorithmParameters params = null; + if (super.encodedParams != null) { + try { + params = AlgorithmParameters.getInstance("PBE", "SunJCE"); + params.init(super.encodedParams); + } catch (NoSuchProviderException nspe) { + // eat. + } catch (NoSuchAlgorithmException nsae) { + //eat. + } catch (IOException ioe) { + //eat. + } + } + return params; + } +} From 5d717a96fb998e6ad1b86d4e12dd024576eefa11 Mon Sep 17 00:00:00 2001 From: Andrew Brygin Date: Wed, 24 Oct 2012 05:30:34 +0400 Subject: [PATCH 03/59] 7053526: Upgrade JDK 8 to use Little CMS 2.4 Reviewed-by: prr, jgodinez --- jdk/make/sun/cmm/lcms/FILES_c_unix.gmk | 1 + jdk/make/sun/cmm/lcms/FILES_c_windows.gmk | 1 + .../native/sun/java2d/cmm/lcms/cmscam02.c | 42 +- .../native/sun/java2d/cmm/lcms/cmscgats.c | 211 ++- .../native/sun/java2d/cmm/lcms/cmscnvrt.c | 70 +- .../share/native/sun/java2d/cmm/lcms/cmserr.c | 28 +- .../native/sun/java2d/cmm/lcms/cmsgamma.c | 78 +- .../share/native/sun/java2d/cmm/lcms/cmsgmt.c | 15 +- .../native/sun/java2d/cmm/lcms/cmshalf.c | 564 +++++++ .../native/sun/java2d/cmm/lcms/cmsintrp.c | 349 +++-- .../share/native/sun/java2d/cmm/lcms/cmsio0.c | 112 +- .../share/native/sun/java2d/cmm/lcms/cmsio1.c | 287 +++- .../share/native/sun/java2d/cmm/lcms/cmslut.c | 222 ++- .../share/native/sun/java2d/cmm/lcms/cmsmd5.c | 2 +- .../native/sun/java2d/cmm/lcms/cmsmtrx.c | 3 +- .../native/sun/java2d/cmm/lcms/cmsnamed.c | 190 ++- .../share/native/sun/java2d/cmm/lcms/cmsopt.c | 114 +- .../native/sun/java2d/cmm/lcms/cmspack.c | 1344 ++++++++++++----- .../share/native/sun/java2d/cmm/lcms/cmspcs.c | 1 + .../native/sun/java2d/cmm/lcms/cmsplugin.c | 17 +- .../share/native/sun/java2d/cmm/lcms/cmsps2.c | 88 +- .../native/sun/java2d/cmm/lcms/cmssamp.c | 305 +++- .../share/native/sun/java2d/cmm/lcms/cmssm.c | 14 +- .../native/sun/java2d/cmm/lcms/cmstypes.c | 794 ++++++++-- .../native/sun/java2d/cmm/lcms/cmsvirt.c | 92 +- .../native/sun/java2d/cmm/lcms/cmswtpnt.c | 12 +- .../native/sun/java2d/cmm/lcms/cmsxform.c | 377 +++-- .../share/native/sun/java2d/cmm/lcms/lcms2.h | 153 +- .../sun/java2d/cmm/lcms/lcms2_internal.h | 130 +- .../native/sun/java2d/cmm/lcms/lcms2_plugin.h | 91 +- 30 files changed, 4620 insertions(+), 1087 deletions(-) create mode 100644 jdk/src/share/native/sun/java2d/cmm/lcms/cmshalf.c diff --git a/jdk/make/sun/cmm/lcms/FILES_c_unix.gmk b/jdk/make/sun/cmm/lcms/FILES_c_unix.gmk index f64449a48ad..58e39e3df5a 100644 --- a/jdk/make/sun/cmm/lcms/FILES_c_unix.gmk +++ b/jdk/make/sun/cmm/lcms/FILES_c_unix.gmk @@ -30,6 +30,7 @@ FILES_c = \ cmserr.c \ cmsgamma.c \ cmsgmt.c \ + cmshalf.c \ cmsintrp.c \ cmsio0.c \ cmsio1.c \ diff --git a/jdk/make/sun/cmm/lcms/FILES_c_windows.gmk b/jdk/make/sun/cmm/lcms/FILES_c_windows.gmk index f64449a48ad..58e39e3df5a 100644 --- a/jdk/make/sun/cmm/lcms/FILES_c_windows.gmk +++ b/jdk/make/sun/cmm/lcms/FILES_c_windows.gmk @@ -30,6 +30,7 @@ FILES_c = \ cmserr.c \ cmsgamma.c \ cmsgmt.c \ + cmshalf.c \ cmsintrp.c \ cmsio0.c \ cmsio1.c \ diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c index 207a272694d..a408497e250 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 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"), @@ -409,29 +409,29 @@ cmsHANDLE CMSEXPORT cmsCIECAM02Init(cmsContext ContextID, const cmsViewingCondi switch (lpMod -> surround) { - case CUTSHEET_SURROUND: - lpMod->F = 0.8; - lpMod->c = 0.41; - lpMod->Nc = 0.8; - break; + 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 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; + 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; + default: + // Average surround + lpMod -> F = 1.0; + lpMod -> c = 0.69; + lpMod -> Nc = 1.0; } lpMod -> n = compute_n(lpMod); diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c index f3ffbe44d61..15a2439448e 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 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"), @@ -73,6 +73,7 @@ # define DIR_CHAR '/' #endif + // Symbols typedef enum { @@ -143,6 +144,8 @@ typedef struct _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 @@ -162,7 +165,6 @@ typedef struct _FileContext { // This struct hold all information about an open IT8 handler. typedef struct { - char SheetType[MAXSTR]; // The first row of the IT8 (the type) cmsUInt32Number TablesCount; // How many tables in this stream cmsUInt32Number nTable; // The actual table @@ -433,6 +435,8 @@ cmsBool isabsolutepath(const char *path) 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 @@ -574,7 +578,7 @@ void ReadReal(cmsIT8* it8, int inum) if (it8->ch == '.') { // Decimal point cmsFloat64Number frac = 0.0; // fraction - int prec = 0; // precision + int prec = 0; // precision NextCh(it8); // Eats dec. point @@ -621,6 +625,81 @@ void ReadReal(cmsIT8* it8, int inum) } } +// Parses a float number +// This can not call directly atof because it uses locale dependant +// parsing, while CCMX files always use . as decimal separator +static +cmsFloat64Number ParseFloatNumber(const char *Buffer) +{ + cmsFloat64Number dnum = 0.0; + int sign = 1; + + 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; // precission + + 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)) { + + if ((cmsFloat64Number) e * 10L < INT_MAX) + e = e * 10 + (*Buffer - '0'); + + if (*Buffer) Buffer++; + } + + e = sgn*e; + dnum = dnum * xpow10(e); + } + + return sign * dnum; +} // Reads next symbol @@ -1011,7 +1090,7 @@ void* AllocChunk(cmsIT8* it8, cmsUInt32Number size) cmsUInt32Number Free = it8 ->Allocator.BlockSize - it8 ->Allocator.Used; cmsUInt8Number* ptr; - size = _cmsALIGNLONG(size); + size = _cmsALIGNMEM(size); if (size > Free) { @@ -1212,7 +1291,7 @@ cmsInt32Number CMSEXPORT cmsIT8SetTable(cmsHANDLE IT8, cmsUInt32Number nTable) cmsHANDLE CMSEXPORT cmsIT8Alloc(cmsContext ContextID) { cmsIT8* it8; - int i; + cmsUInt32Number i; it8 = (cmsIT8*) _cmsMallocZero(ContextID, sizeof(cmsIT8)); if (it8 == NULL) return NULL; @@ -1243,7 +1322,7 @@ cmsHANDLE CMSEXPORT cmsIT8Alloc(cmsContext ContextID) it8 -> lineno = 1; strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT); - strcpy(it8->SheetType, "CGATS.17"); + cmsIT8SetSheetType((cmsHANDLE) it8, "CGATS.17"); // Initialize predefined properties & data @@ -1260,18 +1339,15 @@ cmsHANDLE CMSEXPORT cmsIT8Alloc(cmsContext ContextID) const char* CMSEXPORT cmsIT8GetSheetType(cmsHANDLE hIT8) { - cmsIT8* it8 = (cmsIT8*) hIT8; - - return it8 ->SheetType; - + return GetTable((cmsIT8*) hIT8)->SheetType; } cmsBool CMSEXPORT cmsIT8SetSheetType(cmsHANDLE hIT8, const char* Type) { - cmsIT8* it8 = (cmsIT8*) hIT8; + TABLE* t = GetTable((cmsIT8*) hIT8); - strncpy(it8 ->SheetType, Type, MAXSTR-1); - it8 ->SheetType[MAXSTR-1] = 0; + strncpy(t ->SheetType, Type, MAXSTR-1); + t ->SheetType[MAXSTR-1] = 0; return TRUE; } @@ -1285,8 +1361,6 @@ cmsBool CMSEXPORT cmsIT8SetComment(cmsHANDLE hIT8, const char* Val) 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) { @@ -1298,7 +1372,6 @@ cmsBool CMSEXPORT cmsIT8SetPropertyStr(cmsHANDLE hIT8, const char* Key, const ch 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; @@ -1351,8 +1424,7 @@ cmsFloat64Number CMSEXPORT cmsIT8GetPropertyDbl(cmsHANDLE hIT8, const char* cPro { const char *v = cmsIT8GetProperty(hIT8, cProp); - if (v) return atof(v); - else return 0.0; + return ParseFloatNumber(v); } const char* CMSEXPORT cmsIT8GetPropertyMulti(cmsHANDLE hIT8, const char* Key, const char *SubKey) @@ -1553,6 +1625,9 @@ 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) { @@ -1701,8 +1776,6 @@ cmsBool CMSEXPORT cmsIT8SaveToFile(cmsHANDLE hIT8, const char* cFileName) sd.stream = fopen(cFileName, "wt"); if (!sd.stream) return FALSE; - WriteStr(&sd, it8->SheetType); - WriteStr(&sd, "\n"); for (i=0; i < it8 ->TablesCount; i++) { cmsIT8SetTable(hIT8, i); @@ -1737,20 +1810,18 @@ cmsBool CMSEXPORT cmsIT8SaveToMem(cmsHANDLE hIT8, void *MemPtr, cmsUInt32Number* else sd.Max = 0; // Just counting the needed bytes - WriteStr(&sd, it8->SheetType); - WriteStr(&sd, "\n"); for (i=0; i < it8 ->TablesCount; i++) { - cmsIT8SetTable(hIT8, i); - WriteHeader(it8, &sd); - WriteDataFormat(&sd, it8); - WriteData(&sd, it8); + 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; + *sd.Ptr = 0; *BytesNeeded = sd.Used; @@ -1963,12 +2034,8 @@ cmsBool HeaderSection(cmsIT8* it8) static -cmsBool ParseIT8(cmsIT8* it8, cmsBool nosheet) +void ReadType(cmsIT8* it8, char* SheetTypePtr) { - char* SheetTypePtr = it8 ->SheetType; - - if (nosheet == 0) { - // First line is a very special case. while (isseparator(it8->ch)) @@ -1979,9 +2046,20 @@ cmsBool ParseIT8(cmsIT8* it8, cmsBool nosheet) *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); @@ -2003,6 +2081,39 @@ cmsBool ParseIT8(cmsIT8* it8, cmsBool nosheet) 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') { + + 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; @@ -2123,14 +2234,14 @@ void CookPointers(cmsIT8* it8) // 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(cmsUInt8Number* Buffer, int n) { - int cols = 1, space = 0, quot = 0; + int words = 1, space = 0, quot = 0; int i; - if (n < 10) return FALSE; // Too small + if (n < 10) return 0; // Too small if (n > 132) n = 132; @@ -2141,7 +2252,7 @@ int IsMyBlock(cmsUInt8Number* Buffer, int n) { case '\n': case '\r': - return quot == 1 || cols > 2 ? 0 : cols; + return ((quot == 1) || (words > 2)) ? 0 : words; case '\t': case ' ': if(!quot && !space) @@ -2153,14 +2264,13 @@ int IsMyBlock(cmsUInt8Number* Buffer, int n) default: if (Buffer[i] < 32) return 0; if (Buffer[i] > 127) return 0; - cols += space; + words += space; space = 0; break; } } - return FALSE; - + return 0; } @@ -2271,7 +2381,7 @@ cmsHANDLE CMSEXPORT cmsIT8LoadFromFile(cmsContext ContextID, const char* cFileN it8 ->nTable = 0; if (fclose(it8 ->FileStack[0]->Stream)!= 0) { - cmsIT8Free(hIT8); + cmsIT8Free(hIT8); return NULL; } @@ -2454,13 +2564,7 @@ cmsFloat64Number CMSEXPORT cmsIT8GetDataRowColDbl(cmsHANDLE hIT8, int row, int c Buffer = cmsIT8GetDataRowCol(hIT8, row, col); - if (Buffer) { - - return atof(Buffer); - - } else - return 0; - + return ParseFloatNumber(Buffer); } @@ -2515,14 +2619,7 @@ cmsFloat64Number CMSEXPORT cmsIT8GetDataDbl(cmsHANDLE it8, const char* cPatch, Buffer = cmsIT8GetData(it8, cPatch, cSample); - if (Buffer) { - - return atof(Buffer); - - } else { - - return 0; - } + return ParseFloatNumber(Buffer); } @@ -2680,5 +2777,7 @@ void CMSEXPORT cmsIT8DefineDblFormat(cmsHANDLE hIT8, const char* Formatter) strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT); else strcpy(it8->DoubleFormatter, Formatter); + + it8 ->DoubleFormatter[sizeof(it8 ->DoubleFormatter)-1] = 0; } diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c index 9bea64f4fd9..d1a1cc99804 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 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"), @@ -193,17 +193,21 @@ void ComputeBlackPointCompensation(const cmsCIEXYZ* BlackPointIn, static cmsFloat64Number CHAD2Temp(const cmsMAT3* Chad) { - // Convert D50 across CHAD to get the absolute white point - cmsVEC3 d, s; - cmsCIEXYZ Dest; - cmsCIExyY DestChromaticity; - cmsFloat64Number TempK; + // 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, Chad, &s); + _cmsMAT3eval(&d, &m2, &s); Dest.X = d.n[VX]; Dest.Y = d.n[VY]; @@ -219,15 +223,14 @@ cmsFloat64Number CHAD2Temp(const cmsMAT3* Chad) // Compute a CHAD based on a given temperature static -void Temp2CHAD(cmsMAT3* Chad, cmsFloat64Number Temp) + void Temp2CHAD(cmsMAT3* Chad, cmsFloat64Number Temp) { cmsCIEXYZ White; cmsCIExyY ChromaticityOfWhite; cmsWhitePointFromTemp(&ChromaticityOfWhite, Temp); cmsxyY2XYZ(&White, &ChromaticityOfWhite); - _cmsAdaptationMatrix(Chad, NULL, cmsD50_XYZ(), &White); - + _cmsAdaptationMatrix(Chad, NULL, &White, cmsD50_XYZ()); } // Join scalings to obtain relative input to absolute and then to relative output. @@ -240,7 +243,7 @@ cmsBool ComputeAbsoluteIntent(cmsFloat64Number AdaptationState, const cmsMAT3* ChromaticAdaptationMatrixOut, cmsMAT3* m) { - cmsMAT3 Scale, m1, m2, m3; + cmsMAT3 Scale, m1, m2, m3, m4; // Adaptation state if (AdaptationState == 1.0) { @@ -259,23 +262,32 @@ cmsBool ComputeAbsoluteIntent(cmsFloat64Number AdaptationState, _cmsVEC3init(&Scale.v[1], 0, WhitePointIn->Y / WhitePointOut->Y, 0); _cmsVEC3init(&Scale.v[2], 0, 0, WhitePointIn->Z / WhitePointOut->Z); - m1 = *ChromaticAdaptationMatrixIn; - if (!_cmsMAT3inverse(&m1, &m2)) return FALSE; - _cmsMAT3per(&m3, &m2, &Scale); - // m3 holds CHAD from input white to D50 times abs. col. scaling 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, &m3, ChromaticAdaptationMatrixOut); + m3 = *ChromaticAdaptationMatrixIn; + if (!_cmsMAT3inverse(&m3, &m4)) return FALSE; + _cmsMAT3per(m, &m2, &m4); + } else { cmsMAT3 MixedCHAD; cmsFloat64Number TempSrc, TempDest, Temp; - TempSrc = CHAD2Temp(ChromaticAdaptationMatrixIn); // K for source white - TempDest = CHAD2Temp(ChromaticAdaptationMatrixOut); // K for dest white + 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 @@ -285,9 +297,9 @@ cmsBool ComputeAbsoluteIntent(cmsFloat64Number AdaptationState, return TRUE; } - Temp = AdaptationState * TempSrc + (1.0 - AdaptationState) * TempDest; + Temp = (1.0 - AdaptationState) * TempDest + AdaptationState * TempSrc; - // Get a CHAD from D50 to whatever output temperature. This replaces output CHAD + // Get a CHAD from whatever output temperature to D50. This replaces output CHAD Temp2CHAD(&MixedCHAD, Temp); _cmsMAT3per(m, &m3, &MixedCHAD); @@ -362,7 +374,7 @@ cmsBool ComputeConversion(int i, cmsHPROFILE hProfiles[], cmsCIEXYZ BlackPointIn, BlackPointOut; cmsDetectBlackPoint(&BlackPointIn, hProfiles[i-1], Intent, 0); - cmsDetectBlackPoint(&BlackPointOut, hProfiles[i], Intent, 0); + cmsDetectDestinationBlackPoint(&BlackPointOut, hProfiles[i], Intent, 0); // If black points are equal, then do nothing if (BlackPointIn.X != BlackPointOut.X || @@ -463,6 +475,10 @@ cmsBool ColorSpaceIsCompatible(cmsColorSpaceSignature a, cmsColorSpaceSignature // 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; @@ -511,7 +527,7 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID, lIsInput = TRUE; } else { - // Else use profile in the input direction if current space is not PCS + // Else use profile in the input direction if current space is not PCS lIsInput = (CurrentColorSpace != cmsSigXYZData) && (CurrentColorSpace != cmsSigLabData); } @@ -537,7 +553,7 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID, // 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) { + if (lIsDeviceLink || ((ClassSig == cmsSigNamedColorClass) && (nProfiles == 1))) { // Get the involved LUT from the profile Lut = _cmsReadDevicelinkLUT(hProfile, Intent); @@ -876,7 +892,8 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, // Check for non-cmyk profiles if (cmsGetColorSpace(hProfiles[0]) != cmsSigCmykData || - cmsGetColorSpace(hProfiles[nProfiles-1]) != cmsSigCmykData) + !(cmsGetColorSpace(hProfiles[nProfiles-1]) == cmsSigCmykData || + cmsGetDeviceClass(hProfiles[nProfiles-1]) == cmsSigOutputClass)) return DefaultICCintents(ContextID, nProfiles, ICCIntents, hProfiles, BPC, AdaptationStates, dwFlags); // Allocate an empty LUT for holding the result @@ -893,6 +910,8 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, // Get total area coverage (in 0..1 domain) bp.MaxTAC = cmsDetectTAC(hProfiles[nProfiles-1]) / 100.0; + if (bp.MaxTAC <= 0) goto Cleanup; + // Create a LUT holding normal ICC transform bp.cmyk2cmyk = DefaultICCintents(ContextID, @@ -902,6 +921,7 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, BPC, AdaptationStates, dwFlags); + if (bp.cmyk2cmyk == NULL) goto Cleanup; // Now the tone curve bp.KTone = _cmsBuildKToneCurve(ContextID, 4096, nProfiles, @@ -910,7 +930,7 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, BPC, AdaptationStates, dwFlags); - + if (bp.KTone == NULL) goto Cleanup; // To measure the output, Last profile to Lab hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); @@ -918,6 +938,7 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, 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, hProfiles[nProfiles-1], @@ -925,6 +946,7 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, 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) diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c index ab740e2bdaf..a18a59a1ffa 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 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"), @@ -72,17 +72,21 @@ int CMSEXPORT cmsstrcasecmp(const char* s1, const char* s2) // long int because C99 specifies ftell in such way (7.19.9.2) long int CMSEXPORT cmsfilelength(FILE* f) { - long int n; + long int p , n; + + p = ftell(f); // register current file position if (fseek(f, 0, SEEK_END) != 0) { return -1; } + n = ftell(f); - fseek(f, 0, SEEK_SET); + 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 @@ -160,6 +164,12 @@ void* _cmsCallocDefaultFn(cmsContext ContextID, cmsUInt32Number num, cmsUInt32Nu { 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; @@ -269,12 +279,16 @@ void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Numbe // 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 thats not true on any platform) +// 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; @@ -288,9 +302,7 @@ _cmsSubAllocator_chunk* _cmsCreateSubAllocChunk(cmsContext ContextID, cmsUInt32N return NULL; } - // 20K by default - if (Initial == 0) - Initial = 20*1024; + chunk ->BlockSize = Initial; chunk ->Used = 0; @@ -344,7 +356,7 @@ void* _cmsSubAlloc(_cmsSubAllocator* sub, cmsUInt32Number size) cmsUInt32Number Free = sub -> h ->BlockSize - sub -> h -> Used; cmsUInt8Number* ptr; - size = _cmsALIGNLONG(size); + size = _cmsALIGNMEM(size); // Check for memory. If there is no room, allocate a new chunk of double memory size. if (size > Free) { diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c index 49dfa9830d7..9ee36e2d538 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 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"), @@ -277,18 +277,28 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu switch (Type) { - // X = Y ^ Gamma + // X = Y ^ Gamma case 1: - if (R < 0) - Val = 0; + 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) - Val = 0; + if (R < 0) { + + if (fabs(Params[0] - 1.0) < MATRIX_DET_TOLERANCE) + Val = R; + else + Val = 0; + } else Val = pow(R, 1/Params[0]); break; @@ -552,6 +562,19 @@ cmsFloat64Number EvalSegmentedFn(const cmsToneCurve *g, cmsFloat64Number R) 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. @@ -828,7 +851,7 @@ int GetInterval(cmsFloat64Number In, const cmsUInt16Number LutTable[], const str cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsInt32Number nResultSamples, const cmsToneCurve* InCurve) { cmsToneCurve *out; - cmsFloat64Number a = 1, b = 0, y, x1, y1, x2, y2; + cmsFloat64Number a = 0, b = 0, y, x1, y1, x2, y2; int i, j; int Ascending; @@ -859,6 +882,7 @@ cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsInt32Number nResultSamples, con j = GetInterval(y, InCurve->Table16, InCurve->InterpParams); if (j >= 0) { + // Get limits of interval x1 = InCurve ->Table16[j]; x2 = InCurve ->Table16[j+1]; @@ -883,6 +907,7 @@ cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsInt32Number nResultSamples, con out ->Table16[i] = _cmsQuickSaturateWord(a* y + b); } + return out; } @@ -891,7 +916,7 @@ cmsToneCurve* CMSEXPORT cmsReverseToneCurve(const cmsToneCurve* InGamma) { _cmsAssert(InGamma != NULL); - return cmsReverseToneCurveEx(InGamma -> nEntries, InGamma); + return cmsReverseToneCurveEx(4096, InGamma); } // From: Eilers, P.H.C. (1994) Smoothing and interpolation with finite @@ -1035,20 +1060,42 @@ cmsBool CMSEXPORT cmsIsToneCurveMonotonic(const cmsToneCurve* t) { int n; int i, last; + cmsBool lDescending; _cmsAssert(t != NULL); - n = t ->nEntries; - last = t ->Table16[n-1]; + // Degenerated curves are monotonic? Ok, let's pass them + n = t ->nEntries; + if (n < 2) return TRUE; - for (i = n-2; i >= 0; --i) { + // Curve direction + lDescending = cmsIsToneCurveDescending(t); - if (t ->Table16[i] > last) + if (lDescending) { - return FALSE; - else - last = t ->Table16[i]; + last = t ->Table16[0]; + for (i = 1; i < 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 = n-2; i >= 0; --i) { + + if (t ->Table16[i] - last > 2) + return FALSE; + else + last = t ->Table16[i]; + + } } return TRUE; @@ -1163,4 +1210,3 @@ cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Num return (sum / n); // The mean } - diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c index 504b038c1f4..d7fb6dd274e 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 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"), @@ -212,7 +212,6 @@ cmsToneCurve* _cmsBuildKToneCurve(cmsContext ContextID, // Make sure it is monotonic if (!cmsIsToneCurveMonotonic(KTone)) { - cmsFreeToneCurve(KTone); return NULL; } @@ -246,7 +245,7 @@ int GamutSampler(register const cmsUInt16Number In[], register cmsUInt16Number O GAMUTCHAIN* t = (GAMUTCHAIN* ) Cargo; cmsCIELab LabIn1, LabOut1; cmsCIELab LabIn2, LabOut2; - cmsFloat32Number Proof[cmsMAXCHANNELS], Proof2[cmsMAXCHANNELS]; + cmsUInt16Number Proof[cmsMAXCHANNELS], Proof2[cmsMAXCHANNELS]; cmsFloat64Number dE1, dE2, ErrorRatio; // Assume in-gamut by default. @@ -396,8 +395,8 @@ cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID, cmsFLAGS_NOCACHE); - // Does create the forward step. Lab double to cmsFloat32Number - dwFormat = (FLOAT_SH(1)|CHANNELS_SH(nChannels)|BYTES_SH(4)); + // 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, @@ -421,10 +420,10 @@ cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID, if (Gamut != NULL) { - CLUT = cmsStageAllocCLut16bit(ContextID, nGridpoints, nChannels, 1, NULL); - cmsPipelineInsertStage(Gamut, cmsAT_BEGIN, CLUT); + CLUT = cmsStageAllocCLut16bit(ContextID, nGridpoints, nChannels, 1, NULL); + cmsPipelineInsertStage(Gamut, cmsAT_BEGIN, CLUT); - cmsStageSampleCLut16bit(CLUT, GamutSampler, (void*) &Chain, 0); + cmsStageSampleCLut16bit(CLUT, GamutSampler, (void*) &Chain, 0); } } else diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmshalf.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmshalf.c new file mode 100644 index 00000000000..11efe3adf71 --- /dev/null +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmshalf.c @@ -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-2012 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 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 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 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 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 _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 _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 --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c index 258addde7c4..183d2f84d01 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 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"), @@ -55,7 +55,7 @@ #include "lcms2_internal.h" -// This module incorporates several interpolation routines, for 1, 3, 4, 5, 6, 7 and 8 channels on input and +// 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 // Interpolation routines by default @@ -83,7 +83,7 @@ cmsBool _cmsRegisterInterpPlugin(cmsPluginBase* Data) // Set the interpolation method -static + cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p) { // Invoke factory, possibly in the Plug-in @@ -318,6 +318,116 @@ void Eval1InputFloat(const cmsFloat32Number Value[], } } +// 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 = Input[0] * p->Domain[0]; + py = 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 + (Input[0] >= 1.0 ? 0 : p->opta[1]); + + Y0 = p -> opta[0] * y0; + Y1 = Y0 + (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 +void BilinearInterp16(register const cmsUInt16Number Input[], + register cmsUInt16Number Output[], + register 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; + register int rx, ry; + int x0, y0; + register 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 @@ -343,9 +453,21 @@ void TrilinearInterpFloat(const cmsFloat32Number Input[], TotalOut = p -> nOutputs; - px = Input[0] * p->Domain[0]; - py = Input[1] * p->Domain[1]; - pz = Input[2] * p->Domain[2]; + // We need some clipping here + px = Input[0]; + py = Input[1]; + pz = Input[2]; + + if (px < 0) px = 0; + if (px > 1) px = 1; + if (py < 0) py = 0; + if (py > 1) py = 1; + if (pz < 0) pz = 0; + if (pz > 1) pz = 1; + + px *= p->Domain[0]; + py *= p->Domain[1]; + pz *= p->Domain[2]; x0 = (int) _cmsQuickFloor(px); fx = px - (cmsFloat32Number) x0; y0 = (int) _cmsQuickFloor(py); fy = py - (cmsFloat32Number) y0; @@ -486,9 +608,21 @@ void TetrahedralInterpFloat(const cmsFloat32Number Input[], TotalOut = p -> nOutputs; - px = Input[0] * p->Domain[0]; - py = Input[1] * p->Domain[1]; - pz = Input[2] * p->Domain[2]; + // We need some clipping here + px = Input[0]; + py = Input[1]; + pz = Input[2]; + + if (px < 0) px = 0; + if (px > 1) px = 1; + if (py < 0) py = 0; + if (py > 1) py = 1; + if (pz < 0) pz = 0; + if (pz > 1) pz = 1; + + px *= p->Domain[0]; + py *= p->Domain[1]; + pz *= p->Domain[2]; x0 = (int) _cmsQuickFloor(px); rx = (px - (cmsFloat32Number) x0); y0 = (int) _cmsQuickFloor(py); ry = (py - (cmsFloat32Number) y0); @@ -570,7 +704,6 @@ void TetrahedralInterpFloat(const cmsFloat32Number Input[], -#define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) static void TetrahedralInterp16(register const cmsUInt16Number Input[], @@ -578,99 +711,131 @@ void TetrahedralInterp16(register const cmsUInt16Number Input[], register 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 OutChan; - cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1; - cmsUInt32Number TotalOut = p -> nOutputs; + cmsS15Fixed16Number fx, fy, fz; + cmsS15Fixed16Number rx, ry, rz; + int x0, y0, z0; + cmsS15Fixed16Number c0, c1, c2, c3, Rest; + cmsS15Fixed16Number 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]); - 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); - 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); + rx = FIXED_REST_TO_INT(fx); + ry = FIXED_REST_TO_INT(fy); + rz = FIXED_REST_TO_INT(fz); X0 = p -> opta[2] * x0; - X1 = X0 + (Input[0] == 0xFFFFU ? 0 : p->opta[2]); + X1 = (Input[0] == 0xFFFFU ? 0 : p->opta[2]); Y0 = p -> opta[1] * y0; - Y1 = Y0 + (Input[1] == 0xFFFFU ? 0 : p->opta[1]); + Y1 = (Input[1] == 0xFFFFU ? 0 : p->opta[1]); Z0 = p -> opta[0] * z0; - Z1 = Z0 + (Input[2] == 0xFFFFU ? 0 : p->opta[0]); + Z1 = (Input[2] == 0xFFFFU ? 0 : p->opta[0]); - // These are the 6 Tetrahedral - for (OutChan=0; OutChan < TotalOut; OutChan++) { + LutTable = &LutTable[X0+Y0+Z0]; - 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); + // 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 && 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; - - Output[OutChan] = (cmsUInt16Number) c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)); + } 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); + } + } } - } -#undef DENS #define DENS(i,j,k) (LutTable[(i)+(j)+(k)+OutChan]) @@ -1102,7 +1267,7 @@ void Eval7Inputs(register const cmsUInt16Number Input[], K1 = p16 -> opta[6] * (k0 + (Input[0] != 0xFFFFU ? 1 : 0)); p1 = *p16; - memmove(&p1.Domain[0], &p16 ->Domain[1], 5*sizeof(cmsUInt32Number)); + memmove(&p1.Domain[0], &p16 ->Domain[1], 6*sizeof(cmsUInt32Number)); T = LutTable + K0; p1.Table = T; @@ -1285,6 +1450,12 @@ cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cm } break; + case 2: // Duotone + if (IsFloat) + Interpolation.LerpFloat = BilinearInterpFloat; + else + Interpolation.Lerp16 = BilinearInterp16; + break; case 3: // RGB et al diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c index 257a964125d..5bad907e2d7 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 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"), @@ -142,6 +142,7 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromNULL(cmsContext ContextID) iohandler ->ContextID = ContextID; iohandler ->stream = (void*) fm; iohandler ->UsedSpace = 0; + iohandler ->ReportedSize = 0; iohandler ->PhysicalFile[0] = 0; iohandler ->Read = NULLRead; @@ -232,13 +233,11 @@ cmsBool MemoryWrite(struct _cms_io_handler* iohandler, cmsUInt32Number size, co memmove(ResData ->Block + ResData ->Pointer, Ptr, size); ResData ->Pointer += size; + iohandler->UsedSpace += size; if (ResData ->Pointer > iohandler->UsedSpace) iohandler->UsedSpace = ResData ->Pointer; - - iohandler->UsedSpace += size; - return TRUE; } @@ -297,6 +296,7 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromMem(cmsContext ContextID, void *Buff fm ->FreeBlockOnClose = TRUE; fm ->Size = size; fm ->Pointer = 0; + iohandler -> ReportedSize = size; break; case 'w': @@ -307,10 +307,11 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromMem(cmsContext ContextID, void *Buff fm ->FreeBlockOnClose = FALSE; fm ->Size = size; fm ->Pointer = 0; + iohandler -> ReportedSize = 0; break; default: - cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknow access mode '%c'", *AccessMode); + cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown access mode '%c'", *AccessMode); return NULL; } @@ -407,6 +408,7 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const cha cmsSignalError(ContextID, cmsERROR_FILE, "File '%s' not found", FileName); return NULL; } + iohandler -> ReportedSize = cmsfilelength(fm); break; case 'w': @@ -416,11 +418,12 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const cha cmsSignalError(ContextID, cmsERROR_FILE, "Couldn't create '%s'", FileName); return NULL; } + iohandler -> ReportedSize = 0; break; default: _cmsFree(ContextID, iohandler); - cmsSignalError(ContextID, cmsERROR_FILE, "Unknow access mode '%c'", *AccessMode); + cmsSignalError(ContextID, cmsERROR_FILE, "Unknown access mode '%c'", *AccessMode); return NULL; } @@ -455,6 +458,7 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromStream(cmsContext ContextID, FILE* S iohandler -> ContextID = ContextID; iohandler -> stream = (void*) Stream; iohandler -> UsedSpace = 0; + iohandler -> ReportedSize = cmsfilelength(Stream); iohandler -> PhysicalFile[0] = 0; iohandler ->Read = FileRead; @@ -643,12 +647,17 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) Icc -> flags = _cmsAdjustEndianess32(Header.flags); Icc -> manufacturer = _cmsAdjustEndianess32(Header.manufacturer); Icc -> model = _cmsAdjustEndianess32(Header.model); - _cmsAdjustEndianess64(&Icc -> attributes, Header.attributes); + _cmsAdjustEndianess64(&Icc -> attributes, &Header.attributes); Icc -> Version = _cmsAdjustEndianess32(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); @@ -664,6 +673,7 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) return FALSE; } + // Read tag directory Icc -> TagCount = 0; for (i=0; i < TagCount; i++) { @@ -673,7 +683,8 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) if (!_cmsReadUInt32Number(io, &Tag.size)) return FALSE; // Perform some sanity check. Offset + size should fall inside file. - if (Tag.offset + Tag.size > HeaderSize) + if (Tag.offset + Tag.size > HeaderSize || + Tag.offset + Tag.size < Tag.offset) continue; Icc -> TagNames[Icc ->TagCount] = Tag.sig; @@ -728,7 +739,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace) Header.manufacturer = _cmsAdjustEndianess32(Icc -> manufacturer); Header.model = _cmsAdjustEndianess32(Icc -> model); - _cmsAdjustEndianess64(&Header.attributes, Icc -> attributes); + _cmsAdjustEndianess64(&Header.attributes, &Icc -> attributes); // Rendering intent in the header (for embedded profiles) Header.renderingIntent = _cmsAdjustEndianess32(Icc -> RenderingIntent); @@ -822,7 +833,7 @@ cmsUInt32Number CMSEXPORT cmsGetHeaderModel(cmsHPROFILE hProfile) void CMSEXPORT cmsSetHeaderModel(cmsHPROFILE hProfile, cmsUInt32Number model) { _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile; - Icc -> manufacturer = (cmsUInt32Number) model; + Icc -> model = (cmsUInt32Number) model; } @@ -1138,10 +1149,12 @@ cmsBool SaveTags(_cmsICCPROFILE* Icc, _cmsICCPROFILE* FileOrig) continue; } - TypeBase = TypeHandler ->Signature; + TypeBase = TypeHandler ->Signature; if (!_cmsWriteTypeBase(io, TypeBase)) return FALSE; + TypeHandler ->ContextID = Icc ->ContextID; + TypeHandler ->ICCVersion = Icc ->Version; if (!TypeHandler ->WritePtr(TypeHandler, io, Data, TagDescriptor ->ElemCount)) { char String[5]; @@ -1317,8 +1330,12 @@ cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile) cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i]; - if (TypeHandler != NULL) + if (TypeHandler != NULL) { + + TypeHandler ->ContextID = Icc ->ContextID; // As an additional parameters + TypeHandler ->ICCVersion = Icc ->Version; TypeHandler ->FreePtr(TypeHandler, Icc -> TagPtrs[i]); + } else _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]); } @@ -1371,7 +1388,6 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) if (n < 0) return NULL; // Not found, return NULL - // If the element is already in memory, return the pointer if (Icc -> TagPtrs[n]) { @@ -1406,6 +1422,9 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) // Read the tag Icc -> TagTypeHandlers[n] = TypeHandler; + + TypeHandler ->ContextID = Icc ->ContextID; + TypeHandler ->ICCVersion = Icc ->Version; Icc -> TagPtrs[n] = TypeHandler ->ReadPtr(TypeHandler, io, &ElemCount, TagSize); // The tag type is supported, but something wrong happend and we cannot read the tag. @@ -1463,11 +1482,15 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v cmsTagTypeSignature Type; int i; cmsFloat64Number Version; + char TypeString[5], SigString[5]; if (data == NULL) { - cmsSignalError(cmsGetProfileContextID(hProfile), cmsERROR_NULL, "couldn't wite NULL to tag"); + i = _cmsSearchTag(Icc, sig, FALSE); + if (i >= 0) + Icc ->TagNames[i] = (cmsTagSignature) 0; + // Unsupported by now, reserved for future ampliations (delete) return FALSE; } @@ -1482,7 +1505,13 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v } else { TypeHandler = Icc ->TagTypeHandlers[i]; - TypeHandler->FreePtr(TypeHandler, Icc -> TagPtrs[i]); + + if (TypeHandler != NULL) { + + TypeHandler ->ContextID = Icc ->ContextID; // As an additional parameter + TypeHandler ->ICCVersion = Icc ->Version; + TypeHandler->FreePtr(TypeHandler, Icc -> TagPtrs[i]); + } } } } @@ -1514,6 +1543,7 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v // 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 @@ -1525,33 +1555,47 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v } else { + Type = TagDescriptor ->SupportedTypes[0]; } // Does the tag support this type? if (!IsTypeSupported(TagDescriptor, Type)) { - cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%x' for tag '%x'", Type, sig); + + _cmsTagSignature2String(TypeString, (cmsTagSignature) Type); + _cmsTagSignature2String(SigString, sig); + + cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%s' for tag '%s'", TypeString, SigString); return FALSE; } // Does we have a handler for this type? TypeHandler = _cmsGetTagTypeHandler(Type); if (TypeHandler == NULL) { - cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%x' for tag '%x'", Type, sig); + + _cmsTagSignature2String(TypeString, (cmsTagSignature) Type); + _cmsTagSignature2String(SigString, sig); + + cmsSignalError(Icc ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported type '%s' for tag '%s'", TypeString, SigString); return FALSE; // Should never happen } + // Fill fields on icc structure Icc ->TagTypeHandlers[i] = TypeHandler; Icc ->TagNames[i] = sig; Icc ->TagSizes[i] = 0; Icc ->TagOffsets[i] = 0; - Icc ->TagPtrs[i] = TypeHandler ->DupPtr(TypeHandler, data, TagDescriptor ->ElemCount); + + TypeHandler ->ContextID = Icc ->ContextID; + TypeHandler ->ICCVersion = Icc ->Version; + Icc ->TagPtrs[i] = TypeHandler ->DupPtr(TypeHandler, data, TagDescriptor ->ElemCount); if (Icc ->TagPtrs[i] == NULL) { - TypeHandler ->DupPtr(TypeHandler, data, TagDescriptor ->ElemCount); - cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Malformed struct in type '%x' for tag '%x'", Type, sig); + _cmsTagSignature2String(TypeString, (cmsTagSignature) Type); + _cmsTagSignature2String(SigString, sig); + cmsSignalError(Icc ->ContextID, cmsERROR_CORRUPTION_DETECTED, "Malformed struct in type '%s' for tag '%s'", TypeString, SigString); return FALSE; } @@ -1627,21 +1671,31 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig if (data == NULL) { MemIO = cmsOpenIOhandlerFromNULL(cmsGetProfileContextID(hProfile)); } else{ - MemIO = cmsOpenIOhandlerFromMem(cmsGetProfileContextID(hProfile), data, BufferSize, "w"); + MemIO = cmsOpenIOhandlerFromMem(cmsGetProfileContextID(hProfile), data, BufferSize, "w"); } if (MemIO == NULL) return 0; // Obtain type handling for the tag TypeHandler = Icc ->TagTypeHandlers[i]; TagDescriptor = _cmsGetTagDescriptor(sig); + if (TagDescriptor == NULL) { + cmsCloseIOhandler(MemIO); + return 0; + } // Serialize + TypeHandler ->ContextID = Icc ->ContextID; + TypeHandler ->ICCVersion = Icc ->Version; + if (!_cmsWriteTypeBase(MemIO, TypeHandler ->Signature)) { cmsCloseIOhandler(MemIO); return 0; } - if (!TypeHandler ->WritePtr(TypeHandler, MemIO, Object, TagDescriptor ->ElemCount)) return 0; + if (!TypeHandler ->WritePtr(TypeHandler, MemIO, Object, TagDescriptor ->ElemCount)) { + cmsCloseIOhandler(MemIO); + return 0; + } // Get Size and close rc = MemIO ->Tell(MemIO); @@ -1692,3 +1746,17 @@ cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignature sig, cmsTagSi 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 --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c index b0daaf0e252..2dd12f79b4d 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 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"), @@ -150,7 +150,7 @@ cmsBool _cmsReadCHAD(cmsMAT3* Dest, cmsHPROFILE hProfile) return TRUE; } - return _cmsAdaptationMatrix(Dest, NULL, cmsD50_XYZ(), White); + return _cmsAdaptationMatrix(Dest, NULL, White, cmsD50_XYZ()); } } @@ -261,11 +261,81 @@ cmsPipeline* BuildRGBInputMatrixShaper(cmsHPROFILE hProfile) cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, Shapes)); cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, (cmsFloat64Number*) &Mat, 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) { + + cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocXYZ2Lab(ContextID)); + } + } return Lut; } + + +// 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); + + 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 accomodated to 0..1.0, we should undo this change + if ( spc == cmsSigLabData) + { + cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID)); + } + else + if (spc == cmsSigXYZData) + { + cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID)); + } + + return Lut; +} +*/ +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) + { + cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID)); + } + else if (spc == cmsSigXYZData) + { + cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID)); + } + + if ( PCS == cmsSigLabData) + { + cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID)); + } + else if( PCS == cmsSigXYZData) + { + cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID)); + } + + return Lut; +} + + // 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 cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent) @@ -275,10 +345,30 @@ cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent) cmsTagSignature tagFloat = Device2PCSFloat[Intent]; cmsContext ContextID = cmsGetProfileContextID(hProfile); + // On named color, take the appropiate 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; + } + + cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocNamedColor(nc, TRUE)); + cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)); + return Lut; + } + if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence - // Floating point LUT are always V4, so no adjustment is required - return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat)); + // 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 @@ -304,6 +394,10 @@ cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent) 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)); + // Add a matrix for conversion V2 to V4 Lab PCS cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)); return Lut; @@ -407,6 +501,14 @@ cmsPipeline* BuildRGBOutputMatrixShaper(cmsHPROFILE hProfile) 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) { + + cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLab2XYZ(ContextID)); + } + cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocMatrix(ContextID, 3, 3, (cmsFloat64Number*) &Inv, NULL)); cmsPipelineInsertStage(Lut, cmsAT_END, cmsStageAllocToneCurves(ContextID, 3, InvShapes)); } @@ -415,6 +517,88 @@ cmsPipeline* BuildRGBOutputMatrixShaper(cmsHPROFILE hProfile) return Lut; } + +// 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(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); + + 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 accomodated to 0..1.0, we should undo this change + if ( PCS == cmsSigLabData) + { + cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID)); + } + else + if (PCS == cmsSigXYZData) + { + cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID)); + } + + return Lut; +}*/ + +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 accomodated to 0..1.0, we should undo this change + if ( PCS == cmsSigLabData) + { + cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID)); + } + else + if (PCS == cmsSigXYZData) + { + cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID)); + } + + // the output can be Lab or XYZ, in which case normalisation is needed on the end of the pipeline + if ( dataSpace == cmsSigLabData) + { + cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID)); + } + else if ( dataSpace == cmsSigXYZData) + { + cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID)); + } + + return Lut; +} + // Create an output MPE LUT from agiven profile. Version mismatches are handled here cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent) { @@ -425,8 +609,8 @@ cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent) if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence - // Floating point LUT are always V4, so no adjustment is required - return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat)); + // Floating point LUT are always V4 + return _cmsReadFloatOutputTag(hProfile, tagFloat); } // Revert to perceptual if no tag is found @@ -447,6 +631,12 @@ cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent) // 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) @@ -454,6 +644,11 @@ cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent) // Add a matrix for conversion V4 to V2 Lab PCS cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID)); + + // If the output is Lab, add also a conversion at the end + if (cmsGetColorSpace(hProfile) == cmsSigLabData) + cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)); + return Lut; } @@ -467,12 +662,46 @@ cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent) return BuildGrayOutputPipeline(hProfile); } - // Not gray, create a normal matrix-shaper + // 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) + { + cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToLabFloat(ContextID)); + } + else + if (spc == cmsSigXYZData) + { + cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageNormalizeToXyzFloat(ContextID)); + } + + if (PCS == cmsSigLabData) + { + cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID)); + } + else + if (PCS == cmsSigXYZData) + { + cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID)); + } + + return Lut; +} + // 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* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent) @@ -483,10 +712,30 @@ cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent) cmsTagSignature tagFloat = Device2PCSFloat[Intent]; cmsContext ContextID = cmsGetProfileContextID(hProfile); + + // On named color, take the appropiate tag + if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) { + + cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) cmsReadTag(hProfile, cmsSigNamedColor2Tag); + + if (nc == NULL) return NULL; + + Lut = cmsPipelineAlloc(ContextID, 0, 0); + if (Lut == NULL) { + cmsFreeNamedColorList(nc); + return NULL; + } + + cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocNamedColor(nc, FALSE)); + if (cmsGetColorSpace(hProfile) == cmsSigLabData) + cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)); + return Lut; + } + if (cmsIsTag(hProfile, tagFloat)) { // Float tag takes precedence - // Floating point LUT are always V4, no adjustment is required - return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat)); + // Floating point LUT are always V + return _cmsReadFloatDevicelinkTag(hProfile, tagFloat); } tagFloat = Device2PCSFloat[0]; @@ -509,6 +758,12 @@ cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent) // 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 (cmsGetColorSpace(hProfile) == cmsSigLabData) + ChangeInterpolationToTrilinear(Lut); // After reading it, we have info about the original type OriginalType = _cmsGetTagTrueType(hProfile, tag16); @@ -558,7 +813,7 @@ cmsBool CMSEXPORT cmsIsMatrixShaper(cmsHPROFILE hProfile) } // Returns TRUE if the intent is implemented as CLUT -cmsBool CMSEXPORT cmsIsCLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent, int UsedDirection) +cmsBool CMSEXPORT cmsIsCLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number UsedDirection) { const cmsTagSignature* TagTable; @@ -589,7 +844,7 @@ cmsBool CMSEXPORT cmsIsCLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent, int U // Return info about supported intents cmsBool CMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, - cmsUInt32Number Intent, int UsedDirection) + cmsUInt32Number Intent, cmsUInt32Number UsedDirection) { if (cmsIsCLUT(hProfile, Intent, UsedDirection)) return TRUE; @@ -607,7 +862,6 @@ cmsBool CMSEXPORT cmsIsIntentSupported(cmsHPROFILE 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; @@ -632,12 +886,13 @@ cmsSEQ* _cmsReadProfileSequence(cmsHPROFILE hProfile) NewSeq = cmsDupProfileSequenceDescription(ProfileSeq); // Ok, proceed to the mixing - for (i=0; i < ProfileSeq ->n; i++) { + 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); + memmove(&NewSeq ->seq[i].ProfileID, &ProfileId ->seq[i].ProfileID, sizeof(cmsProfileID)); + NewSeq ->seq[i].Description = cmsMLUdup(ProfileId ->seq[i].Description); + } } - return NewSeq; } diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c index e5534234282..76b14238bf7 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 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"), @@ -154,7 +154,7 @@ cmsBool CMSEXPORT cmsPipelineCheckAndRetreiveStages(const cmsPipeline* Lut, cms for (i=0; i < n; i++) { // Get asked type - Type = va_arg(args, cmsStageSignature); + Type = (cmsStageSignature)va_arg(args, cmsStageSignature); if (mpe ->Type != Type) { va_end(args); // Mismatch. We are done. @@ -197,9 +197,14 @@ void EvaluateCurves(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage *mpe) { - _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) mpe ->Data; + _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++) { @@ -210,9 +215,14 @@ void EvaluateCurves(const cmsFloat32Number In[], static void CurveSetElemTypeFree(cmsStage* mpe) { - _cmsStageToneCurvesData* Data = (_cmsStageToneCurvesData*) mpe ->Data; + _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) @@ -275,12 +285,14 @@ cmsStage* CMSEXPORT cmsStageAllocToneCurves(cmsContext ContextID, cmsUInt32Numbe EvaluateCurves, CurveSetDup, CurveSetElemTypeFree, NULL ); if (NewMPE == NULL) return NULL; - NewElem = (_cmsStageToneCurvesData*) _cmsMalloc(ContextID, sizeof(_cmsStageToneCurvesData)); + 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) { @@ -301,11 +313,10 @@ cmsStage* CMSEXPORT cmsStageAllocToneCurves(cmsContext ContextID, cmsUInt32Numbe cmsStageFree(NewMPE); return NULL; } + } - NewMPE ->Data = (void*) NewElem; - - return NewMPE; + return NewMPE; } @@ -402,6 +413,9 @@ cmsStage* CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number R 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, @@ -479,10 +493,20 @@ void EvaluateCLUTfloatIn16(const cmsFloat32Number In[], cmsFloat32Number Out[], static cmsUInt32Number CubeSize(const cmsUInt32Number Dims[], cmsUInt32Number b) { - cmsUInt32Number rv; + cmsUInt32Number rv, dim; - for (rv = 1; b > 0; b--) - rv *= Dims[b-1]; + _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; } @@ -549,17 +573,35 @@ cmsStage* CMSEXPORT cmsStageAllocCLut16bitGranular(cmsContext ContextID, _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*) _cmsMalloc(ContextID, sizeof(_cmsStageCLutData)); - if (NewElem == 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); @@ -578,8 +620,6 @@ cmsStage* CMSEXPORT cmsStageAllocCLut16bitGranular(cmsContext ContextID, return NULL; } - NewMPE ->Data = (void*) NewElem; - return NewMPE; } @@ -623,18 +663,37 @@ cmsStage* CMSEXPORT cmsStageAllocCLutFloatGranular(cmsContext ContextID, const c { cmsUInt32Number i, n; _cmsStageCLutData* NewElem; - cmsStage* NewMPE = _cmsStageAllocPlaceholder(ContextID, cmsSigCLutElemType, inputChan, outputChan, - EvaluateCLUTfloat, CLUTElemDup, CLutElemTypeFree, NULL); + 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*) _cmsMalloc(ContextID, sizeof(_cmsStageCLutData)); - if (NewElem == NULL) return NULL; + NewElem = (_cmsStageCLutData*) _cmsMallocZero(ContextID, sizeof(_cmsStageCLutData)); + if (NewElem == NULL) { + cmsStageFree(NewMPE); + return NULL; + } - NewElem -> nEntries = n = outputChan * CubeSize( clutPoints, inputChan); + 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); @@ -647,7 +706,6 @@ cmsStage* CMSEXPORT cmsStageAllocCLutFloatGranular(cmsContext ContextID, const c } } - NewMPE ->Data = (void*) NewElem; NewElem ->Params = _cmsComputeInterpParamsEx(ContextID, clutPoints, inputChan, outputChan, NewElem ->Tab.TFloat, CMS_LERP_FLAGS_FLOAT); if (NewElem ->Params == NULL) { @@ -715,8 +773,13 @@ cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, v int nInputs, nOutputs; cmsUInt32Number* nSamples; cmsUInt16Number In[cmsMAXCHANNELS], Out[MAX_STAGE_CHANNELS]; - _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data; + _cmsStageCLutData* clut; + if (mpe == NULL) return FALSE; + + clut = (_cmsStageCLutData*) mpe->Data; + + if (clut == NULL) return FALSE; nSamples = clut->Params ->nSamples; nInputs = clut->Params ->nInputs; @@ -726,6 +789,7 @@ cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, v if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE; nTotalPoints = CubeSize(nSamples, nInputs); + if (nTotalPoints == 0) return FALSE; index = 0; for (i = 0; i < nTotalPoints; i++) { @@ -779,6 +843,7 @@ cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE; nTotalPoints = CubeSize(nSamples, nInputs); + if (nTotalPoints == 0) return FALSE; index = 0; for (i = 0; i < nTotalPoints; i++) { @@ -828,6 +893,7 @@ cmsBool CMSEXPORT cmsSliceSpace16(cmsUInt32Number nInputs, const cmsUInt32Number if (nInputs >= cmsMAXCHANNELS) return FALSE; nTotalPoints = CubeSize(clutPoints, nInputs); + if (nTotalPoints == 0) return FALSE; for (i = 0; i < nTotalPoints; i++) { @@ -857,6 +923,7 @@ cmsInt32Number CMSEXPORT cmsSliceSpaceFloat(cmsUInt32Number nInputs, const cmsUI if (nInputs >= cmsMAXCHANNELS) return FALSE; nTotalPoints = CubeSize(clutPoints, nInputs); + if (nTotalPoints == 0) return FALSE; for (i = 0; i < nTotalPoints; i++) { @@ -992,6 +1059,89 @@ cmsStage* _cmsStageAllocLabV4ToV2(cmsContext ContextID) } +// 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; +} + + + // ******************************************************************************** // Type cmsSigXYZ2LabElemType // ******************************************************************************** @@ -1201,22 +1351,28 @@ cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUInt32Number In NewLUT ->DupDataFn = NULL; NewLUT ->FreeDataFn = NULL; NewLUT ->Data = NewLUT; - - NewLUT ->ContextID = ContextID; + NewLUT ->ContextID = ContextID; BlessLUT(NewLUT); 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; } @@ -1244,6 +1400,7 @@ void CMSEXPORT cmsPipelineFree(cmsPipeline* 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); } @@ -1251,6 +1408,7 @@ void CMSEXPORT cmsPipelineEval16(const cmsUInt16Number In[], cmsUInt16Number Out // 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); } @@ -1288,8 +1446,10 @@ cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut) Anterior = NewMPE; } - NewLUT ->DupDataFn = lut ->DupDataFn; - NewLUT ->FreeDataFn = lut ->FreeDataFn; + 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); @@ -1306,6 +1466,9 @@ void CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag { cmsStage* Anterior = NULL, *pt; + _cmsAssert(lut != NULL); + _cmsAssert(mpe != NULL); + switch (loc) { case cmsAT_BEGIN: @@ -1456,13 +1619,13 @@ cmsUInt32Number CMSEXPORT cmsPipelineStageCount(const cmsPipeline* lut) return n; } -// This function may be used to set the optional evalueator and a block of private data. If private data is being used, an optional +// 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, _cmsOPTeval16Fn Eval16, void* PrivateData, - _cmsOPTfreeDataFn FreePrivateDataFn, - _cmsOPTdupDataFn DupPrivateDataFn) + _cmsFreeUserDataFn FreePrivateDataFn, + _cmsDupUserDataFn DupPrivateDataFn) { Lut ->Eval16Fn = Eval16; @@ -1640,3 +1803,4 @@ cmsBool CMSEXPORT cmsPipelineEvalReverseFloat(cmsFloat32Number Target[], return TRUE; } + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmd5.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmd5.c index 881e425d402..ae00376ce3c 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmd5.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmd5.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 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"), diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c index 590020213df..ed9366c05d0 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 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"), @@ -202,3 +202,4 @@ void CMSEXPORT _cmsMAT3eval(cmsVEC3* r, const cmsMAT3* a, const cmsVEC3* v) 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 --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c index 156f6a54107..93a574e6654 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2012 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"), @@ -117,7 +117,7 @@ cmsBool GrowMLUpool(cmsMLU* mlu) } -// Grows a ntry table for a MLU. Each time this function is called, table size is multiplied times two. +// Grows a entry table for a MLU. Each time this function is called, table size is multiplied times two. static cmsBool GrowMLUtable(cmsMLU* mlu) { @@ -130,7 +130,7 @@ cmsBool GrowMLUtable(cmsMLU* mlu) AllocatedEntries = mlu ->AllocatedEntries * 2; // Check for overflow - if (AllocatedEntries < mlu ->AllocatedEntries) return FALSE; + if (AllocatedEntries / 2 != mlu ->AllocatedEntries) return FALSE; // Reallocate the memory NewPtr = (_cmsMLUentry*)_cmsRealloc(mlu ->ContextID, mlu ->Entries, AllocatedEntries*sizeof(_cmsMLUentry)); @@ -359,9 +359,9 @@ const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu, if (Best == -1) Best = 0; - v = mlu ->Entries + Best; + v = mlu ->Entries + Best; - if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language; + if (UsedLanguageCode != NULL) *UsedLanguageCode = v ->Language; if (UsedCountryCode != NULL) *UsedCountryCode = v ->Country; if (len != NULL) *len = v ->Len; @@ -372,8 +372,8 @@ const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu, // 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 char LanguageCode[3], const char CountryCode[3], + char* Buffer, cmsUInt32Number BufferSize) { const wchar_t *Wide; cmsUInt32Number StrLen = 0; @@ -417,8 +417,8 @@ cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu, // 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 char LanguageCode[3], const char CountryCode[3], + wchar_t* Buffer, cmsUInt32Number BufferSize) { const wchar_t *Wide; cmsUInt32Number StrLen = 0; @@ -491,6 +491,9 @@ cmsBool GrowNamedColorList(cmsNAMEDCOLORLIST* v) else size = v ->Allocated * 2; + // Keep a maximum color lists can grow, 100K entries seems reasonable + if (size > 1024*100) return FALSE; + NewPtr = (_cmsNAMEDCOLOR*) _cmsRealloc(v ->ContextID, v ->List, size * sizeof(_cmsNAMEDCOLOR)); if (NewPtr == NULL) return FALSE; @@ -516,6 +519,8 @@ cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, cmsUIn strncpy(v ->Prefix, Prefix, sizeof(v ->Prefix)); strncpy(v ->Suffix, Suffix, sizeof(v ->Suffix)); + v->Prefix[32] = v->Suffix[32] = 0; + v -> ColorantCount = ColorantCount; return v; @@ -569,9 +574,14 @@ cmsBool CMSEXPORT cmsAppendNamedColor(cmsNAMEDCOLORLIST* NamedColorList, for (i=0; i < 3; i++) NamedColorList ->List[NamedColorList ->nColors].PCS[i] = PCS == NULL ? 0 : PCS[i]; - if (Name != NULL) + if (Name != NULL) { + strncpy(NamedColorList ->List[NamedColorList ->nColors].Name, Name, sizeof(NamedColorList ->List[NamedColorList ->nColors].Name)); + + NamedColorList ->List[NamedColorList ->nColors].Name[cmsMAX_PATH-1] = 0; + + } else NamedColorList ->List[NamedColorList ->nColors].Name[0] = 0; @@ -644,6 +654,24 @@ void* DupNamedColorList(cmsStage* mpe) 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; ignored", index); + } + 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) { @@ -662,15 +690,15 @@ void EvalNamedColor(const cmsFloat32Number In[], cmsFloat32Number Out[], const c // Named color lookup element -cmsStage* _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList) +cmsStage* _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList, cmsBool UsePCS) { return _cmsStageAllocPlaceholder(NamedColorList ->ContextID, - cmsSigNamedColorElemType, - 1, 3, - EvalNamedColor, - DupNamedColorList, - FreeNamedColorList, - cmsDupNamedColorList(NamedColorList)); + cmsSigNamedColorElemType, + 1, UsePCS ? 3 : NamedColorList ->ColorantCount, + UsePCS ? EvalNamedColorPCS : EvalNamedColor, + DupNamedColorList, + FreeNamedColorList, + cmsDupNamedColorList(NamedColorList)); } @@ -771,3 +799,131 @@ Error: 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; + _cmsDICT* new_dict; + cmsDICTentry *entry; + + _cmsAssert(old_dict != NULL); + + hNew = cmsDictAlloc(old_dict ->ContextID); + if (hNew == NULL) return NULL; + + new_dict = (_cmsDICT*) hNew; + + // 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 --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsopt.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsopt.c index dab93e24fb7..808e03c0c98 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsopt.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsopt.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2011 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"), @@ -223,6 +223,12 @@ cmsBool PreOptimize(cmsPipeline* Lut) // 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); + if (Opt) AnyOpt = TRUE; } while (Opt); @@ -298,7 +304,7 @@ Prelin16Data* PrelinOpt16alloc(cmsContext ContextID, int nOutputs, cmsToneCurve** Out ) { int i; - Prelin16Data* p16 = (Prelin16Data*) _cmsMallocZero(ContextID, sizeof(Prelin16Data)); + Prelin16Data* p16 = _cmsMallocZero(ContextID, sizeof(Prelin16Data)); if (p16 == NULL) return NULL; p16 ->nInputs = nInputs; @@ -411,42 +417,54 @@ cmsBool PatchLUT(cmsStage* CLUT, cmsUInt16Number At[], cmsUInt16Number Value[], return FALSE; } - 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 (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 = p16 -> opta[3] * x0 + - p16 -> opta[2] * y0 + - p16 -> opta[1] * z0 + - p16 -> opta[0] * w0; + p16 -> opta[2] * y0 + + p16 -> opta[1] * z0 + + 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 = p16 -> opta[2] * x0 + - p16 -> opta[1] * y0 + - p16 -> opta[0] * z0; + p16 -> opta[1] * y0 + + 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 = p16 -> opta[0] * x0; @@ -462,13 +480,15 @@ cmsBool PatchLUT(cmsStage* CLUT, cmsUInt16Number At[], cmsUInt16Number Value[], return TRUE; } -// Auxiliar, to see if two values are equal. +// Auxiliar, to see if two values are equal or very different static cmsBool WhitesAreEqual(int n, cmsUInt16Number White1[], cmsUInt16Number White2[] ) { int i; for (i=0; i < n; i++) { + + if (abs(White1[i] - White2[i]) > 0xf000) return TRUE; // Values are so extremly different that the fixup should be avoided if (White1[i] != White2[i]) return FALSE; } return TRUE; @@ -491,6 +511,8 @@ cmsBool FixWhiteMisalignment(cmsPipeline* Lut, cmsColorSpaceSignature EntryColor &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); @@ -555,6 +577,7 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 { cmsPipeline* Src; cmsPipeline* Dest; + cmsStage* mpe; cmsStage* CLUT; cmsStage *KeepPreLin = NULL, *KeepPostLin = NULL; int nGridPoints; @@ -580,6 +603,13 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 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; @@ -817,8 +847,8 @@ void PrelinEval8(register const cmsUInt16Number Input[], cmsUInt8Number r, g, b; cmsS15Fixed16Number rx, ry, rz; cmsS15Fixed16Number c0, c1, c2, c3, Rest; - int OutChan; - register cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1; + int OutChan; + register cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1; Prelin8Data* p8 = (Prelin8Data*) D; register const cmsInterpParams* p = p8 ->p; int TotalOut = p -> nOutputs; @@ -892,15 +922,35 @@ void PrelinEval8(register const cmsUInt16Number Input[], } - Rest = c1 * rx + c2 * ry + c3 * rz; - - Output[OutChan] = (cmsUInt16Number)c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)); + 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) +{ + int i, Zeros = 0, Poles = 0; + int 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 / 4)) return TRUE; // Degenerated, mostly zeros + if (Poles > (nEntries / 4)) return TRUE; // Degenerated, mostly poles + + return FALSE; +} + // -------------------------------------------------------------------------------------------------------------- // We need xput over here @@ -917,6 +967,7 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte cmsStage* OptimizedCLUTmpe; cmsColorSpaceSignature ColorSpace, OutputColorSpace; cmsStage* OptimizedPrelinMpe; + cmsStage* mpe; cmsToneCurve** OptimizedPrelinCurves; _cmsStageCLutData* OptimizedPrelinCLUT; @@ -935,6 +986,14 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte } 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(T_COLORSPACE(*InputFormat)); OutputColorSpace = _cmsICCcolorSpace(T_COLORSPACE(*OutputFormat)); nGridPoints = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags); @@ -981,6 +1040,9 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte // Exclude if non-monotonic if (!cmsIsToneCurveMonotonic(Trans[t])) lIsSuitable = FALSE; + + if (IsDegenerated(Trans[t])) + lIsSuitable = FALSE; } // If it is not suitable, just quit @@ -1413,12 +1475,12 @@ void FillSecondShaper(cmsUInt16Number* Table, cmsToneCurve* Curve, cmsBool Is8Bi // 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 + 0.5); + 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 + 0.5); + else Table[i] = _cmsQuickSaturateWord(Val * 65535.0); } } @@ -1655,3 +1717,5 @@ cmsBool _cmsOptimizePipeline(cmsPipeline** PtrLut, return AnySuccess; } + + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c index 72d81a09d5f..0a2ba7b4499 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c @@ -57,8 +57,8 @@ // 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) +// cmsFloat32Number (4 bytes per component) and double (marked as 0 bytes per component +// as special case) // --------------------------------------------------------------------------- @@ -73,9 +73,7 @@ // * 0xffff / 0xff00 = (255 * 257) / (255 * 256) = 257 / 256 cmsINLINE cmsUInt16Number FomLabV2ToLabV4(cmsUInt16Number x) { - int a; - - a = (x << 8 | x) >> 8; // * 257 / 256 + int a = (x << 8 | x) >> 8; // * 257 / 256 if ( a > 0xffff) return 0xffff; return (cmsUInt16Number) a; } @@ -90,17 +88,18 @@ cmsINLINE cmsUInt16Number FomLabV4ToLabV2(cmsUInt16Number x) typedef struct { cmsUInt32Number Type; cmsUInt32Number Mask; - cmsFormatter16 Frm; + cmsFormatter16 Frm; } cmsFormatters16; typedef struct { cmsUInt32Number Type; cmsUInt32Number Mask; - cmsFormatterFloat Frm; + cmsFormatterFloat Frm; } cmsFormattersFloat; + #define ANYSPACE COLORSPACE_SH(31) #define ANYCHANNELS CHANNELS_SH(15) #define ANYEXTRA EXTRA_SH(7) @@ -119,6 +118,7 @@ typedef struct { // Unpacking routines (16 bits) ---------------------------------------------------------------------------------------- + // Does almost everything but is slow static cmsUInt8Number* UnrollChunkyBytes(register _cmsTRANSFORM* info, @@ -131,7 +131,7 @@ cmsUInt8Number* UnrollChunkyBytes(register _cmsTRANSFORM* info, int Reverse = T_FLAVOR(info ->InputFormat); int SwapFirst = T_SWAPFIRST(info -> InputFormat); int Extra = T_EXTRA(info -> InputFormat); - int ExtraFirst = DoSwap && !SwapFirst; + int ExtraFirst = DoSwap ^ SwapFirst; cmsUInt16Number v; int i; @@ -160,6 +160,10 @@ cmsUInt8Number* UnrollChunkyBytes(register _cmsTRANSFORM* info, } return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); + } // Extra channels are just ignored because come in the next planes @@ -169,13 +173,14 @@ cmsUInt8Number* UnrollPlanarBytes(register _cmsTRANSFORM* info, register cmsUInt8Number* accum, register cmsUInt32Number Stride) { - int nChan = T_CHANNELS(info -> InputFormat); - int DoSwap= T_DOSWAP(info ->InputFormat); - int Reverse= T_FLAVOR(info ->InputFormat); + int nChan = T_CHANNELS(info -> InputFormat); + int DoSwap = T_DOSWAP(info ->InputFormat); + int SwapFirst = T_SWAPFIRST(info ->InputFormat); + int Reverse = T_FLAVOR(info ->InputFormat); int i; cmsUInt8Number* Init = accum; - if (DoSwap) { + if (DoSwap ^ SwapFirst) { accum += T_EXTRA(info -> InputFormat) * Stride; } @@ -204,6 +209,9 @@ cmsUInt8Number* Unroll4Bytes(register _cmsTRANSFORM* info, wIn[3] = FROM_8_TO_16(*accum); accum++; // K return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -218,6 +226,9 @@ cmsUInt8Number* Unroll4BytesReverse(register _cmsTRANSFORM* info, wIn[3] = FROM_8_TO_16(REVERSE_FLAVOR_8(*accum)); accum++; // K return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -232,6 +243,9 @@ cmsUInt8Number* Unroll4BytesSwapFirst(register _cmsTRANSFORM* info, wIn[2] = FROM_8_TO_16(*accum); accum++; // Y return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } // KYMC @@ -247,6 +261,9 @@ cmsUInt8Number* Unroll4BytesSwap(register _cmsTRANSFORM* info, wIn[0] = FROM_8_TO_16(*accum); accum++; // C return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -261,6 +278,9 @@ cmsUInt8Number* Unroll4BytesSwapSwapFirst(register _cmsTRANSFORM* info, wIn[3] = FROM_8_TO_16(*accum); accum++; // C return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -274,6 +294,9 @@ cmsUInt8Number* Unroll3Bytes(register _cmsTRANSFORM* info, wIn[2] = FROM_8_TO_16(*accum); accum++; // B return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -288,6 +311,9 @@ cmsUInt8Number* Unroll3BytesSkip1Swap(register _cmsTRANSFORM* info, wIn[0] = FROM_8_TO_16(*accum); accum++; // R return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -302,6 +328,9 @@ cmsUInt8Number* Unroll3BytesSkip1SwapFirst(register _cmsTRANSFORM* info, wIn[2] = FROM_8_TO_16(*accum); accum++; // B return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } @@ -317,6 +346,9 @@ cmsUInt8Number* Unroll3BytesSwap(register _cmsTRANSFORM* info, wIn[0] = FROM_8_TO_16(*accum); accum++; // R return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -330,6 +362,9 @@ cmsUInt8Number* UnrollLabV2_8(register _cmsTRANSFORM* info, wIn[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // b return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -344,6 +379,9 @@ cmsUInt8Number* UnrollALabV2_8(register _cmsTRANSFORM* info, wIn[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // b return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -357,34 +395,30 @@ cmsUInt8Number* UnrollLabV2_16(register _cmsTRANSFORM* info, wIn[2] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2; // b return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } - - -// Monochrome + alpha. Alpha is lost +// for duplex static cmsUInt8Number* Unroll2Bytes(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++; // L - wIn[3] = FROM_8_TO_16(*accum); accum++; // alpha - return accum; -} - -static -cmsUInt8Number* Unroll2ByteSwapFirst(register _cmsTRANSFORM* info, register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { - wIn[3] = FROM_8_TO_16(*accum); accum++; // alpha - wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++; // L + 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(register _cmsTRANSFORM* info, @@ -393,7 +427,27 @@ cmsUInt8Number* Unroll1Byte(register _cmsTRANSFORM* info, register 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(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register 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 @@ -404,7 +458,11 @@ cmsUInt8Number* Unroll1ByteSkip2(register _cmsTRANSFORM* info, { wIn[0] = wIn[1] = wIn[2] = FROM_8_TO_16(*accum); accum++; // L accum += 2; + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -414,7 +472,11 @@ cmsUInt8Number* Unroll1ByteReversed(register _cmsTRANSFORM* info, register 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); } @@ -430,7 +492,7 @@ cmsUInt8Number* UnrollAnyWords(register _cmsTRANSFORM* info, int Reverse = T_FLAVOR(info ->InputFormat); int SwapFirst = T_SWAPFIRST(info -> InputFormat); int Extra = T_EXTRA(info -> InputFormat); - int ExtraFirst = DoSwap && !SwapFirst; + int ExtraFirst = DoSwap ^ SwapFirst; int i; if (ExtraFirst) { @@ -463,6 +525,8 @@ cmsUInt8Number* UnrollAnyWords(register _cmsTRANSFORM* info, } return accum; + + cmsUNUSED_PARAMETER(Stride); } static @@ -511,6 +575,9 @@ cmsUInt8Number* Unroll4Words(register _cmsTRANSFORM* info, wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // K return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -525,6 +592,9 @@ cmsUInt8Number* Unroll4WordsReverse(register _cmsTRANSFORM* info, wIn[3] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; // K return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -539,6 +609,9 @@ cmsUInt8Number* Unroll4WordsSwapFirst(register _cmsTRANSFORM* info, wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // Y return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } // KYMC @@ -554,6 +627,9 @@ cmsUInt8Number* Unroll4WordsSwap(register _cmsTRANSFORM* info, wIn[0] = *(cmsUInt16Number*) accum; accum+= 2; // C return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -568,6 +644,9 @@ cmsUInt8Number* Unroll4WordsSwapSwapFirst(register _cmsTRANSFORM* info, wIn[3] = *(cmsUInt16Number*) accum; accum+= 2; // C return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -579,7 +658,11 @@ cmsUInt8Number* Unroll3Words(register _cmsTRANSFORM* info, 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 @@ -591,7 +674,11 @@ cmsUInt8Number* Unroll3WordsSwap(register _cmsTRANSFORM* info, 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 @@ -606,6 +693,9 @@ cmsUInt8Number* Unroll3WordsSkip1Swap(register _cmsTRANSFORM* info, wIn[0] = *(cmsUInt16Number*) accum; accum += 2; // B return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -620,6 +710,9 @@ cmsUInt8Number* Unroll3WordsSkip1SwapFirst(register _cmsTRANSFORM* info, wIn[2] = *(cmsUInt16Number*) accum; accum += 2; // B return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -629,7 +722,11 @@ cmsUInt8Number* Unroll1Word(register _cmsTRANSFORM* info, register cmsUInt32Number Stride) { wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // L + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -639,7 +736,11 @@ cmsUInt8Number* Unroll1WordReversed(register _cmsTRANSFORM* info, register cmsUInt32Number Stride) { wIn[0] = wIn[1] = wIn[2] = REVERSE_FLAVOR_16(*(cmsUInt16Number*) accum); accum+= 2; + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -651,33 +752,29 @@ cmsUInt8Number* Unroll1WordSkip3(register _cmsTRANSFORM* info, wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum; accum += 8; + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static cmsUInt8Number* Unroll2Words(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) -{ - wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // L - wIn[3] = *(cmsUInt16Number*) accum; accum += 2; // alpha - - return accum; -} - -static -cmsUInt8Number* Unroll2WordSwapFirst(register _cmsTRANSFORM* info, register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { - wIn[3] = *(cmsUInt16Number*) accum; accum += 2; // alpha - wIn[0] = wIn[1] = wIn[2] = *(cmsUInt16Number*) accum; accum+= 2; // L + 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(register _cmsTRANSFORM* info, @@ -701,7 +798,41 @@ cmsUInt8Number* UnrollLabDoubleTo16(register _cmsTRANSFORM* info, else { cmsFloat2LabEncoded(wIn, (cmsCIELab*) accum); - accum += sizeof(cmsCIELab); + accum += sizeof(cmsCIELab) + T_EXTRA(info ->InputFormat) * sizeof(cmsFloat64Number); + return accum; + } +} + + +// This is a conversion of Lab float to 16 bits +static +cmsUInt8Number* UnrollLabFloatTo16(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + cmsCIELab Lab; + + if (T_PLANAR(info -> InputFormat)) { + + cmsFloat32Number* Pt = (cmsFloat32Number*) accum; + + + Lab.L = Pt[0]; + Lab.a = Pt[Stride]; + Lab.b = Pt[Stride*2]; + + 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; } } @@ -729,7 +860,7 @@ cmsUInt8Number* UnrollXYZDoubleTo16(register _cmsTRANSFORM* info, else { cmsFloat2XYZEncoded(wIn, (cmsCIEXYZ*) accum); - accum += sizeof(cmsCIEXYZ); + accum += sizeof(cmsCIEXYZ) + T_EXTRA(info ->InputFormat) * sizeof(cmsFloat64Number); return accum; } @@ -761,65 +892,117 @@ cmsINLINE cmsBool IsInkSpace(cmsUInt32Number Type) // Inks does come in percentage, remaining cases are between 0..1.0, again to 16 bits static cmsUInt8Number* UnrollDoubleTo16(register _cmsTRANSFORM* info, - register cmsUInt16Number wIn[], - register cmsUInt8Number* accum, - register cmsUInt32Number Stride) + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) { - cmsFloat64Number* Inks = (cmsFloat64Number*) accum; - int nChan = T_CHANNELS(info -> InputFormat); - int Planar = T_PLANAR(info -> InputFormat); - int i; + + int nChan = T_CHANNELS(info -> InputFormat); + int DoSwap = T_DOSWAP(info ->InputFormat); + int Reverse = T_FLAVOR(info ->InputFormat); + int SwapFirst = T_SWAPFIRST(info -> InputFormat); + int Extra = T_EXTRA(info -> InputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; + int Planar = T_PLANAR(info -> InputFormat); cmsFloat64Number v; - cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0; + cmsUInt16Number vi; + int i, start = 0; + cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0; + + + if (ExtraFirst) + start = Extra; for (i=0; i < nChan; i++) { + int index = DoSwap ? (nChan - i - 1) : i; + if (Planar) - - v = Inks[i * Stride]; + v = (cmsFloat32Number) ((cmsFloat64Number*) accum)[(i + start) * Stride]; else - v = Inks[i]; + v = (cmsFloat32Number) ((cmsFloat64Number*) accum)[i + start]; - wIn[i] = _cmsQuickSaturateWord(v * maximum); + 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 + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat64Number); + return accum + (nChan + Extra) * sizeof(cmsFloat64Number); } + + static cmsUInt8Number* UnrollFloatTo16(register _cmsTRANSFORM* info, register cmsUInt16Number wIn[], register cmsUInt8Number* accum, register cmsUInt32Number Stride) { - cmsFloat32Number* Inks = (cmsFloat32Number*) accum; - int nChan = T_CHANNELS(info -> InputFormat); - int Planar = T_PLANAR(info -> InputFormat); - int i; + + int nChan = T_CHANNELS(info -> InputFormat); + int DoSwap = T_DOSWAP(info ->InputFormat); + int Reverse = T_FLAVOR(info ->InputFormat); + int SwapFirst = T_SWAPFIRST(info -> InputFormat); + int Extra = T_EXTRA(info -> InputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; + int Planar = T_PLANAR(info -> InputFormat); cmsFloat32Number v; - cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0; + cmsUInt16Number vi; + int i, start = 0; + cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0; + + + if (ExtraFirst) + start = Extra; for (i=0; i < nChan; i++) { + int index = DoSwap ? (nChan - i - 1) : i; + if (Planar) - - v = Inks[i * Stride]; + v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[(i + start) * Stride]; else - v = Inks[i]; + v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[i + start]; - wIn[i] = _cmsQuickSaturateWord(v * maximum); + 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 + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat32Number); + return accum + (nChan + Extra) * sizeof(cmsFloat32Number); } + + // For 1 channel, we need to duplicate data (it comes in 0..1.0 range) static cmsUInt8Number* UnrollDouble1Chan(register _cmsTRANSFORM* info, @@ -832,12 +1015,13 @@ cmsUInt8Number* UnrollDouble1Chan(register _cmsTRANSFORM* info, wIn[0] = wIn[1] = wIn[2] = _cmsQuickSaturateWord(Inks[0] * 65535.0); return accum + sizeof(cmsFloat64Number); + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } //------------------------------------------------------------------------------------------------------------------- -// True cmsFloat32Number transformation. - // For anything going from cmsFloat32Number static cmsUInt8Number* UnrollFloatsToFloat(_cmsTRANSFORM* info, @@ -845,55 +1029,104 @@ cmsUInt8Number* UnrollFloatsToFloat(_cmsTRANSFORM* info, cmsUInt8Number* accum, cmsUInt32Number Stride) { - cmsFloat32Number* Inks = (cmsFloat32Number*) accum; - int nChan = T_CHANNELS(info -> InputFormat); - int Planar = T_PLANAR(info -> InputFormat); - int i; - cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 100.0 : 1.0; + + int nChan = T_CHANNELS(info -> InputFormat); + int DoSwap = T_DOSWAP(info ->InputFormat); + int Reverse = T_FLAVOR(info ->InputFormat); + int SwapFirst = T_SWAPFIRST(info -> InputFormat); + int Extra = T_EXTRA(info -> InputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; + int Planar = T_PLANAR(info -> InputFormat); + cmsFloat32Number v; + int i, start = 0; + cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 100.0F : 1.0F; - for (i=0; i < nChan; i++) { + if (ExtraFirst) + start = Extra; + + for (i=0; i < nChan; i++) { + + int index = DoSwap ? (nChan - i - 1) : i; if (Planar) - wIn[i] = (cmsFloat32Number) (Inks[i * Stride] / maximum); + v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[(i + start) * Stride]; else - wIn[i] = (cmsFloat32Number) (Inks[i] / maximum); + 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 + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat32Number); + return accum + (nChan + Extra) * sizeof(cmsFloat32Number); } // For anything going from double + static cmsUInt8Number* UnrollDoublesToFloat(_cmsTRANSFORM* info, - cmsFloat32Number wIn[], - cmsUInt8Number* accum, - cmsUInt32Number Stride) + cmsFloat32Number wIn[], + cmsUInt8Number* accum, + cmsUInt32Number Stride) { - cmsFloat64Number* Inks = (cmsFloat64Number*) accum; - int nChan = T_CHANNELS(info -> InputFormat); - int Planar = T_PLANAR(info -> InputFormat); - int i; + + int nChan = T_CHANNELS(info -> InputFormat); + int DoSwap = T_DOSWAP(info ->InputFormat); + int Reverse = T_FLAVOR(info ->InputFormat); + int SwapFirst = T_SWAPFIRST(info -> InputFormat); + int Extra = T_EXTRA(info -> InputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; + int Planar = T_PLANAR(info -> InputFormat); + cmsFloat64Number v; + int i, start = 0; cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 100.0 : 1.0; - for (i=0; i < nChan; i++) { + + if (ExtraFirst) + start = Extra; + + for (i=0; i < nChan; i++) { + + int index = DoSwap ? (nChan - i - 1) : i; if (Planar) - wIn[i] = (cmsFloat32Number) (Inks[i * Stride] / maximum); + v = (cmsFloat64Number) ((cmsFloat64Number*) accum)[(i + start) * Stride]; else - wIn[i] = (cmsFloat32Number) (Inks[i] / maximum); + 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 + T_EXTRA(info ->InputFormat)) * sizeof(cmsFloat64Number); + return accum + (nChan + Extra) * sizeof(cmsFloat64Number); } + // From Lab double to cmsFloat32Number static cmsUInt8Number* UnrollLabDoubleToFloat(_cmsTRANSFORM* info, @@ -913,11 +1146,11 @@ cmsUInt8Number* UnrollLabDoubleToFloat(_cmsTRANSFORM* info, } else { - wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1 + 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; + accum += sizeof(cmsFloat64Number)*(3 + T_EXTRA(info ->InputFormat)); return accum; } } @@ -933,7 +1166,7 @@ cmsUInt8Number* UnrollLabFloatToFloat(_cmsTRANSFORM* info, if (T_PLANAR(info -> InputFormat)) { - wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1 + 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); @@ -941,16 +1174,17 @@ cmsUInt8Number* UnrollLabFloatToFloat(_cmsTRANSFORM* info, } else { - wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1 + 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; + 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, @@ -974,7 +1208,7 @@ cmsUInt8Number* UnrollXYZDoubleToFloat(_cmsTRANSFORM* info, wIn[1] = (cmsFloat32Number) (Pt[1] / MAX_ENCODEABLE_XYZ); wIn[2] = (cmsFloat32Number) (Pt[2] / MAX_ENCODEABLE_XYZ); - accum += sizeof(cmsFloat64Number)*3; + accum += sizeof(cmsFloat64Number)*(3 + T_EXTRA(info ->InputFormat)); return accum; } } @@ -1001,11 +1235,13 @@ cmsUInt8Number* UnrollXYZFloatToFloat(_cmsTRANSFORM* info, wIn[1] = (cmsFloat32Number) (Pt[1] / MAX_ENCODEABLE_XYZ); wIn[2] = (cmsFloat32Number) (Pt[2] / MAX_ENCODEABLE_XYZ); - accum += sizeof(cmsFloat32Number)*3; + accum += sizeof(cmsFloat32Number)*(3 + T_EXTRA(info ->InputFormat)); return accum; } } + + // Packing routines ----------------------------------------------------------------------------------------------------------- @@ -1022,7 +1258,7 @@ cmsUInt8Number* PackAnyBytes(register _cmsTRANSFORM* info, int Reverse = T_FLAVOR(info ->OutputFormat); int Extra = T_EXTRA(info -> OutputFormat); int SwapFirst = T_SWAPFIRST(info -> OutputFormat); - int ExtraFirst = DoSwap && !SwapFirst; + int ExtraFirst = DoSwap ^ SwapFirst; cmsUInt8Number* swap1; cmsUInt8Number v = 0; int i; @@ -1057,6 +1293,8 @@ cmsUInt8Number* PackAnyBytes(register _cmsTRANSFORM* info, return output; + + cmsUNUSED_PARAMETER(Stride); } @@ -1073,7 +1311,7 @@ cmsUInt8Number* PackAnyWords(register _cmsTRANSFORM* info, int Reverse = T_FLAVOR(info ->OutputFormat); int Extra = T_EXTRA(info -> OutputFormat); int SwapFirst = T_SWAPFIRST(info -> OutputFormat); - int ExtraFirst = DoSwap && !SwapFirst; + int ExtraFirst = DoSwap ^ SwapFirst; cmsUInt16Number* swap1; cmsUInt16Number v = 0; int i; @@ -1113,6 +1351,8 @@ cmsUInt8Number* PackAnyWords(register _cmsTRANSFORM* info, return output; + + cmsUNUSED_PARAMETER(Stride); } @@ -1122,12 +1362,19 @@ cmsUInt8Number* PackPlanarBytes(register _cmsTRANSFORM* info, register cmsUInt8Number* output, register cmsUInt32Number Stride) { - int nChan = T_CHANNELS(info -> OutputFormat); - int DoSwap = T_DOSWAP(info ->OutputFormat); - int Reverse= T_FLAVOR(info ->OutputFormat); + int nChan = T_CHANNELS(info -> OutputFormat); + int DoSwap = T_DOSWAP(info ->OutputFormat); + int SwapFirst = T_SWAPFIRST(info ->OutputFormat); + int Reverse = T_FLAVOR(info ->OutputFormat); int i; cmsUInt8Number* Init = output; + + if (DoSwap ^ SwapFirst) { + output += T_EXTRA(info -> OutputFormat) * Stride; + } + + for (i=0; i < nChan; i++) { int index = DoSwap ? (nChan - i - 1) : i; @@ -1138,6 +1385,8 @@ cmsUInt8Number* PackPlanarBytes(register _cmsTRANSFORM* info, } return (Init + 1); + + cmsUNUSED_PARAMETER(Stride); } @@ -1194,6 +1443,9 @@ cmsUInt8Number* Pack6Bytes(register _cmsTRANSFORM* info, *output++ = FROM_16_TO_8(wOut[5]); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } // KCMYcm @@ -1212,6 +1464,9 @@ cmsUInt8Number* Pack6BytesSwap(register _cmsTRANSFORM* info, *output++ = FROM_16_TO_8(wOut[0]); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } // CMYKcm @@ -1235,6 +1490,9 @@ cmsUInt8Number* Pack6Words(register _cmsTRANSFORM* info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } // KCMYcm @@ -1258,6 +1516,9 @@ cmsUInt8Number* Pack6WordsSwap(register _cmsTRANSFORM* info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } @@ -1273,6 +1534,9 @@ cmsUInt8Number* Pack4Bytes(register _cmsTRANSFORM* info, *output++ = FROM_16_TO_8(wOut[3]); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -1287,6 +1551,9 @@ cmsUInt8Number* Pack4BytesReverse(register _cmsTRANSFORM* info, *output++ = REVERSE_FLAVOR_8(FROM_16_TO_8(wOut[3])); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } @@ -1302,6 +1569,9 @@ cmsUInt8Number* Pack4BytesSwapFirst(register _cmsTRANSFORM* info, *output++ = FROM_16_TO_8(wOut[2]); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } // ABGR @@ -1317,6 +1587,9 @@ cmsUInt8Number* Pack4BytesSwap(register _cmsTRANSFORM* info, *output++ = FROM_16_TO_8(wOut[0]); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -1331,6 +1604,9 @@ cmsUInt8Number* Pack4BytesSwapSwapFirst(register _cmsTRANSFORM* info, *output++ = FROM_16_TO_8(wOut[3]); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -1349,6 +1625,9 @@ cmsUInt8Number* Pack4Words(register _cmsTRANSFORM* info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -1367,6 +1646,9 @@ cmsUInt8Number* Pack4WordsReverse(register _cmsTRANSFORM* info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } // ABGR @@ -1386,6 +1668,9 @@ cmsUInt8Number* Pack4WordsSwap(register _cmsTRANSFORM* info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } // CMYK @@ -1405,6 +1690,9 @@ cmsUInt8Number* Pack4WordsBigEndian(register _cmsTRANSFORM* info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } @@ -1419,6 +1707,9 @@ cmsUInt8Number* PackLabV2_8(register _cmsTRANSFORM* info, *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[2])); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -1433,6 +1724,9 @@ cmsUInt8Number* PackALabV2_8(register _cmsTRANSFORM* info, *output++ = FROM_16_TO_8(FomLabV4ToLabV2(wOut[2])); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -1449,6 +1743,9 @@ cmsUInt8Number* PackLabV2_16(register _cmsTRANSFORM* info, output += 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -1462,6 +1759,9 @@ cmsUInt8Number* Pack3Bytes(register _cmsTRANSFORM* info, *output++ = FROM_16_TO_8(wOut[2]); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -1475,6 +1775,9 @@ cmsUInt8Number* Pack3BytesOptimized(register _cmsTRANSFORM* info, *output++ = (wOut[2] & 0xFF); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -1488,6 +1791,9 @@ cmsUInt8Number* Pack3BytesSwap(register _cmsTRANSFORM* info, *output++ = FROM_16_TO_8(wOut[0]); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -1501,6 +1807,9 @@ cmsUInt8Number* Pack3BytesSwapOptimized(register _cmsTRANSFORM* info, *output++ = (wOut[0] & 0xFF); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } @@ -1518,6 +1827,9 @@ cmsUInt8Number* Pack3Words(register _cmsTRANSFORM* info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -1534,6 +1846,9 @@ cmsUInt8Number* Pack3WordsSwap(register _cmsTRANSFORM* info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static @@ -1550,10 +1865,13 @@ cmsUInt8Number* Pack3WordsBigEndian(register _cmsTRANSFORM* info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3BytesAndSkip1(register _cmsTRANSFORM* Info, +cmsUInt8Number* Pack3BytesAndSkip1(register _cmsTRANSFORM* info, register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) @@ -1564,10 +1882,13 @@ cmsUInt8Number* Pack3BytesAndSkip1(register _cmsTRANSFORM* Info, output++; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3BytesAndSkip1Optimized(register _cmsTRANSFORM* Info, +cmsUInt8Number* Pack3BytesAndSkip1Optimized(register _cmsTRANSFORM* info, register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) @@ -1578,11 +1899,14 @@ cmsUInt8Number* Pack3BytesAndSkip1Optimized(register _cmsTRANSFORM* Info, output++; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3BytesAndSkip1SwapFirst(register _cmsTRANSFORM* Info, +cmsUInt8Number* Pack3BytesAndSkip1SwapFirst(register _cmsTRANSFORM* info, register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) @@ -1593,10 +1917,13 @@ cmsUInt8Number* Pack3BytesAndSkip1SwapFirst(register _cmsTRANSFORM* Info, *output++ = FROM_16_TO_8(wOut[2]); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3BytesAndSkip1SwapFirstOptimized(register _cmsTRANSFORM* Info, +cmsUInt8Number* Pack3BytesAndSkip1SwapFirstOptimized(register _cmsTRANSFORM* info, register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) @@ -1607,10 +1934,13 @@ cmsUInt8Number* Pack3BytesAndSkip1SwapFirstOptimized(register _cmsTRANSFORM* Inf *output++ = (wOut[2] & 0xFF); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3BytesAndSkip1Swap(register _cmsTRANSFORM* Info, +cmsUInt8Number* Pack3BytesAndSkip1Swap(register _cmsTRANSFORM* info, register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) @@ -1621,10 +1951,13 @@ cmsUInt8Number* Pack3BytesAndSkip1Swap(register _cmsTRANSFORM* Info, *output++ = FROM_16_TO_8(wOut[0]); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3BytesAndSkip1SwapOptimized(register _cmsTRANSFORM* Info, +cmsUInt8Number* Pack3BytesAndSkip1SwapOptimized(register _cmsTRANSFORM* info, register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) @@ -1635,11 +1968,14 @@ cmsUInt8Number* Pack3BytesAndSkip1SwapOptimized(register _cmsTRANSFORM* Info, *output++ = (wOut[0] & 0xFF); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirst(register _cmsTRANSFORM* Info, +cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirst(register _cmsTRANSFORM* info, register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) @@ -1650,10 +1986,13 @@ cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirst(register _cmsTRANSFORM* Info, output++; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirstOptimized(register _cmsTRANSFORM* Info, +cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirstOptimized(register _cmsTRANSFORM* info, register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) @@ -1664,10 +2003,13 @@ cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirstOptimized(register _cmsTRANSFORM* output++; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3WordsAndSkip1(register _cmsTRANSFORM* Info, +cmsUInt8Number* Pack3WordsAndSkip1(register _cmsTRANSFORM* info, register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) @@ -1681,10 +2023,13 @@ cmsUInt8Number* Pack3WordsAndSkip1(register _cmsTRANSFORM* Info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3WordsAndSkip1Swap(register _cmsTRANSFORM* Info, +cmsUInt8Number* Pack3WordsAndSkip1Swap(register _cmsTRANSFORM* info, register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) @@ -1698,11 +2043,14 @@ cmsUInt8Number* Pack3WordsAndSkip1Swap(register _cmsTRANSFORM* Info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3WordsAndSkip1SwapFirst(register _cmsTRANSFORM* Info, +cmsUInt8Number* Pack3WordsAndSkip1SwapFirst(register _cmsTRANSFORM* info, register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) @@ -1716,11 +2064,14 @@ cmsUInt8Number* Pack3WordsAndSkip1SwapFirst(register _cmsTRANSFORM* Info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack3WordsAndSkip1SwapSwapFirst(register _cmsTRANSFORM* Info, +cmsUInt8Number* Pack3WordsAndSkip1SwapSwapFirst(register _cmsTRANSFORM* info, register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) @@ -1734,46 +2085,61 @@ cmsUInt8Number* Pack3WordsAndSkip1SwapSwapFirst(register _cmsTRANSFORM* Info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack1Byte(register _cmsTRANSFORM* Info, +cmsUInt8Number* Pack1Byte(register _cmsTRANSFORM* info, register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { *output++ = FROM_16_TO_8(wOut[0]); + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack1ByteReversed(register _cmsTRANSFORM* Info, +cmsUInt8Number* Pack1ByteReversed(register _cmsTRANSFORM* info, register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { *output++ = FROM_16_TO_8(REVERSE_FLAVOR_16(wOut[0])); + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack1ByteSkip1(register _cmsTRANSFORM* Info, +cmsUInt8Number* Pack1ByteSkip1(register _cmsTRANSFORM* info, register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { *output++ = FROM_16_TO_8(wOut[0]); output++; + return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack1ByteSkip1SwapFirst(register _cmsTRANSFORM* Info, +cmsUInt8Number* Pack1ByteSkip1SwapFirst(register _cmsTRANSFORM* info, register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) @@ -1782,10 +2148,13 @@ cmsUInt8Number* Pack1ByteSkip1SwapFirst(register _cmsTRANSFORM* Info, *output++ = FROM_16_TO_8(wOut[0]); return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack1Word(register _cmsTRANSFORM* Info, +cmsUInt8Number* Pack1Word(register _cmsTRANSFORM* info, register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) @@ -1794,11 +2163,14 @@ cmsUInt8Number* Pack1Word(register _cmsTRANSFORM* Info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack1WordReversed(register _cmsTRANSFORM* Info, +cmsUInt8Number* Pack1WordReversed(register _cmsTRANSFORM* info, register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) @@ -1807,10 +2179,13 @@ cmsUInt8Number* Pack1WordReversed(register _cmsTRANSFORM* Info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack1WordBigEndian(register _cmsTRANSFORM* Info, +cmsUInt8Number* Pack1WordBigEndian(register _cmsTRANSFORM* info, register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) @@ -1819,11 +2194,14 @@ cmsUInt8Number* Pack1WordBigEndian(register _cmsTRANSFORM* Info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack1WordSkip1(register _cmsTRANSFORM* Info, +cmsUInt8Number* Pack1WordSkip1(register _cmsTRANSFORM* info, register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) @@ -1832,10 +2210,13 @@ cmsUInt8Number* Pack1WordSkip1(register _cmsTRANSFORM* Info, output+= 4; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } static -cmsUInt8Number* Pack1WordSkip1SwapFirst(register _cmsTRANSFORM* Info, +cmsUInt8Number* Pack1WordSkip1SwapFirst(register _cmsTRANSFORM* info, register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) @@ -1845,18 +2226,21 @@ cmsUInt8Number* Pack1WordSkip1SwapFirst(register _cmsTRANSFORM* Info, output+= 2; return output; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); } // Unencoded Float values -- don't try optimize speed static -cmsUInt8Number* PackLabDoubleFrom16(register _cmsTRANSFORM* Info, +cmsUInt8Number* PackLabDoubleFrom16(register _cmsTRANSFORM* info, register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { - if (T_PLANAR(Info -> OutputFormat)) { + if (T_PLANAR(info -> OutputFormat)) { cmsCIELab Lab; cmsFloat64Number* Out = (cmsFloat64Number*) output; @@ -1871,9 +2255,38 @@ cmsUInt8Number* PackLabDoubleFrom16(register _cmsTRANSFORM* Info, else { cmsLabEncoded2Float((cmsCIELab*) output, wOut); - return output + (sizeof(cmsCIELab) + T_EXTRA(Info ->OutputFormat) * sizeof(cmsFloat64Number)); + return output + (sizeof(cmsCIELab) + T_EXTRA(info ->OutputFormat) * sizeof(cmsFloat64Number)); } +} + +static +cmsUInt8Number* PackLabFloatFrom16(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + cmsCIELab Lab; + cmsLabEncoded2Float(&Lab, wOut); + + if (T_PLANAR(info -> OutputFormat)) { + + cmsFloat32Number* Out = (cmsFloat32Number*) output; + + 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 @@ -1888,7 +2301,7 @@ cmsUInt8Number* PackXYZDoubleFrom16(register _cmsTRANSFORM* Info, cmsFloat64Number* Out = (cmsFloat64Number*) output; cmsXYZEncoded2Float(&XYZ, wOut); - Out[0] = XYZ.X; + Out[0] = XYZ.X; Out[Stride] = XYZ.Y; Out[Stride*2] = XYZ.Z; @@ -1904,96 +2317,135 @@ cmsUInt8Number* PackXYZDoubleFrom16(register _cmsTRANSFORM* Info, } static -cmsUInt8Number* PackDoubleFrom16(register _cmsTRANSFORM* Info, - register cmsUInt16Number wOut[], - register cmsUInt8Number* output, - register cmsUInt32Number Stride) -{ - cmsFloat64Number* Inks = (cmsFloat64Number*) output; - int nChan = T_CHANNELS(Info -> OutputFormat); - int i; - cmsFloat64Number maximum = IsInkSpace(Info ->InputFormat) ? 655.35 : 65535.0; - - if (T_PLANAR(Info -> OutputFormat)) { - - for (i=0; i < nChan; i++) { - - Inks[i*Stride] = wOut[i] / maximum; - } - - return output + sizeof(cmsFloat64Number); - } - else { - - for (i=0; i < nChan; i++) { - - Inks[i] = wOut[i] / maximum; - } - - - return output + (nChan + T_EXTRA(Info ->OutputFormat)) * sizeof(cmsFloat64Number); - } - -} - -static -cmsUInt8Number* PackFloatFrom16(register _cmsTRANSFORM* Info, +cmsUInt8Number* PackDoubleFrom16(register _cmsTRANSFORM* info, register cmsUInt16Number wOut[], register cmsUInt8Number* output, register cmsUInt32Number Stride) { - cmsFloat32Number* Inks = (cmsFloat32Number*) output; - int nChan = T_CHANNELS(Info -> OutputFormat); - int i; - cmsFloat64Number maximum = IsInkSpace(Info ->OutputFormat) ? 655.35 : 65535.0; + int nChan = T_CHANNELS(info -> OutputFormat); + int DoSwap = T_DOSWAP(info ->OutputFormat); + int Reverse = T_FLAVOR(info ->OutputFormat); + int Extra = T_EXTRA(info -> OutputFormat); + int SwapFirst = T_SWAPFIRST(info -> OutputFormat); + int Planar = T_PLANAR(info -> OutputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; + cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 655.35 : 65535.0; + cmsFloat64Number v = 0; + cmsFloat64Number* swap1 = (cmsFloat64Number*) output; + int i, start = 0; - if (T_PLANAR(Info -> OutputFormat)) { + if (ExtraFirst) + start = Extra; - for (i=0; i < nChan; i++) { + for (i=0; i < nChan; i++) { - Inks[i*Stride] = (cmsFloat32Number) (wOut[i] / maximum); - } + int index = DoSwap ? (nChan - i - 1) : i; - return output + sizeof(cmsFloat32Number); + v = (cmsFloat64Number) wOut[index] / maximum; + + if (Reverse) + v = maximum - v; + + if (Planar) + ((cmsFloat64Number*) output)[(i + start) * Stride]= v; + else + ((cmsFloat64Number*) output)[i + start] = v; } - else { - for (i=0; i < nChan; i++) { - - Inks[i] = (cmsFloat32Number) (wOut[i] / maximum); - } - - - return output + (nChan + T_EXTRA(Info ->OutputFormat)) * sizeof(cmsFloat32Number); + if (!ExtraFirst) { + output += Extra * sizeof(cmsFloat64Number); } + 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 * sizeof(cmsFloat64Number); + } +static +cmsUInt8Number* PackFloatFrom16(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + int nChan = T_CHANNELS(info -> OutputFormat); + int DoSwap = T_DOSWAP(info ->OutputFormat); + int Reverse = T_FLAVOR(info ->OutputFormat); + int Extra = T_EXTRA(info -> OutputFormat); + int SwapFirst = T_SWAPFIRST(info -> OutputFormat); + int Planar = T_PLANAR(info -> OutputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; + cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 655.35 : 65535.0; + cmsFloat64Number v = 0; + cmsFloat32Number* swap1 = (cmsFloat32Number*) output; + int i, start = 0; + + if (ExtraFirst) + start = Extra; + + for (i=0; i < nChan; i++) { + + int 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 (!ExtraFirst) { + output += Extra * sizeof(cmsFloat32Number); + } + + 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 * sizeof(cmsFloat32Number); +} + + + // -------------------------------------------------------------------------------------------------------- static -cmsUInt8Number* PackChunkyFloatsFromFloat(_cmsTRANSFORM* info, - cmsFloat32Number wOut[], - cmsUInt8Number* output, - cmsUInt32Number Stride) +cmsUInt8Number* PackFloatsFromFloat(_cmsTRANSFORM* info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) { int nChan = T_CHANNELS(info -> OutputFormat); int DoSwap = T_DOSWAP(info ->OutputFormat); int Reverse = T_FLAVOR(info ->OutputFormat); int Extra = T_EXTRA(info -> OutputFormat); int SwapFirst = T_SWAPFIRST(info -> OutputFormat); - int ExtraFirst = DoSwap && !SwapFirst; + int Planar = T_PLANAR(info -> OutputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0; - cmsFloat32Number* swap1; + cmsFloat32Number* swap1 = (cmsFloat32Number*) output; cmsFloat64Number v = 0; - int i; + int i, start = 0; - swap1 = (cmsFloat32Number*) output; - - if (ExtraFirst) { - output += Extra * sizeof(cmsFloat32Number); - } + if (ExtraFirst) + start = Extra; for (i=0; i < nChan; i++) { @@ -2004,42 +2456,48 @@ cmsUInt8Number* PackChunkyFloatsFromFloat(_cmsTRANSFORM* info, if (Reverse) v = maximum - v; - *(cmsFloat32Number*) output = (cmsFloat32Number) v; - - output += sizeof(cmsFloat32Number); + if (Planar) + ((cmsFloat32Number*) output)[(i + start)* Stride]= (cmsFloat32Number) v; + else + ((cmsFloat32Number*) output)[i + start] = (cmsFloat32Number) v; } if (!ExtraFirst) { output += Extra * sizeof(cmsFloat32Number); } - if (Extra == 0 && SwapFirst) { + if (Extra == 0 && SwapFirst) { - memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat32Number)); + memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat32Number)); *swap1 = (cmsFloat32Number) v; } - - return output; + if (T_PLANAR(info -> OutputFormat)) + return output + sizeof(cmsFloat32Number); + else + return output + nChan * sizeof(cmsFloat32Number); } static -cmsUInt8Number* PackPlanarFloatsFromFloat(_cmsTRANSFORM* info, - cmsFloat32Number wOut[], - cmsUInt8Number* output, - cmsUInt32Number Stride) +cmsUInt8Number* PackDoublesFromFloat(_cmsTRANSFORM* info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) { - int nChan = T_CHANNELS(info -> OutputFormat); - int DoSwap = T_DOSWAP(info ->OutputFormat); - int Reverse= T_FLAVOR(info ->OutputFormat); - int i; - cmsUInt8Number* Init = output; + int nChan = T_CHANNELS(info -> OutputFormat); + int DoSwap = T_DOSWAP(info ->OutputFormat); + int Reverse = T_FLAVOR(info ->OutputFormat); + int Extra = T_EXTRA(info -> OutputFormat); + int SwapFirst = T_SWAPFIRST(info -> OutputFormat); + int Planar = T_PLANAR(info -> OutputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0; - cmsFloat64Number v; + cmsFloat64Number v = 0; + cmsFloat64Number* swap1 = (cmsFloat64Number*) output; + int i, start = 0; - if (DoSwap) { - output += T_EXTRA(info -> OutputFormat) * Stride * sizeof(cmsFloat32Number); - } + if (ExtraFirst) + start = Extra; for (i=0; i < nChan; i++) { @@ -2047,101 +2505,33 @@ cmsUInt8Number* PackPlanarFloatsFromFloat(_cmsTRANSFORM* info, v = wOut[index] * maximum; - if (Reverse) - v = maximum - v; - - *(cmsFloat32Number*) output = (cmsFloat32Number) v; - output += (Stride * sizeof(cmsFloat32Number)); - } - - return (Init + sizeof(cmsFloat32Number)); -} - - -static -cmsUInt8Number* PackChunkyDoublesFromFloat(_cmsTRANSFORM* info, - cmsFloat32Number wOut[], - cmsUInt8Number* output, - cmsUInt32Number Stride) -{ - int nChan = T_CHANNELS(info -> OutputFormat); - int DoSwap = T_DOSWAP(info ->OutputFormat); - int Reverse = T_FLAVOR(info ->OutputFormat); - int Extra = T_EXTRA(info -> OutputFormat); - int SwapFirst = T_SWAPFIRST(info -> OutputFormat); - int ExtraFirst = DoSwap && !SwapFirst; - cmsFloat64Number* swap1; - cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0; - cmsFloat64Number v = 0; - int i; - - swap1 = (cmsFloat64Number*) output; - - if (ExtraFirst) { - output += Extra * sizeof(cmsFloat64Number); - } - - for (i=0; i < nChan; i++) { - - int index = DoSwap ? (nChan - i - 1) : i; - - v = (cmsFloat64Number) wOut[index] * maximum; - if (Reverse) v = maximum - v; - *(cmsFloat64Number*) output = v; - - output += sizeof(cmsFloat64Number); + if (Planar) + ((cmsFloat64Number*) output)[(i + start) * Stride] = v; + else + ((cmsFloat64Number*) output)[i + start] = v; } if (!ExtraFirst) { output += Extra * sizeof(cmsFloat64Number); } - if (Extra == 0 && SwapFirst) { + if (Extra == 0 && SwapFirst) { - memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat64Number)); + memmove(swap1 + 1, swap1, (nChan-1)* sizeof(cmsFloat64Number)); *swap1 = v; } - return output; + if (T_PLANAR(info -> OutputFormat)) + return output + sizeof(cmsFloat64Number); + else + return output + nChan * sizeof(cmsFloat64Number); + } -static -cmsUInt8Number* PackPlanarDoublesFromFloat(_cmsTRANSFORM* info, - cmsFloat32Number wOut[], - cmsUInt8Number* output, - cmsUInt32Number Stride) -{ - int nChan = T_CHANNELS(info -> OutputFormat); - int DoSwap = T_DOSWAP(info ->OutputFormat); - int Reverse= T_FLAVOR(info ->OutputFormat); - int i; - cmsUInt8Number* Init = output; - cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0 : 1.0; - cmsFloat64Number v; - - if (DoSwap) { - output += T_EXTRA(info -> OutputFormat) * Stride * sizeof(cmsFloat64Number); - } - - for (i=0; i < nChan; i++) { - - int index = DoSwap ? (nChan - i - 1) : i; - - v = (cmsFloat64Number) wOut[index] * maximum; - - if (Reverse) - v = maximum - v; - - *(cmsFloat64Number*) output = v; - output += (Stride * sizeof(cmsFloat64Number)); - } - - return (Init + sizeof(cmsFloat64Number)); -} @@ -2156,7 +2546,7 @@ cmsUInt8Number* PackLabFloatFromFloat(_cmsTRANSFORM* Info, if (T_PLANAR(Info -> OutputFormat)) { - Out[0] = (cmsFloat32Number) (wOut[0] * 100.0); + 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); @@ -2173,6 +2563,7 @@ cmsUInt8Number* PackLabFloatFromFloat(_cmsTRANSFORM* Info, } + static cmsUInt8Number* PackLabDoubleFromFloat(_cmsTRANSFORM* Info, cmsFloat32Number wOut[], @@ -2183,7 +2574,7 @@ cmsUInt8Number* PackLabDoubleFromFloat(_cmsTRANSFORM* Info, if (T_PLANAR(Info -> OutputFormat)) { - Out[0] = (cmsFloat64Number) (wOut[0] * 100.0); + 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); @@ -2212,7 +2603,7 @@ cmsUInt8Number* PackXYZFloatFromFloat(_cmsTRANSFORM* Info, if (T_PLANAR(Info -> OutputFormat)) { - Out[0] = (cmsFloat32Number) (wOut[0] * MAX_ENCODEABLE_XYZ); + 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); @@ -2229,7 +2620,6 @@ cmsUInt8Number* PackXYZFloatFromFloat(_cmsTRANSFORM* Info, } - // Same, but convert to double static cmsUInt8Number* PackXYZDoubleFromFloat(_cmsTRANSFORM* Info, @@ -2241,7 +2631,7 @@ cmsUInt8Number* PackXYZDoubleFromFloat(_cmsTRANSFORM* Info, if (T_PLANAR(Info -> OutputFormat)) { - Out[0] = (cmsFloat64Number) (wOut[0] * MAX_ENCODEABLE_XYZ); + 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); @@ -2259,6 +2649,223 @@ cmsUInt8Number* PackXYZDoubleFromFloat(_cmsTRANSFORM* Info, } +// ---------------------------------------------------------------------------------------------------------------- + +#ifndef CMS_NO_HALF_SUPPORT + +// Decodes an stream of half floats to wIn[] described by input format + +static +cmsUInt8Number* UnrollHalfTo16(register _cmsTRANSFORM* info, + register cmsUInt16Number wIn[], + register cmsUInt8Number* accum, + register cmsUInt32Number Stride) +{ + + int nChan = T_CHANNELS(info -> InputFormat); + int DoSwap = T_DOSWAP(info ->InputFormat); + int Reverse = T_FLAVOR(info ->InputFormat); + int SwapFirst = T_SWAPFIRST(info -> InputFormat); + int Extra = T_EXTRA(info -> InputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; + int Planar = T_PLANAR(info -> InputFormat); + cmsFloat32Number v; + int i, start = 0; + cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 655.35F : 65535.0F; + + + if (ExtraFirst) + start = Extra; + + for (i=0; i < nChan; i++) { + + int 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(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) +{ + + int nChan = T_CHANNELS(info -> InputFormat); + int DoSwap = T_DOSWAP(info ->InputFormat); + int Reverse = T_FLAVOR(info ->InputFormat); + int SwapFirst = T_SWAPFIRST(info -> InputFormat); + int Extra = T_EXTRA(info -> InputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; + int Planar = T_PLANAR(info -> InputFormat); + cmsFloat32Number v; + int i, start = 0; + cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 100.0F : 1.0F; + + + if (ExtraFirst) + start = Extra; + + for (i=0; i < nChan; i++) { + + int 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(register _cmsTRANSFORM* info, + register cmsUInt16Number wOut[], + register cmsUInt8Number* output, + register cmsUInt32Number Stride) +{ + int nChan = T_CHANNELS(info -> OutputFormat); + int DoSwap = T_DOSWAP(info ->OutputFormat); + int Reverse = T_FLAVOR(info ->OutputFormat); + int Extra = T_EXTRA(info -> OutputFormat); + int SwapFirst = T_SWAPFIRST(info -> OutputFormat); + int Planar = T_PLANAR(info -> OutputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; + cmsFloat32Number maximum = IsInkSpace(info ->OutputFormat) ? 655.35F : 65535.0F; + cmsFloat32Number v = 0; + cmsUInt16Number* swap1 = (cmsUInt16Number*) output; + int i, start = 0; + + if (ExtraFirst) + start = Extra; + + for (i=0; i < nChan; i++) { + + int 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 (!ExtraFirst) { + output += Extra * sizeof(cmsUInt16Number); + } + + 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 * sizeof(cmsUInt16Number); +} + + + +static +cmsUInt8Number* PackHalfFromFloat(_cmsTRANSFORM* info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) +{ + int nChan = T_CHANNELS(info -> OutputFormat); + int DoSwap = T_DOSWAP(info ->OutputFormat); + int Reverse = T_FLAVOR(info ->OutputFormat); + int Extra = T_EXTRA(info -> OutputFormat); + int SwapFirst = T_SWAPFIRST(info -> OutputFormat); + int Planar = T_PLANAR(info -> OutputFormat); + int ExtraFirst = DoSwap ^ SwapFirst; + cmsFloat32Number maximum = IsInkSpace(info ->OutputFormat) ? 100.0F : 1.0F; + cmsUInt16Number* swap1 = (cmsUInt16Number*) output; + cmsFloat32Number v = 0; + int i, start = 0; + + if (ExtraFirst) + start = Extra; + + for (i=0; i < nChan; i++) { + + int 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 (!ExtraFirst) { + output += Extra * sizeof(cmsUInt16Number); + } + + 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 * sizeof(cmsUInt16Number); +} + +#endif + // ---------------------------------------------------------------------------------------------------------------- @@ -2266,19 +2873,24 @@ static cmsFormatters16 InputFormatters16[] = { // Type Mask Function // ---------------------------- ------------------------------------ ---------------------------- - { TYPE_Lab_DBL, ANYPLANAR, UnrollLabDoubleTo16}, - { TYPE_XYZ_DBL, ANYPLANAR, UnrollXYZDoubleTo16}, + { TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, UnrollLabDoubleTo16}, + { TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, UnrollXYZDoubleTo16}, + { TYPE_Lab_FLT, ANYPLANAR|ANYEXTRA, UnrollLabFloatTo16}, { TYPE_GRAY_DBL, 0, UnrollDouble1Chan}, - { FLOAT_SH(1)|BYTES_SH(0), ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, UnrollDoubleTo16}, - { FLOAT_SH(1)|BYTES_SH(4), ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, UnrollFloatTo16}, - + { 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}, - - { CHANNELS_SH(2)|BYTES_SH(1), ANYSPACE, Unroll2Bytes}, - { CHANNELS_SH(2)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll2ByteSwapFirst}, + { COLORSPACE_SH(PT_MCH2)|CHANNELS_SH(2)|BYTES_SH(1), 0, Unroll2Bytes}, { TYPE_LabV2_8, 0, UnrollLabV2_8 }, { TYPE_ALabV2_8, 0, UnrollALabV2_8 }, @@ -2295,17 +2907,17 @@ static cmsFormatters16 InputFormatters16[] = { { 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|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarBytes}, - { BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollChunkyBytes}, + { 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(2)|BYTES_SH(2)|SWAPFIRST_SH(1), ANYSPACE, Unroll2WordSwapFirst}, - { CHANNELS_SH(3)|BYTES_SH(2), ANYSPACE, Unroll3Words}, { CHANNELS_SH(4)|BYTES_SH(2), ANYSPACE, Unroll4Words}, @@ -2318,7 +2930,7 @@ static cmsFormatters16 InputFormatters16[] = { { 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)|PLANAR_SH(1), ANYFLAVOR|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarWords}, { BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollAnyWords}, }; @@ -2328,13 +2940,21 @@ static cmsFormattersFloat InputFormattersFloat[] = { // Type Mask Function // ---------------------------- ------------------------------------ ---------------------------- - { TYPE_Lab_DBL, ANYPLANAR, UnrollLabDoubleToFloat}, - { TYPE_Lab_FLT, ANYPLANAR, UnrollLabFloatToFloat}, - { TYPE_XYZ_DBL, ANYPLANAR, UnrollXYZDoubleToFloat}, - { TYPE_XYZ_FLT, ANYPLANAR, UnrollXYZFloatToFloat}, + { TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, UnrollLabDoubleToFloat}, + { TYPE_Lab_FLT, ANYPLANAR|ANYEXTRA, UnrollLabFloatToFloat}, - { FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollFloatsToFloat}, - { FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollDoublesToFloat}, + { 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 }; @@ -2345,9 +2965,9 @@ cmsFormatter _cmsGetStockInputFormatter(cmsUInt32Number dwInput, cmsUInt32Number cmsUInt32Number i; cmsFormatter fr; + switch (dwFlags) { - if (!(dwFlags & CMS_PACK_FLAGS_FLOAT)) { - + case CMS_PACK_FLAGS_16BITS: { for (i=0; i < sizeof(InputFormatters16) / sizeof(cmsFormatters16); i++) { cmsFormatters16* f = InputFormatters16 + i; @@ -2357,7 +2977,9 @@ cmsFormatter _cmsGetStockInputFormatter(cmsUInt32Number dwInput, cmsUInt32Number } } } - else { + break; + + case CMS_PACK_FLAGS_FLOAT: { for (i=0; i < sizeof(InputFormattersFloat) / sizeof(cmsFormattersFloat); i++) { cmsFormattersFloat* f = InputFormattersFloat + i; @@ -2367,6 +2989,11 @@ cmsFormatter _cmsGetStockInputFormatter(cmsUInt32Number dwInput, cmsUInt32Number } } } + break; + + default:; + + } fr.Fmt16 = NULL; return fr; @@ -2376,10 +3003,19 @@ static cmsFormatters16 OutputFormatters16[] = { // Type Mask Function // ---------------------------- ------------------------------------ ---------------------------- - { TYPE_Lab_DBL, ANYPLANAR, PackLabDoubleFrom16}, - { TYPE_XYZ_DBL, ANYPLANAR, PackXYZDoubleFrom16}, - { FLOAT_SH(1)|BYTES_SH(0), ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, PackDoubleFrom16}, - { FLOAT_SH(1)|BYTES_SH(4), ANYCHANNELS|ANYPLANAR|ANYEXTRA|ANYSPACE, PackFloatFrom16}, + { TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, PackLabDoubleFrom16}, + { TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, PackXYZDoubleFrom16}, + + { TYPE_Lab_FLT, ANYPLANAR|ANYEXTRA, PackLabFloatFrom16}, + + { 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}, @@ -2419,7 +3055,7 @@ static cmsFormatters16 OutputFormatters16[] = { { 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|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarBytes}, + { 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}, @@ -2453,41 +3089,38 @@ static cmsFormatters16 OutputFormatters16[] = { static cmsFormattersFloat OutputFormattersFloat[] = { // Type Mask Function // ---------------------------- --------------------------------------------------- ---------------------------- - { TYPE_Lab_FLT, ANYPLANAR, PackLabFloatFromFloat}, - { TYPE_XYZ_FLT, ANYPLANAR, PackXYZFloatFromFloat}, - { TYPE_Lab_DBL, ANYPLANAR, PackLabDoubleFromFloat}, - { TYPE_XYZ_DBL, ANYPLANAR, PackXYZDoubleFromFloat}, - { FLOAT_SH(1)|BYTES_SH(4), - ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackChunkyFloatsFromFloat }, - { FLOAT_SH(1)|BYTES_SH(4)|PLANAR_SH(1), ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarFloatsFromFloat}, - { FLOAT_SH(1)|BYTES_SH(0), - ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackChunkyDoublesFromFloat }, - { FLOAT_SH(1)|BYTES_SH(0)|PLANAR_SH(1), ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarDoublesFromFloat}, + { 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; - if (dwFlags & CMS_PACK_FLAGS_FLOAT) { + switch (dwFlags) + { - for (i=0; i < sizeof(OutputFormattersFloat) / sizeof(cmsFormattersFloat); i++) { - cmsFormattersFloat* f = OutputFormattersFloat + i; - - if ((dwInput & ~f ->Mask) == f ->Type) { - fr.FmtFloat = f ->Frm; - return fr; - } - } - - } - else { + case CMS_PACK_FLAGS_16BITS: { for (i=0; i < sizeof(OutputFormatters16) / sizeof(cmsFormatters16); i++) { cmsFormatters16* f = OutputFormatters16 + i; @@ -2497,6 +3130,24 @@ cmsFormatter _cmsGetStockOutputFormatter(cmsUInt32Number dwInput, cmsUInt32Numbe return fr; } } + } + break; + + case CMS_PACK_FLAGS_FLOAT: { + + for (i=0; i < sizeof(OutputFormattersFloat) / sizeof(cmsFormattersFloat); i++) { + cmsFormattersFloat* f = OutputFormattersFloat + i; + + if ((dwInput & ~f ->Mask) == f ->Type) { + fr.FmtFloat = f ->Frm; + return fr; + } + } + } + break; + + default:; + } fr.Fmt16 = NULL; @@ -2523,8 +3174,8 @@ cmsBool _cmsRegisterFormattersPlugin(cmsPluginBase* Data) // Reset if (Data == NULL) { - FactoryList = NULL; - return TRUE; + FactoryList = NULL; + return TRUE; } fl = (cmsFormattersFactoryList*) _cmsPluginMalloc(sizeof(cmsFormattersFactoryList)); @@ -2540,7 +3191,7 @@ cmsBool _cmsRegisterFormattersPlugin(cmsPluginBase* Data) cmsFormatter _cmsGetFormatter(cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8 cmsFormatterDirection Dir, - cmsUInt32Number dwFlags) // Float or 16 bits + cmsUInt32Number dwFlags) { cmsFormattersFactoryList* f; @@ -2597,3 +3248,4 @@ cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsU // Create a fake formatter for result return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans); } + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c index b85de13c0f0..461f253a7b7 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c @@ -898,6 +898,7 @@ cmsUInt32Number CMSEXPORT cmsChannelsOf(cmsColorSpaceSignature ColorSpace) { switch (ColorSpace) { + case cmsSig1colorData: case cmsSigGrayData: return 1; case cmsSig2colorData: return 2; diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c index 8fa37438a5d..1e91d001231 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c @@ -105,12 +105,12 @@ cmsUInt32Number CMSEXPORT _cmsAdjustEndianess32(cmsUInt32Number DWord) // 1 2 3 4 5 6 7 8 // 8 7 6 5 4 3 2 1 -void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number QWord) +void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number* QWord) { #ifndef CMS_USE_BIG_ENDIAN - cmsUInt8Number* pIn = (cmsUInt8Number*) &QWord; + cmsUInt8Number* pIn = (cmsUInt8Number*) QWord; cmsUInt8Number* pOut = (cmsUInt8Number*) Result; _cmsAssert(Result != NULL); @@ -128,7 +128,7 @@ void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number Q _cmsAssert(Result != NULL); - *Result = QWord; + *Result = *QWord; #endif } @@ -218,7 +218,7 @@ cmsBool CMSEXPORT _cmsReadUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n) if (io -> Read(io, &tmp, sizeof(cmsUInt64Number), 1) != 1) return FALSE; - if (n != NULL) _cmsAdjustEndianess64(n, tmp); + if (n != NULL) _cmsAdjustEndianess64(n, &tmp); return TRUE; } @@ -340,7 +340,7 @@ cmsBool CMSEXPORT _cmsWriteFloat32Number(cmsIOHANDLER* io, cmsFloat32Number n) return TRUE; } -cmsBool CMSEXPORT _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number n) +cmsBool CMSEXPORT _cmsWriteUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n) { cmsUInt64Number tmp; @@ -568,7 +568,7 @@ cmsBool CMSEXPORT cmsPlugin(void* Plug_in) if (Plugin ->ExpectedVersion > LCMS_VERSION) { cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "plugin needs Little CMS %d, current version is %d", - Plugin ->ExpectedVersion, LCMS_VERSION); + Plugin ->ExpectedVersion, LCMS_VERSION); return FALSE; } @@ -610,6 +610,10 @@ cmsBool CMSEXPORT cmsPlugin(void* Plug_in) if (!_cmsRegisterOptimizationPlugin(Plugin)) return FALSE; break; + case cmsPluginTransformSig: + if (!_cmsRegisterTransformPlugin(Plugin)) return FALSE; + break; + default: cmsSignalError(0, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type); return FALSE; @@ -633,6 +637,7 @@ void CMSEXPORT cmsUnregisterPlugins(void) _cmsRegisterParametricCurvesPlugin(NULL); _cmsRegisterMultiProcessElementPlugin(NULL); _cmsRegisterOptimizationPlugin(NULL); + _cmsRegisterTransformPlugin(NULL); if (PluginPool != NULL) _cmsSubAllocDestroy(PluginPool); diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c index d0d3ef7bd17..a9672bdf71a 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2008 Marti Maria Saguer +// Copyright (c) 1998-2011 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"), @@ -329,9 +329,9 @@ cmsUInt8Number Word2Byte(cmsUInt16Number w) static cmsUInt8Number L2Byte(cmsUInt16Number w) { - int ww = w + 0x0080; + int ww = w + 0x0080; - if (ww > 0xFFFF) return 0xFF; + if (ww > 0xFFFF) return 0xFF; return (cmsUInt8Number) ((cmsUInt16Number) (ww >> 8) & 0xFF); } @@ -498,6 +498,7 @@ void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table) cmsUInt32Number i; cmsFloat64Number gamma; + if (Table == NULL) return; // Error if (Table ->nEntries <= 0) return; // Empty table @@ -577,6 +578,8 @@ void EmitNGamma(cmsIOHANDLER* m, int n, cmsToneCurve* g[]) 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]->nEntries)) { _cmsIOPrintf(m, "dup "); @@ -674,6 +677,7 @@ int OutputValueSampler(register const cmsUInt16Number In[], register cmsUInt16Nu cmsUInt16Number wWordOut = Out[i]; cmsUInt8Number wByteOut; // Value as byte + // We always deal with Lab4 wByteOut = Word2Byte(wWordOut); @@ -771,9 +775,9 @@ int EmitCIEBasedABC(cmsIOHANDLER* m, cmsFloat64Number* Matrix, cmsToneCurve** Cu for( i=0; i < 3; i++ ) { - _cmsIOPrintf(m, "%.6f %.6f %.6f ", Matrix[0 + 3*i], - Matrix[1 + 3*i], - Matrix[2 + 3*i]); + _cmsIOPrintf(m, "%.6f %.6f %.6f ", Matrix[i + 3*0], + Matrix[i + 3*1], + Matrix[i + 3*2]); } @@ -857,21 +861,23 @@ int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, int Intent, cmsCIEXY // Generates a curve from a gray profile static -cmsToneCurve* ExtractGray2Y(cmsContext ContextID, cmsHPROFILE hProfile, int Intent) + cmsToneCurve* ExtractGray2Y(cmsContext ContextID, cmsHPROFILE hProfile, int 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; - for (i=0; i < 256; i++) { + if (Out != NULL) { + for (i=0; i < 256; i++) { - cmsUInt8Number Gray = (cmsUInt8Number) i; - cmsCIEXYZ XYZ; + cmsUInt8Number Gray = (cmsUInt8Number) i; + cmsCIEXYZ XYZ; - cmsDoTransform(xform, &Gray, &XYZ, 1); + cmsDoTransform(xform, &Gray, &XYZ, 1); - Out ->Table16[i] =_cmsQuickSaturateWord(XYZ.Y * 65535.0); + Out ->Table16[i] =_cmsQuickSaturateWord(XYZ.Y * 65535.0); + } } cmsDeleteTransform(xform); @@ -924,7 +930,7 @@ int WriteInputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Nu switch (nChannels) { case 1: { - cmsToneCurve* Gray2Y = ExtractGray2Y(m ->ContextID, hProfile, Intent); + cmsToneCurve* Gray2Y = ExtractGray2Y(m ->ContextID, hProfile, Intent); EmitCIEBasedA(m, Gray2Y, &BlackPointAdaptedToD50); cmsFreeToneCurve(Gray2Y); } @@ -932,7 +938,7 @@ int WriteInputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Nu case 3: case 4: { - cmsUInt32Number OutFrm = TYPE_Lab_16; + cmsUInt32Number OutFrm = TYPE_Lab_16; cmsPipeline* DeviceLink; _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform; @@ -984,14 +990,23 @@ int WriteInputMatrixShaper(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsStage* Matr if (ColorSpace == cmsSigGrayData) { cmsToneCurve** ShaperCurve = _cmsStageGetPtrToCurveSet(Shaper); - rc = EmitCIEBasedA(m, ShaperCurve[0], &BlackPointAdaptedToD50); + rc = EmitCIEBasedA(m, ShaperCurve[0], &BlackPointAdaptedToD50); } else if (ColorSpace == cmsSigRgbData) { - rc = EmitCIEBasedABC(m, GetPtrToMatrix(Matrix), - _cmsStageGetPtrToCurveSet(Shaper), + 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 { @@ -1000,7 +1015,7 @@ int WriteInputMatrixShaper(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsStage* Matr return 0; } - return rc; + return rc; } @@ -1084,8 +1099,8 @@ cmsUInt32Number GenerateCSA(cmsContext ContextID, if (ColorSpace != cmsSigXYZData && ColorSpace != cmsSigLabData) { - cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Invalid output color space"); - goto Error; + cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Invalid output color space"); + goto Error; } @@ -1101,8 +1116,8 @@ cmsUInt32Number GenerateCSA(cmsContext ContextID, } else { - // We need a LUT for the rest - if (!WriteInputLUT(mem, hProfile, Intent, dwFlags)) goto Error; + // We need a LUT for the rest + if (!WriteInputLUT(mem, hProfile, Intent, dwFlags)) goto Error; } } @@ -1211,7 +1226,7 @@ void EmitPQRStage(cmsIOHANDLER* m, cmsHPROFILE hProfile, int DoBPC, int lIsAbsol "{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); + White.X, White.Y, White.Z); return; } @@ -1534,24 +1549,25 @@ cmsUInt32Number GenerateCRD(cmsContext ContextID, cmsUInt32Number CMSEXPORT cmsGetPostScriptColorResource(cmsContext ContextID, - cmsPSResourceType Type, - cmsHPROFILE hProfile, - cmsUInt32Number Intent, - cmsUInt32Number dwFlags, - cmsIOHANDLER* io) + 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; + 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; @@ -1560,7 +1576,7 @@ cmsUInt32Number CMSEXPORT cmsGetPostScriptColorResource(cmsContext ContextID, cmsUInt32Number CMSEXPORT cmsGetPostScriptCRD(cmsContext ContextID, - cmsHPROFILE hProfile, + cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags, void* Buffer, cmsUInt32Number dwBufferLen) { diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c index a06226e13b9..2dccc5433ff 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c @@ -216,7 +216,6 @@ cmsBool BlackPointUsingPerceptualBlack(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfi // 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) { @@ -292,3 +291,307 @@ cmsBool CMSEXPORT cmsDetectBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfil 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 disc; + 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; + + // y = t x2 + u x + c + // x = ( - u + Sqrt( u^2 - 4 t c ) ) / ( 2 t ) + disc = res.n[1]*res.n[1] - 4.0 * res.n[0] * res.n[2]; + if (disc < 0) return -1; + + return ( -1.0 * res.n[1] + sqrt( disc )) / (2.0 * res.n[0]); +} + +static +cmsBool IsMonotonic(int n, const cmsFloat64Number Table[]) +{ + int i; + cmsFloat64Number last; + + last = Table[n-1]; + + for (i = n-2; i >= 0; --i) { + + if (Table[i] > last) + + return FALSE; + else + last = Table[i]; + + } + + return TRUE; +} + +// 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 MinL, MaxL; + cmsBool NearlyStraightMidRange = FALSE; + cmsFloat64Number L; + cmsFloat64Number x[101], y[101]; + cmsFloat64Number lo, hi, NonMonoMin; + int n, l, i, NonMonoIndx; + + + // 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!, presto chargo hocus pocus, go for the Adobe magic + + // Step 1 + // ====== + + // 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; + + // Calculate Min L* + Lab = InitialLab; + Lab.L = 0; + cmsDoTransform(hRoundTrip, &Lab, &destLab, 1); + MinL = destLab.L; + + // Calculate Max L* + Lab = InitialLab; + Lab.L = 100; + cmsDoTransform(hRoundTrip, &Lab, &destLab, 1); + MaxL = destLab.L; + + // Step 3 + // ====== + + // check if quadratic estimation needs to be done. + if (Intent == INTENT_RELATIVE_COLORIMETRIC) { + + // Conceptually, this code tests how close the source l and converted L are to one another in the mid-range + // of the values. If the converted ramp of L values is close enough to a straight line y=x, then InitialLab + // is good enough to be the DestinationBlackPoint, + NearlyStraightMidRange = TRUE; + + for (l=0; l <= 100; l++) { + + Lab.L = l; + Lab.a = InitialLab.a; + Lab.b = InitialLab.b; + + cmsDoTransform(hRoundTrip, &Lab, &destLab, 1); + + L = destLab.L; + + // Check the mid range in 20% after MinL + if (L > (MinL + 0.2 * (MaxL - MinL))) { + + // Is close enough? + if (fabs(L - l) > 4.0) { + + // Too far away, profile is buggy! + NearlyStraightMidRange = FALSE; + break; + } + } + } + } + else { + // Check is always performed for perceptual and saturation intents + NearlyStraightMidRange = FALSE; + } + + + // If no furter checking is needed, we are done + if (NearlyStraightMidRange) { + + cmsLab2XYZ(NULL, BlackPoint, &InitialLab); + cmsDeleteTransform(hRoundTrip); + return TRUE; + } + + // 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. + + // STEP 4 + // ======= + + // 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 points for the fitting. + n = 0; + for (l=0; l <= 100; l++) { + + cmsFloat64Number ff; + + Lab.L = (cmsFloat64Number) l; + Lab.a = InitialLab.a; + Lab.b = InitialLab.b; + + cmsDoTransform(hRoundTrip, &Lab, &destLab, 1); + + ff = (destLab.L - MinL)/(MaxL - MinL); + + if (ff >= lo && ff < hi) { + + x[n] = Lab.L; + y[n] = ff; + n++; + } + + } + + // This part is not on the Adobe paper, but I found is necessary for getting any result. + + if (IsMonotonic(n, y)) { + + // Monotonic means lower point is stil valid + cmsLab2XYZ(NULL, BlackPoint, &InitialLab); + cmsDeleteTransform(hRoundTrip); + return TRUE; + } + + // No suitable points, regret and use safer algorithm + if (n == 0) { + cmsDeleteTransform(hRoundTrip); + return cmsDetectBlackPoint(BlackPoint, hProfile, Intent, dwFlags); + } + + + NonMonoMin = 100; + NonMonoIndx = 0; + for (i=0; i < n; i++) { + + if (y[i] < NonMonoMin) { + NonMonoIndx = i; + NonMonoMin = y[i]; + } + } + + Lab.L = x[NonMonoIndx]; + + // fit and get the vertex of quadratic curve + Lab.L = RootOfLeastSquaresFitQuadraticCurve(n, x, y); + + if (Lab.L < 0.0 || Lab.L > 50.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 --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmssm.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmssm.c index 68e86aa3b26..783f3c31bf5 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmssm.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmssm.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2011 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"), @@ -468,7 +468,8 @@ static int FindNearSectors(cmsGDB* gbd, int alpha, int theta, cmsGDBPoint* Close[]) { int nSectors = 0; - int i, a, t; + int a, t; + cmsUInt32Number i; cmsGDBPoint* pt; for (i=0; i < NSTEPS; i++) { @@ -505,7 +506,7 @@ cmsBool InterpolateMissingSector(cmsGDB* gbd, int alpha, int theta) cmsVEC3 Centre; cmsLine ray; int nCloseSectors; - cmsGDBPoint* Close[NSTEPS]; + cmsGDBPoint* Close[NSTEPS + 1]; cmsSpherical closel, templ; cmsLine edge; int k, m; @@ -582,13 +583,13 @@ cmsBool CMSEXPORT cmsGDBCompute(cmsHANDLE hGBD, cmsUInt32Number dwFlags) _cmsAssert(hGBD != NULL); // Interpolate black - for (alpha = 0; alpha <= SECTORS; alpha++) { + for (alpha = 0; alpha < SECTORS; alpha++) { if (!InterpolateMissingSector(gbd, alpha, 0)) return FALSE; } // Interpolate white - for (alpha = 0; alpha <= SECTORS; alpha++) { + for (alpha = 0; alpha < SECTORS; alpha++) { if (!InterpolateMissingSector(gbd, alpha, SECTORS-1)) return FALSE; } @@ -596,7 +597,7 @@ cmsBool CMSEXPORT cmsGDBCompute(cmsHANDLE hGBD, cmsUInt32Number dwFlags) // Interpolate Mid for (theta = 1; theta < SECTORS; theta++) { - for (alpha = 0; alpha <= SECTORS; alpha++) { + for (alpha = 0; alpha < SECTORS; alpha++) { if (!InterpolateMissingSector(gbd, alpha, theta)) return FALSE; } @@ -760,3 +761,4 @@ cmsBool cmsGBDdumpVRML(cmsHANDLE hGBD, const char* fname) return TRUE; } #endif + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmstypes.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmstypes.c index 102c7ce96c4..79cdda7c43e 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmstypes.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmstypes.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2011 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"), @@ -84,10 +84,10 @@ typedef struct _cmsTagTypeLinkedList_st { #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) } +#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 } +#define TYPE_MPE_HANDLER(t, x) { (t), READ_FN(x), WRITE_FN(x), GenericMPEdup, GenericMPEfree, NULL, 0 } // Register a new type handler. This routine is shared between normal types and MPE static @@ -154,7 +154,7 @@ cmsBool _cmsWriteWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, const wchar_t* cmsUInt32Number i; _cmsAssert(io != NULL); - _cmsAssert(Array != NULL); + _cmsAssert(!(Array == NULL && n > 0)); for (i=0; i < n; i++) { if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) Array[i])) return FALSE; @@ -163,6 +163,28 @@ cmsBool _cmsWriteWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, const wchar_t* return TRUE; } +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, @@ -171,8 +193,8 @@ typedef cmsBool (* PositionTableEntryFn)(struct _cms_typehandler_struct* self, cmsUInt32Number n, cmsUInt32Number SizeOfTag); -// Helper function to deal with position tables as decribed in several addendums to ICC spec 4.2 -// A table of n elements is written, where first comes n records containing offsets and sizes and +// Helper function to deal with position tables as decribed in ICC spec 4.3 +// A table of n elements is readed, 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, @@ -224,7 +246,7 @@ Error: static cmsBool WritePositionTable(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, - cmsUInt32Number SizeOfTag, + cmsUInt32Number SizeOfTag, cmsUInt32Number Count, cmsUInt32Number BaseOffset, void *Cargo, @@ -713,6 +735,8 @@ void *Type_Text_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms *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; @@ -807,13 +831,20 @@ void *Type_Data_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms 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)) return NULL; + if (!_cmsReadUInt32Number(io, &BinData->flag)) { + _cmsFree(self ->ContextID, BinData); + return NULL; + } if (io -> Read(io, BinData ->data, sizeof(cmsUInt8Number), LenOfData) != LenOfData) { @@ -1104,6 +1135,9 @@ void *Type_Curve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm 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; @@ -1219,17 +1253,23 @@ static cmsBool Type_ParametricCurve_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) { cmsToneCurve* Curve = (cmsToneCurve*) Ptr; - int i, nParams; + int i, nParams, typen; static const int ParamsByType[] = { 0, 1, 3, 4, 5, 7 }; + typen = Curve -> Segments[0].Type; - if (Curve ->nSegments > 1 || Curve -> Segments[0].Type < 1) { + if (Curve ->nSegments > 1 || typen < 1) { - cmsSignalError(self->ContextID, 0, "Multisegment or Inverted parametric curves cannot be written"); + cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Multisegment or Inverted parametric curves cannot be written"); return FALSE; } - nParams = ParamsByType[Curve ->Segments[0].Type]; + 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 @@ -1394,13 +1434,11 @@ void Type_Measurement_Free(struct _cms_typehandler_struct* self, void* 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) // -// FIXME: this doesn't work if sizeof(wchat_t) != 2 !!! static void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) @@ -1410,7 +1448,7 @@ void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU cmsUInt32Number SizeOfHeader; cmsUInt32Number Len, Offset; cmsUInt32Number i; - cmsUInt16Number* Block; + wchar_t* Block; cmsUInt32Number BeginOfThisString, EndOfThisString, LargestPosition; *nItems = 0; @@ -1438,12 +1476,17 @@ void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU // Now deal with Len and offset. if (!_cmsReadUInt32Number(io, &Len)) goto Error; - mlu ->Entries[i].Len = Len; - if (!_cmsReadUInt32Number(io, &Offset)) goto Error; + // Check for overflow + if (Offset < (SizeOfHeader + 8)) goto Error; + + // True begin of the string BeginOfThisString = Offset - SizeOfHeader - 8; - mlu ->Entries[i].StrW = BeginOfThisString; + + // Ajust 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; @@ -1452,15 +1495,22 @@ void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU } // Now read the remaining of tag and fill all strings. Substract the directory - SizeOfTag = LargestPosition; + SizeOfTag = (LargestPosition * sizeof(wchar_t)) / sizeof(cmsUInt16Number); + if (SizeOfTag == 0) + { + Block = NULL; + NumOfWchar = 0; - Block = (cmsUInt16Number*) _cmsMalloc(self ->ContextID, SizeOfTag); - if (Block == NULL) goto Error; + } + 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; + } - NumOfWchar = SizeOfTag / sizeof(cmsUInt16Number); - - if (!_cmsReadUInt16Array(io, NumOfWchar, Block)) goto Error; - mlu ->MemPool = Block; + mlu ->MemPool = Block; mlu ->PoolSize = SizeOfTag; mlu ->PoolUsed = SizeOfTag; @@ -1476,9 +1526,18 @@ static cmsBool Type_MLU_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) { cmsMLU* mlu =(cmsMLU*) Ptr; - cmsUInt32Number HeaderSize, Offset; + cmsUInt32Number HeaderSize; + cmsUInt32Number Len, Offset; int 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; @@ -1486,16 +1545,19 @@ cmsBool Type_MLU_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, 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, mlu ->Entries[i].Len)) return FALSE; - - Offset = mlu ->Entries[i].StrW + HeaderSize + 8; - + if (!_cmsWriteUInt32Number(io, Len)) return FALSE; if (!_cmsWriteUInt32Number(io, Offset)) return FALSE; } - if (!_cmsWriteUInt16Array(io, mlu ->PoolUsed / sizeof(cmsUInt16Number), (cmsUInt16Number*) mlu ->MemPool)) return FALSE; + if (!_cmsWriteWCharArray(io, mlu ->PoolUsed / sizeof(wchar_t), (wchar_t*) mlu ->MemPool)) return FALSE; return TRUE; @@ -1584,6 +1646,7 @@ cmsBool Read8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut cmsToneCurve* Tables[cmsMAXCHANNELS]; if (nChannels > cmsMAXCHANNELS) return FALSE; + if (nChannels <= 0) return FALSE; memset(Tables, 0, sizeof(Tables)); @@ -1604,6 +1667,7 @@ cmsBool Read8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut } _cmsFree(ContextID, Temp); + Temp = NULL; mpe = cmsStageAllocToneCurves(ContextID, nChannels, Tables); @@ -1658,12 +1722,28 @@ cmsBool Write8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsUInt32Number } +// Check overflow static -unsigned int uipow(cmsUInt32Number a, cmsUInt32Number b) { - cmsUInt32Number rv = 1; - for (; b > 0; b--) +size_t 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; - return rv; + + // Check for overflow + if (rv > UINT_MAX / a) return (size_t) -1; + + } + + rc = rv * n; + + if (rv != rc / n) return (size_t) -1; + return rc; } @@ -1687,6 +1767,8 @@ void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms 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; @@ -1722,8 +1804,9 @@ void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms // Get input tables if (!Read8bitTables(self ->ContextID, io, NewLUT, InputChannels)) goto Error; - // Get 3D CLUT - nTabSize = (OutputChannels * uipow(CLUTpoints, InputChannels)); + // Get 3D CLUT. Check the overflow.... + nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels); + if (nTabSize == (size_t) -1) goto Error; if (nTabSize > 0) { cmsUInt16Number *PtrW, *T; @@ -1850,15 +1933,18 @@ cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, // The prelinearization table if (!Write8bitTables(self ->ContextID, io, NewLUT ->InputChannels, PreMPE)) return FALSE; - nTabSize = (NewLUT->OutputChannels * uipow(clutPoints, NewLUT ->InputChannels)); + nTabSize = uipow(NewLUT->OutputChannels, clutPoints, NewLUT ->InputChannels); + if (nTabSize == (size_t) -1) return FALSE; + if (nTabSize > 0) { - // The 3D CLUT. - if (clut != NULL) { + // The 3D CLUT. + if (clut != NULL) { - for (j=0; j < nTabSize; j++) { + for (j=0; j < nTabSize; j++) { - val = (cmsUInt8Number) FROM_16_TO_8(clut ->Tab.T[j]); - if (!_cmsWriteUInt8Number(io, val)) return FALSE; + val = (cmsUInt8Number) FROM_16_TO_8(clut ->Tab.T[j]); + if (!_cmsWriteUInt8Number(io, val)) return FALSE; + } } } @@ -1905,6 +1991,7 @@ cmsBool Read16bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lu if (nEntries <= 0) return TRUE; // Check for malicious profiles + if (nEntries < 2) return FALSE; if (nChannels > cmsMAXCHANNELS) return FALSE; // Init table to zero @@ -1979,13 +2066,12 @@ void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm if (!_cmsReadUInt8Number(io, &InputChannels)) return NULL; if (!_cmsReadUInt8Number(io, &OutputChannels)) return NULL; - if (!_cmsReadUInt8Number(io, &CLUTpoints)) return NULL; + if (!_cmsReadUInt8Number(io, &CLUTpoints)) return NULL; // 255 maximum // Padding if (!_cmsReadUInt8Number(io, NULL)) return NULL; // Do some checking - if (CLUTpoints > 100) goto Error; if (InputChannels > cmsMAXCHANNELS) goto Error; if (OutputChannels > cmsMAXCHANNELS) goto Error; @@ -2006,7 +2092,6 @@ void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm // Only operates on 3 channels - if ((InputChannels == 3) && !_cmsMAT3isIdentity((cmsMAT3*) Matrix)) { mpemat = cmsStageAllocMatrix(self ->ContextID, 3, 3, Matrix, NULL); @@ -2014,15 +2099,18 @@ void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm cmsPipelineInsertStage(NewLUT, cmsAT_END, mpemat); } - if (!_cmsReadUInt16Number(io, &InputEntries)) return NULL; - if (!_cmsReadUInt16Number(io, &OutputEntries)) return NULL; + 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 = (OutputChannels * uipow(CLUTpoints, InputChannels)); + nTabSize = uipow(OutputChannels, CLUTpoints, InputChannels); + if (nTabSize == (size_t) -1) goto Error; if (nTabSize > 0) { cmsUInt16Number *T; @@ -2030,10 +2118,17 @@ void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm T = (cmsUInt16Number*) _cmsCalloc(self ->ContextID, nTabSize, sizeof(cmsUInt16Number)); if (T == NULL) goto Error; - if (!_cmsReadUInt16Array(io, nTabSize, T)) goto Error; + if (!_cmsReadUInt16Array(io, nTabSize, T)) { + _cmsFree(self ->ContextID, T); + goto Error; + } mpeclut = cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T); - if (mpeclut == NULL) goto Error; + if (mpeclut == NULL) { + _cmsFree(self ->ContextID, T); + goto Error; + } + cmsPipelineInsertStage(NewLUT, cmsAT_END, mpeclut); _cmsFree(self ->ContextID, T); } @@ -2155,11 +2250,13 @@ cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io if (!Write16bitTables(self ->ContextID, io, PreMPE)) return FALSE; } - nTabSize = (OutputChannels * uipow(clutPoints, InputChannels)); - - // The 3D CLUT. - if (clut != NULL) { - if (!_cmsWriteUInt16Array(io, nTabSize, clut->Tab.T)) return FALSE; + nTabSize = uipow(OutputChannels, clutPoints, InputChannels); + if (nTabSize == (size_t) -1) return FALSE; + if (nTabSize > 0) { + // The 3D CLUT. + if (clut != NULL) { + if (!_cmsWriteUInt16Array(io, nTabSize, clut->Tab.T)) return FALSE; + } } // The postlinearization table @@ -2246,8 +2343,12 @@ cmsStage* ReadCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUI if (!io -> Seek(io, Offset)) return NULL; if (io -> Read(io, gridPoints8, cmsMAXCHANNELS, 1) != 1) return NULL; - for (i=0; i < cmsMAXCHANNELS; i++) + + 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; @@ -2256,6 +2357,8 @@ cmsStage* ReadCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUI 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 @@ -2276,7 +2379,7 @@ cmsStage* ReadCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUI if (!_cmsReadUInt16Array(io, Data->nEntries, Data ->Tab.T)) return NULL; } else { - cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknow precision of '%d'", Precision); + cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision); return NULL; } @@ -2304,7 +2407,7 @@ cmsToneCurve* ReadEmbeddedCurve(struct _cms_typehandler_struct* self, cmsIOHANDL char String[5]; _cmsTagSignature2String(String, (cmsTagSignature) BaseType); - cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknow curve type '%s'", String); + cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve type '%s'", String); } return NULL; } @@ -2313,26 +2416,30 @@ cmsToneCurve* ReadEmbeddedCurve(struct _cms_typehandler_struct* self, cmsIOHANDL // Read a set of curves from specific offset static -cmsStage* ReadSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset, int nCurves) +cmsStage* ReadSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset, cmsUInt32Number nCurves) { cmsToneCurve* Curves[cmsMAXCHANNELS]; - int i; - cmsStage* Lin; - + 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) return FALSE; - if (!_cmsReadAlignment(io)) return FALSE; + 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]); @@ -2395,26 +2502,31 @@ void* Type_LUTA2B_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, c if (offsetA!= 0) { mpe = ReadSetOfCurves(self, io, BaseOffset + offsetA, inputChan); + if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; } cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); } if (offsetC != 0) { mpe = ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan); + if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; } cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); } if (offsetM != 0) { mpe = ReadSetOfCurves(self, io, BaseOffset + offsetM, outputChan); + if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; } cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); } if (offsetMat != 0) { mpe = ReadMatrix(self, io, BaseOffset + offsetMat); + if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; } cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); } if (offsetB != 0) { mpe = ReadSetOfCurves(self, io, BaseOffset + offsetB, outputChan); + if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; } cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); } @@ -2441,9 +2553,19 @@ cmsBool WriteMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms if (!_cmsWrite15Fixed16Number(io, m -> Double[7])) return FALSE; if (!_cmsWrite15Fixed16Number(io, m -> Double[8])) return FALSE; + if (m ->Offset != NULL) { + if (!_cmsWrite15Fixed16Number(io, m -> Offset[0])) return FALSE; if (!_cmsWrite15Fixed16Number(io, m -> Offset[1])) return FALSE; if (!_cmsWrite15Fixed16Number(io, m -> Offset[2])) return FALSE; + } + else { + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; + + } + return TRUE; @@ -2468,7 +2590,8 @@ cmsBool WriteSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, // If this is a table-based curve, use curve type even on V4 CurrentType = Type; - if (Curves[i] ->nSegments == 0) + 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) @@ -2491,7 +2614,7 @@ cmsBool WriteSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, char String[5]; _cmsTagSignature2String(String, (cmsTagSignature) Type); - cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknow curve type '%s'", String); + cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve type '%s'", String); } return FALSE; } @@ -2511,6 +2634,11 @@ cmsBool WriteCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUIn 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]; @@ -2536,7 +2664,7 @@ cmsBool WriteCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUIn if (!_cmsWriteUInt16Array(io, CLUT->nEntries, CLUT ->Tab.T)) return FALSE; } else { - cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknow precision of '%d'", Precision); + cmsSignalError(self ->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown precision of '%d'", Precision); return FALSE; } @@ -2694,26 +2822,31 @@ void* Type_LUTB2A_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, c if (offsetB != 0) { mpe = ReadSetOfCurves(self, io, BaseOffset + offsetB, inputChan); + if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; } cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); } if (offsetMat != 0) { mpe = ReadMatrix(self, io, BaseOffset + offsetMat); + if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; } cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); } if (offsetM != 0) { mpe = ReadSetOfCurves(self, io, BaseOffset + offsetM, inputChan); + if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; } cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); } if (offsetC != 0) { mpe = ReadCLUT(self, io, BaseOffset + offsetC, inputChan, outputChan); + if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; } cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); } if (offsetA!= 0) { mpe = ReadSetOfCurves(self, io, BaseOffset + offsetA, outputChan); + if (mpe == NULL) { cmsPipelineFree(NewLUT); return NULL; } cmsPipelineInsertStage(NewLUT, cmsAT_END, mpe); } @@ -2978,7 +3111,10 @@ void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* i prefix[31] = suffix[31] = 0; v = cmsAllocNamedColorList(self ->ContextID, count, nDeviceCoords, prefix, suffix); - if (v == NULL) return NULL; + 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); @@ -3076,6 +3212,13 @@ void Type_NamedColor_Free(struct _cms_typehandler_struct* self, void* Ptr) // 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) { @@ -3119,6 +3262,8 @@ void *Type_ProfileSequenceDesc_Read(struct _cms_typehandler_struct* self, cmsIOH *nItems = 0; if (!_cmsReadUInt32Number(io, &Count)) return NULL; + + if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; SizeOfTag -= sizeof(cmsUInt32Number); @@ -3133,40 +3278,42 @@ void *Type_ProfileSequenceDesc_Read(struct _cms_typehandler_struct* self, cmsIOH cmsPSEQDESC* sec = &OutSeq -> seq[i]; - if (!_cmsReadUInt32Number(io, &sec ->deviceMfg)) return NULL; + if (!_cmsReadUInt32Number(io, &sec ->deviceMfg)) goto Error; + if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error; SizeOfTag -= sizeof(cmsUInt32Number); - if (!_cmsReadUInt32Number(io, &sec ->deviceModel)) return NULL; + if (!_cmsReadUInt32Number(io, &sec ->deviceModel)) goto Error; + if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error; SizeOfTag -= sizeof(cmsUInt32Number); - if (!_cmsReadUInt64Number(io, &sec ->attributes)) return NULL; + if (!_cmsReadUInt64Number(io, &sec ->attributes)) goto Error; + if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error; SizeOfTag -= sizeof(cmsUInt64Number); - if (!_cmsReadUInt32Number(io, (cmsUInt32Number *)&sec ->technology)) return NULL; + if (!_cmsReadUInt32Number(io, (cmsUInt32Number *)&sec ->technology)) goto Error; + if (SizeOfTag < sizeof(cmsUInt32Number)) goto Error; SizeOfTag -= sizeof(cmsUInt32Number); - if (!ReadEmbeddedText(self, io, &sec ->Manufacturer, SizeOfTag)) return NULL; - if (!ReadEmbeddedText(self, io, &sec ->Model, SizeOfTag)) return NULL; + 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 (Text == NULL) { + if (self ->ICCVersion < 0x4000000) { - // Placeholder for a null entry - if (!_cmsWriteTypeBase(io, cmsSigTextDescriptionType)) return FALSE; - return Type_Text_Description_Write(self, io, NULL, 1); - - } - - if (Text->UsedEntries <= 1) { if (!_cmsWriteTypeBase(io, cmsSigTextDescriptionType)) return FALSE; return Type_Text_Description_Write(self, io, Text, 1); } @@ -3191,7 +3338,7 @@ cmsBool Type_ProfileSequenceDesc_Write(struct _cms_typehandler_struct* self, cm if (!_cmsWriteUInt32Number(io, sec ->deviceMfg)) return FALSE; if (!_cmsWriteUInt32Number(io, sec ->deviceModel)) return FALSE; - if (!_cmsWriteUInt64Number(io, sec ->attributes)) return FALSE; + if (!_cmsWriteUInt64Number(io, &sec ->attributes)) return FALSE; if (!_cmsWriteUInt32Number(io, sec ->technology)) return FALSE; if (!SaveDescription(self, io, sec ->Manufacturer)) return FALSE; @@ -3366,26 +3513,33 @@ void *Type_UcrBg_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm // 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); - ASCIIString = (char*) _cmsMalloc(self ->ContextID, sizeof(cmsUInt8Number)*(SizeOfTag + 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); @@ -3482,7 +3636,9 @@ cmsBool ReadCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* i 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; @@ -3600,6 +3756,9 @@ void *Type_Screening_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io 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; @@ -3778,6 +3937,7 @@ cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHAND 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; @@ -4137,7 +4297,7 @@ void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, // Copy MAX_INPUT_DIMENSIONS at most. Expand to cmsUInt32Number nMaxGrids = InputChans > MAX_INPUT_DIMENSIONS ? MAX_INPUT_DIMENSIONS : InputChans; - for (i=0; i < nMaxGrids; i++) GridPoints[i] = Dimensions8[i]; + for (i=0; i < nMaxGrids; i++) GridPoints[i] = (cmsUInt32Number) Dimensions8[i]; // Allocate the true CLUT mpe = cmsStageAllocCLutFloatGranular(self ->ContextID, GridPoints, InputChans, OutputChans, NULL); @@ -4202,8 +4362,8 @@ cmsBool Type_MPEclut_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* // This is the list of built-in MPE types static _cmsTagTypeLinkedList SupportedMPEtypes[] = { -{{ (cmsTagTypeSignature) cmsSigBAcsElemType, NULL, NULL, NULL, NULL }, &SupportedMPEtypes[1] }, // Ignore those elements for now -{{ (cmsTagTypeSignature) cmsSigEAcsElemType, NULL, NULL, NULL, NULL }, &SupportedMPEtypes[2] }, // (That's what the spec says) +{{ (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] }, @@ -4466,6 +4626,11 @@ void *Type_vcgt_Read(struct _cms_typehandler_struct* self, 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++) { @@ -4571,21 +4736,21 @@ cmsBool Type_vcgt_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsGetToneCurveParametricType(Curves[1]) == 5 && cmsGetToneCurveParametricType(Curves[2]) == 5) { - if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaFormulaType)) return FALSE; + if (!_cmsWriteUInt32Number(io, cmsVideoCardGammaFormulaType)) return FALSE; - // Save parameters - for (i=0; i < 3; i++) { + // Save parameters + for (i=0; i < 3; i++) { - _cmsVCGTGAMMA v; + _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; + 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; - } + if (!_cmsWrite15Fixed16Number(io, v.Gamma)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, v.Min)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, v.Max)) return FALSE; + } } else { @@ -4639,6 +4804,435 @@ void Type_vcgt_Free(struct _cms_typehandler_struct* self, void* 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 lenghth + 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; + } + + 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) return FALSE; + } + + 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 // ******************************************************************************** @@ -4676,6 +5270,7 @@ static _cmsTagTypeLinkedList SupportedTagTypes[] = { {TYPE_HANDLER(cmsCorbisBrokenXYZtype, XYZ), &SupportedTagTypes[27] }, {TYPE_HANDLER(cmsMonacoBrokenCurveType, Curve), &SupportedTagTypes[28] }, {TYPE_HANDLER(cmsSigProfileSequenceIdType, ProfileSequenceId), &SupportedTagTypes[29] }, +{TYPE_HANDLER(cmsSigDictType, Dictionary), &SupportedTagTypes[30] }, {TYPE_HANDLER(cmsSigVcgtType, vcgt), NULL } }; @@ -4795,6 +5390,7 @@ static _cmsTagLinkedList SupportedTags[] = { { 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}, NULL} }; diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c index b643e98df4f..ff46a0b3b69 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2011 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"), @@ -143,7 +143,7 @@ cmsHPROFILE CMSEXPORT cmsCreateRGBProfileTHR(cmsContext ContextID, if (!hICC) // can't allocate return NULL; - cmsSetProfileVersion(hICC, 4.2); + cmsSetProfileVersion(hICC, 4.3); cmsSetDeviceClass(hICC, cmsSigDisplayClass); cmsSetColorSpace(hICC, cmsSigRgbData); @@ -247,7 +247,7 @@ cmsHPROFILE CMSEXPORT cmsCreateGrayProfileTHR(cmsContext ContextID, if (!hICC) // can't allocate return NULL; - cmsSetProfileVersion(hICC, 4.2); + cmsSetProfileVersion(hICC, 4.3); cmsSetDeviceClass(hICC, cmsSigDisplayClass); cmsSetColorSpace(hICC, cmsSigGrayData); @@ -310,7 +310,7 @@ cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR(cmsContext ContextID, if (!hICC) return NULL; - cmsSetProfileVersion(hICC, 4.2); + cmsSetProfileVersion(hICC, 4.3); cmsSetDeviceClass(hICC, cmsSigLinkClass); cmsSetColorSpace(hICC, ColorSpace); @@ -430,7 +430,7 @@ cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID, if (!hICC) // can't allocate return NULL; - cmsSetProfileVersion(hICC, 4.2); + cmsSetProfileVersion(hICC, 4.3); cmsSetDeviceClass(hICC, cmsSigLinkClass); cmsSetColorSpace(hICC, ColorSpace); @@ -538,7 +538,7 @@ cmsHPROFILE CMSEXPORT cmsCreateLab4ProfileTHR(cmsContext ContextID, const cmsCIE hProfile = cmsCreateRGBProfileTHR(ContextID, WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL); if (hProfile == NULL) return NULL; - cmsSetProfileVersion(hProfile, 4.2); + cmsSetProfileVersion(hProfile, 4.3); cmsSetDeviceClass(hProfile, cmsSigAbstractClass); cmsSetColorSpace(hProfile, cmsSigLabData); @@ -583,7 +583,7 @@ cmsHPROFILE CMSEXPORT cmsCreateXYZProfileTHR(cmsContext ContextID) hProfile = cmsCreateRGBProfileTHR(ContextID, cmsD50_xyY(), NULL, NULL); if (hProfile == NULL) return NULL; - cmsSetProfileVersion(hProfile, 4.2); + cmsSetProfileVersion(hProfile, 4.3); cmsSetDeviceClass(hProfile, cmsSigAbstractClass); cmsSetColorSpace(hProfile, cmsSigXYZData); @@ -838,7 +838,7 @@ cmsHPROFILE CMSEXPORT cmsCreateNULLProfileTHR(cmsContext ContextID) if (!hProfile) // can't allocate return NULL; - cmsSetProfileVersion(hProfile, 4.2); + cmsSetProfileVersion(hProfile, 4.3); if (!SetTextTags(hProfile, L"NULL profile built-in")) goto Error; @@ -963,6 +963,11 @@ cmsHPROFILE CreateNamedColorDevicelink(cmsHTRANSFORM xform) // 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); @@ -983,6 +988,7 @@ Error: 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 @@ -991,16 +997,16 @@ typedef struct { static const cmsAllowedLUT AllowedLUTTypes[] = { - { FALSE, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, - { FALSE, cmsSigLut16Type, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, - { TRUE , cmsSigLutAtoBType, 1, { cmsSigCurveSetElemType } }, - { TRUE , cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType } }, - { TRUE , cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType } }, - { TRUE , cmsSigLutAtoBType, 5, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType }}, - { TRUE , cmsSigLutBtoAType, 1, { cmsSigCurveSetElemType }}, - { TRUE , cmsSigLutBtoAType, 3, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType }}, - { TRUE , cmsSigLutBtoAType, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType }}, - { TRUE , cmsSigLutBtoAType, 5, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType }} + { FALSE, 0, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, + { FALSE, 0, cmsSigLut16Type, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType}}, + { TRUE , 0, 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)) @@ -1023,15 +1029,17 @@ cmsBool CheckOne(const cmsAllowedLUT* Tab, const cmsPipeline* Lut) static -const cmsAllowedLUT* FindCombination(const cmsPipeline* Lut, cmsBool IsV4) +const cmsAllowedLUT* FindCombination(const cmsPipeline* Lut, cmsBool IsV4, cmsTagSignature DestinationTag) { - int n; + 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; } @@ -1050,6 +1058,7 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat cmsStage* mpe; cmsContext ContextID = cmsGetTransformContextID(hTransform); const cmsAllowedLUT* AllowedLUT; + cmsTagSignature DestinationTag; _cmsAssert(hTransform != NULL); @@ -1080,6 +1089,14 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocLabV4ToV2(ContextID)); } + + 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); @@ -1092,17 +1109,22 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat FrmOut = COLORSPACE_SH(ColorSpaceBitsOut) | CHANNELS_SH(ChansOut)|BYTES_SH(2); + if (cmsGetDeviceClass(hProfile) == 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); + AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag); if (AllowedLUT == NULL) { // Try to optimize _cmsOptimizePipeline(&LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); - AllowedLUT = FindCombination(LUT, Version >= 4.0); + AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag); } @@ -1113,13 +1135,13 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat _cmsOptimizePipeline(&LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags); // Put identity curves if needed - if (cmsPipelineStageCount(LUT) == 1) { + if (cmsPipelineGetPtrToFirstStage(LUT) ->Type != cmsSigCurveSetElemType) + cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, ChansIn)); - cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, ChansIn)); - cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, ChansOut)); - } + if (cmsPipelineGetPtrToLastStage(LUT) ->Type != cmsSigCurveSetElemType) + cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, ChansOut)); - AllowedLUT = FindCombination(LUT, Version >= 4.0); + AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag); } // Somethings is wrong... @@ -1127,25 +1149,15 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat goto Error; } - hProfile = cmsCreateProfilePlaceholder(ContextID); - if (!hProfile) goto Error; // can't allocate - - cmsSetProfileVersion(hProfile, Version); - - FixColorSpaces(hProfile, xform -> EntryColorSpace, xform -> ExitColorSpace, dwFlags); if (dwFlags & cmsFLAGS_8BITS_DEVICELINK) cmsPipelineSetSaveAs8bitsFlag(LUT, TRUE); // Tag profile with information - if (!SetTextTags(hProfile, L"devicelink")) return NULL; + if (!SetTextTags(hProfile, L"devicelink")) goto Error; - if (cmsGetDeviceClass(hProfile) == cmsSigOutputClass) { - - if (!cmsWriteTag(hProfile, cmsSigBToA0Tag, LUT)) goto Error; - } - else - if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error; + // Store result + if (!cmsWriteTag(hProfile, DestinationTag, LUT)) goto Error; if (xform -> InputColorant != NULL) { diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c index 1a38abbad9c..2a626c66b74 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c @@ -172,7 +172,7 @@ static ISOTEMPERATURE isotempdata[] = { // Robertson's method cmsBool CMSEXPORT cmsTempFromWhitePoint(cmsFloat64Number* TempK, const cmsCIExyY* WhitePoint) { - int j; + cmsUInt32Number j; cmsFloat64Number us,vs; cmsFloat64Number uj,vj,tj,di,dj,mi,mj; cmsFloat64Number xs, ys; @@ -263,10 +263,10 @@ cmsBool ComputeChromaticAdaptation(cmsMAT3* Conversion, 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 }} - }}; + {{ 0.8951, 0.2664, -0.1614 }}, + {{ -0.7502, 1.7135, 0.0367 }}, + {{ 0.0389, -0.0685, 1.0296 }} + }}; if (ConeMatrix == NULL) ConeMatrix = &LamRigg; @@ -376,3 +376,5 @@ cmsBool CMSEXPORT cmsAdaptToIlluminant(cmsCIEXYZ* Result, return TRUE; } + + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c index 311eeb4fcba..925a70374d3 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2011 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"), @@ -60,8 +60,8 @@ // Alarm codes for 16-bit transformations, because the fixed range of containers there are // no values left to mark out of gamut. volatile is C99 per 6.2.5 -static volatile cmsUInt16Number Alarm[cmsMAXCHANNELS]; -static volatile cmsFloat64Number GlobalAdaptationState = 0; +static volatile cmsUInt16Number Alarm[cmsMAXCHANNELS] = { 0x7F00, 0x7F00, 0x7F00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static volatile cmsFloat64Number GlobalAdaptationState = 1; // 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) @@ -118,11 +118,13 @@ void CMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform) if (p ->Sequence) cmsFreeProfileSequenceDescription(p ->Sequence); - LCMS_FREE_LOCK(&p->rwlock); + if (p ->UserData) + p ->FreeUserData(p ->ContextID, p ->UserData); + _cmsFree(p ->ContextID, (void *) p); } -// Apply transform +// Apply transform. void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform, const void* InputBuffer, void* OutputBuffer, @@ -131,7 +133,20 @@ void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform, { _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform; - p -> xform(p, InputBuffer, OutputBuffer, Size); + p -> xform(p, InputBuffer, OutputBuffer, Size, Size); +} + + +// Apply transform. +void CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM Transform, + const void* InputBuffer, + void* OutputBuffer, + cmsUInt32Number Size, cmsUInt32Number Stride) + +{ + _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform; + + p -> xform(p, InputBuffer, OutputBuffer, Size, Stride); } @@ -142,7 +157,7 @@ void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform, static void FloatXFORM(_cmsTRANSFORM* p, const void* in, - void* out, cmsUInt32Number Size) + void* out, cmsUInt32Number Size, cmsUInt32Number Stride) { cmsUInt8Number* accum; cmsUInt8Number* output; @@ -155,7 +170,7 @@ void FloatXFORM(_cmsTRANSFORM* p, for (i=0; i < Size; i++) { - accum = p -> FromInputFloat(p, fIn, accum, Size); + accum = p -> FromInputFloat(p, fIn, accum, Stride); // Any gamut chack to do? if (p ->GamutCheck != NULL) { @@ -183,7 +198,7 @@ void FloatXFORM(_cmsTRANSFORM* p, } // Back to asked representation - output = p -> ToOutputFloat(p, fOut, output, Size); + output = p -> ToOutputFloat(p, fOut, output, Stride); } } @@ -193,7 +208,8 @@ void FloatXFORM(_cmsTRANSFORM* p, static void NullXFORM(_cmsTRANSFORM* p, const void* in, - void* out, cmsUInt32Number Size) + void* out, cmsUInt32Number Size, + cmsUInt32Number Stride) { cmsUInt8Number* accum; cmsUInt8Number* output; @@ -206,8 +222,8 @@ void NullXFORM(_cmsTRANSFORM* p, for (i=0; i < n; i++) { - accum = p -> FromInput(p, wIn, accum, Size); - output = p -> ToOutput(p, wIn, output, Size); + accum = p -> FromInput(p, wIn, accum, Stride); + output = p -> ToOutput(p, wIn, output, Stride); } } @@ -216,7 +232,7 @@ void NullXFORM(_cmsTRANSFORM* p, static void PrecalculatedXFORM(_cmsTRANSFORM* p, const void* in, - void* out, cmsUInt32Number Size) + void* out, cmsUInt32Number Size, cmsUInt32Number Stride) { register cmsUInt8Number* accum; register cmsUInt8Number* output; @@ -229,9 +245,9 @@ void PrecalculatedXFORM(_cmsTRANSFORM* p, for (i=0; i < n; i++) { - accum = p -> FromInput(p, wIn, accum, Size); + accum = p -> FromInput(p, wIn, accum, Stride); p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data); - output = p -> ToOutput(p, wOut, output, Size); + output = p -> ToOutput(p, wOut, output, Stride); } } @@ -260,7 +276,7 @@ void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p, static void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p, const void* in, - void* out, cmsUInt32Number Size) + void* out, cmsUInt32Number Size, cmsUInt32Number Stride) { cmsUInt8Number* accum; cmsUInt8Number* output; @@ -273,9 +289,9 @@ void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p, for (i=0; i < n; i++) { - accum = p -> FromInput(p, wIn, accum, Size); + accum = p -> FromInput(p, wIn, accum, Stride); TransformOnePixelWithGamutCheck(p, wIn, wOut); - output = p -> ToOutput(p, wOut, output, Size); + output = p -> ToOutput(p, wOut, output, Stride); } } @@ -284,13 +300,13 @@ void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p, static void CachedXFORM(_cmsTRANSFORM* p, const void* in, - void* out, cmsUInt32Number Size) + void* out, cmsUInt32Number Size, cmsUInt32Number Stride) { cmsUInt8Number* accum; cmsUInt8Number* output; cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS]; cmsUInt32Number i, n; - cmsUInt16Number CacheIn[cmsMAXCHANNELS], CacheOut[cmsMAXCHANNELS]; + _cmsCACHE Cache; accum = (cmsUInt8Number*) in; output = (cmsUInt8Number*) out; @@ -300,36 +316,28 @@ void CachedXFORM(_cmsTRANSFORM* p, memset(wIn, 0, sizeof(wIn)); memset(wOut, 0, sizeof(wOut)); - - LCMS_READ_LOCK(&p ->rwlock); - memmove(CacheIn, p ->CacheIn, sizeof(CacheIn)); - memmove(CacheOut, p ->CacheOut, sizeof(CacheOut)); - LCMS_UNLOCK(&p ->rwlock); + // Get copy of zero cache + memcpy(&Cache, &p ->Cache, sizeof(Cache)); for (i=0; i < n; i++) { - accum = p -> FromInput(p, wIn, accum, Size); + accum = p -> FromInput(p, wIn, accum, Stride); - if (memcmp(wIn, CacheIn, sizeof(CacheIn)) == 0) { + if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) { - memmove(wOut, CacheOut, sizeof(CacheOut)); + memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut)); } else { p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data); - memmove(CacheIn, wIn, sizeof(CacheIn)); - memmove(CacheOut, wOut, sizeof(CacheOut)); + memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn)); + memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut)); } - output = p -> ToOutput(p, wOut, output, Size); + output = p -> ToOutput(p, wOut, output, Stride); } - - LCMS_WRITE_LOCK(&p ->rwlock); - memmove(p->CacheIn, CacheIn, sizeof(CacheIn)); - memmove(p->CacheOut, CacheOut, sizeof(CacheOut)); - LCMS_UNLOCK(&p ->rwlock); } @@ -337,13 +345,13 @@ void CachedXFORM(_cmsTRANSFORM* p, static void CachedXFORMGamutCheck(_cmsTRANSFORM* p, const void* in, - void* out, cmsUInt32Number Size) + void* out, cmsUInt32Number Size, cmsUInt32Number Stride) { cmsUInt8Number* accum; cmsUInt8Number* output; cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS]; cmsUInt32Number i, n; - cmsUInt16Number CacheIn[cmsMAXCHANNELS], CacheOut[cmsMAXCHANNELS]; + _cmsCACHE Cache; accum = (cmsUInt8Number*) in; output = (cmsUInt8Number*) out; @@ -353,51 +361,158 @@ void CachedXFORMGamutCheck(_cmsTRANSFORM* p, memset(wIn, 0, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); memset(wOut, 0, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); - LCMS_READ_LOCK(&p ->rwlock); - memmove(CacheIn, p ->CacheIn, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); - memmove(CacheOut, p ->CacheOut, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); - LCMS_UNLOCK(&p ->rwlock); - + // Get copy of zero cache + memcpy(&Cache, &p ->Cache, sizeof(Cache)); for (i=0; i < n; i++) { - accum = p -> FromInput(p, wIn, accum, Size); + accum = p -> FromInput(p, wIn, accum, Stride); - if (memcmp(wIn, CacheIn, sizeof(cmsUInt16Number) * cmsMAXCHANNELS) == 0) { - memmove(wOut, CacheOut, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); + if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) { + memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut)); } else { TransformOnePixelWithGamutCheck(p, wIn, wOut); - memmove(CacheIn, wIn, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); - memmove(CacheOut, wOut, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); + memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn)); + memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut)); } - output = p -> ToOutput(p, wOut, output, Size); + output = p -> ToOutput(p, wOut, output, Stride); } - LCMS_WRITE_LOCK(&p ->rwlock); - memmove(p->CacheIn, CacheIn, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); - memmove(p->CacheOut, CacheOut, sizeof(cmsUInt16Number) * cmsMAXCHANNELS); - LCMS_UNLOCK(&p ->rwlock); +} + +// ------------------------------------------------------------------------------------------------------------- + +// List of used-defined transform factories +typedef struct _cmsTransformCollection_st { + + _cmsTransformFactory Factory; + struct _cmsTransformCollection_st *Next; + +} _cmsTransformCollection; + +// The linked list head +static _cmsTransformCollection* TransformCollection = NULL; + +// Register new ways to transform +cmsBool _cmsRegisterTransformPlugin(cmsPluginBase* Data) +{ + cmsPluginTransform* Plugin = (cmsPluginTransform*) Data; + _cmsTransformCollection* fl; + + if (Data == NULL) { + + // Free the chain. Memory is safely freed at exit + TransformCollection = NULL; + return TRUE; + } + + // Factory callback is required + if (Plugin ->Factory == NULL) return FALSE; + + + fl = (_cmsTransformCollection*) _cmsPluginMalloc(sizeof(_cmsTransformCollection)); + if (fl == NULL) return FALSE; + + // Copy the parameters + fl ->Factory = Plugin ->Factory; + + // Keep linked list + fl ->Next = TransformCollection; + TransformCollection = fl; + + // All is ok + return TRUE; } - - -// Allocate transform struct and set it to defaults -static -_cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsUInt32Number InputFormat, cmsUInt32Number OutputFormat, cmsUInt32Number dwFlags) +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; +} + + +// 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) +{ + _cmsTransformCollection* Plugin; + // Allocate needed memory _cmsTRANSFORM* p = (_cmsTRANSFORM*) _cmsMallocZero(ContextID, sizeof(_cmsTRANSFORM)); if (!p) return NULL; + // Store the proposed pipeline + p ->Lut = lut; + + // Let's see if any plug-in want to do the transform by itself + for (Plugin = 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(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; + p ->ToOutput = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; + p ->FromInputFloat = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + p ->ToOutputFloat = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + + return p; + } + } + + // Not suitable for the transform plug-in, let's check the pipeline plug-in + if (p ->Lut != NULL) + _cmsOptimizePipeline(&p->Lut, Intent, InputFormat, OutputFormat, dwFlags); + // Check whatever this is a true floating point transform - if (_cmsFormatterIsFloat(InputFormat) && _cmsFormatterIsFloat(OutputFormat)) { + 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(InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; - p ->ToOutputFloat = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + p ->FromInputFloat = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + p ->ToOutputFloat = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat; + *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER; if (p ->FromInputFloat == NULL || p ->ToOutputFloat == NULL) { @@ -411,31 +526,45 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsUInt32Number InputFo } else { - p ->FromInput = _cmsGetFormatter(InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; - p ->ToOutput = _cmsGetFormatter(OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; + if (*InputFormat == 0 && *OutputFormat == 0) { + p ->FromInput = p ->ToOutput = NULL; + *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER; + } + else { - if (p ->FromInput == NULL || p ->ToOutput == NULL) { + int BytesPerPixelInput; + + p ->FromInput = _cmsGetFormatter(*InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; + p ->ToOutput = _cmsGetFormatter(*OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16; + + if (p ->FromInput == NULL || p ->ToOutput == NULL) { + + cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format"); + _cmsFree(ContextID, p); + return NULL; + } + + BytesPerPixelInput = T_BYTES(p ->InputFormat); + if (BytesPerPixelInput == 0 || BytesPerPixelInput >= 2) + *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER; - cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format"); - _cmsFree(ContextID, p); - return NULL; } - if (dwFlags & cmsFLAGS_NULLTRANSFORM) { + if (*dwFlags & cmsFLAGS_NULLTRANSFORM) { p ->xform = NullXFORM; } else { - if (dwFlags & cmsFLAGS_NOCACHE) { + if (*dwFlags & cmsFLAGS_NOCACHE) { - if (dwFlags & cmsFLAGS_GAMUTCHECK) + if (*dwFlags & cmsFLAGS_GAMUTCHECK) p ->xform = PrecalculatedXFORMGamutCheck; // Gamut check, no caché else p ->xform = PrecalculatedXFORM; // No caché, no gamut check } else { - if (dwFlags & cmsFLAGS_GAMUTCHECK) + if (*dwFlags & cmsFLAGS_GAMUTCHECK) p ->xform = CachedXFORMGamutCheck; // Gamut check, caché else p ->xform = CachedXFORM; // No gamut check, caché @@ -444,14 +573,11 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsUInt32Number InputFo } } - - // Create a mutex for shared memory - LCMS_CREATE_LOCK(&p->rwlock); - - p ->InputFormat = InputFormat; - p ->OutputFormat = OutputFormat; - p ->dwOriginalFlags = dwFlags; + p ->InputFormat = *InputFormat; + p ->OutputFormat = *OutputFormat; + p ->dwOriginalFlags = *dwFlags; p ->ContextID = ContextID; + p ->UserData = NULL; return p; } @@ -462,12 +588,14 @@ cmsBool GetXFormColorSpaces(int nProfiles, cmsHPROFILE hProfiles[], cmsColorSpac cmsColorSpaceSignature PostColorSpace; int 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) && @@ -475,17 +603,28 @@ cmsBool GetXFormColorSpaces(int nProfiles, cmsHPROFILE hProfiles[], cmsColorSpac if (hProfile == NULL) return FALSE; - if (lIsInput) { + 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 { - + else + { ColorSpaceIn = cmsGetPCS(hProfile); ColorSpaceOut = cmsGetColorSpace(hProfile); } + if (i==0) + *Input = ColorSpaceIn; + PostColorSpace = ColorSpaceOut; } @@ -531,6 +670,12 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID, 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; @@ -566,21 +711,24 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID, return NULL; } - // Optimize the LUT if possible - _cmsOptimizePipeline(&Lut, LastIntent, &InputFormat, &OutputFormat, &dwFlags); + // Check channel count + if ((cmsChannelsOf(EntryColorSpace) != cmsPipelineInputChannels(Lut)) || + (cmsChannelsOf(ExitColorSpace) != cmsPipelineOutputChannels(Lut))) { + cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Channel count doesn't match. Profile is corrupted"); + return NULL; + } // All seems ok - xform = AllocEmptyTransform(ContextID, InputFormat, OutputFormat, dwFlags); + xform = AllocEmptyTransform(ContextID, Lut, LastIntent, &InputFormat, &OutputFormat, &dwFlags); if (xform == NULL) { - cmsPipelineFree(Lut); return NULL; } // Keep values xform ->EntryColorSpace = EntryColorSpace; xform ->ExitColorSpace = ExitColorSpace; - xform ->Lut = Lut; + xform ->RenderingIntent = Intents[nProfiles-1]; // Create a gamut check LUT if requested @@ -627,14 +775,14 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID, // If this is a cached transform, init first value, which is zero (16 bits only) if (!(dwFlags & cmsFLAGS_NOCACHE)) { - memset(&xform ->CacheIn, 0, sizeof(xform ->CacheIn)); + memset(&xform ->Cache.CacheIn, 0, sizeof(xform ->Cache.CacheIn)); if (xform ->GamutCheck != NULL) { - TransformOnePixelWithGamutCheck(xform, xform ->CacheIn, xform->CacheOut); + TransformOnePixelWithGamutCheck(xform, xform ->Cache.CacheIn, xform->Cache.CacheOut); } else { - xform ->Lut ->Eval16Fn(xform ->CacheIn, xform->CacheOut, xform -> Lut->Data); + xform ->Lut ->Eval16Fn(xform ->Cache.CacheIn, xform->Cache.CacheOut, xform -> Lut->Data); } } @@ -643,7 +791,6 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID, } // 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, @@ -785,3 +932,53 @@ cmsContext CMSEXPORT cmsGetTransformContextID(cmsHTRANSFORM 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(InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16; + ToOutput = _cmsGetFormatter(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 --git a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2.h b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2.h index fcc3998f0a5..aee6cbadb96 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2.h +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2.h @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2011 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"), @@ -52,7 +52,7 @@ // //--------------------------------------------------------------------------------- // -// Version 2.0 +// Version 2.4 // #ifndef _lcms2_H @@ -69,9 +69,6 @@ // Uncomment this if your compiler doesn't work with fast floor function // #define CMS_DONT_USE_FAST_FLOOR 1 -// Uncomment this line if your system does not support multithreading -#define CMS_DONT_USE_PTHREADS 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 @@ -84,6 +81,9 @@ // require "KEYWORD" on undefined identifiers, keep it comented 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 + // ********** End of configuration toggles ****************************** // Needed for streams @@ -101,7 +101,7 @@ extern "C" { #endif // Version/release -#define LCMS_VERSION 2000 +#define LCMS_VERSION 2040 // I will give the chance of redefining basic types for compilers that are not fully C99 compliant #ifndef CMS_BASIC_TYPES_ALREADY_DEFINED @@ -110,6 +110,10 @@ extern "C" { 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; @@ -211,11 +215,13 @@ typedef int cmsBool; #endif #ifdef TARGET_CPU_PPC +# if TARGET_CPU_PPC # define CMS_USE_BIG_ENDIAN 1 +# endif #endif #ifdef macintosh -# ifndef __LITTLE_ENDIAN__ +# ifdef __BIG_ENDIAN__ # define CMS_USE_BIG_ENDIAN 1 # endif #endif @@ -276,6 +282,7 @@ typedef enum { cmsSigCrdInfoType = 0x63726469, // 'crdi' cmsSigCurveType = 0x63757276, // 'curv' cmsSigDataType = 0x64617461, // 'data' + cmsSigDictType = 0x64696374, // 'dict' cmsSigDateTimeType = 0x6474696D, // 'dtim' cmsSigDeviceSettingsType = 0x64657673, // 'devs' cmsSigLut16Type = 0x6d667432, // 'mft2' @@ -302,9 +309,10 @@ typedef enum { cmsSigUInt32ArrayType = 0x75693332, // 'ui32' cmsSigUInt64ArrayType = 0x75693634, // 'ui64' cmsSigUInt8ArrayType = 0x75693038, // 'ui08' + cmsSigVcgtType = 0x76636774, // 'vcgt' cmsSigViewingConditionsType = 0x76696577, // 'view' - cmsSigXYZType = 0x58595A20, // 'XYZ ' - cmsSigVcgtType = 0x76636774 // 'vcgt' + cmsSigXYZType = 0x58595A20 // 'XYZ ' + } cmsTagTypeSignature; @@ -377,7 +385,8 @@ typedef enum { cmsSigUcrBgTag = 0x62666420, // 'bfd ' cmsSigViewingCondDescTag = 0x76756564, // 'vued' cmsSigViewingConditionsTag = 0x76696577, // 'view' - cmsSigVcgtTag = 0x76636774 // 'vcgt' + cmsSigVcgtTag = 0x76636774, // 'vcgt' + cmsSigMetaTag = 0x6D657461 // 'meta' } cmsTagSignature; @@ -409,7 +418,7 @@ typedef enum { cmsSigMotionPictureFilmScanner = 0x6D706673, // 'mpfs' cmsSigMotionPictureFilmRecorder = 0x6D706672, // 'mpfr' cmsSigDigitalMotionPictureCamera = 0x646D7063, // 'dmpc' - cmsSigDigitalCinemaProjector = 0x64636A70, // 'dcpj' + cmsSigDigitalCinemaProjector = 0x64636A70 // 'dcpj' } cmsTechnologySignature; @@ -436,12 +445,12 @@ typedef enum { cmsSigMCH7Data = 0x4D434837, // 'MCH7' cmsSigMCH8Data = 0x4D434838, // 'MCH8' cmsSigMCH9Data = 0x4D434839, // 'MCH9' - cmsSigMCHAData = 0x4D43483A, // 'MCHA' - cmsSigMCHBData = 0x4D43483B, // 'MCHB' - cmsSigMCHCData = 0x4D43483C, // 'MCHC' - cmsSigMCHDData = 0x4D43483D, // 'MCHD' - cmsSigMCHEData = 0x4D43483E, // 'MCHE' - cmsSigMCHFData = 0x4D43483F, // 'MCHF' + 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' @@ -470,7 +479,7 @@ typedef enum { cmsSigLinkClass = 0x6C696E6B, // 'link' cmsSigAbstractClass = 0x61627374, // 'abst' cmsSigColorSpaceClass = 0x73706163, // 'spac' - cmsSigNamedColorClass = 0x6e6d636c, // 'nmcl' + cmsSigNamedColorClass = 0x6e6d636c // 'nmcl' } cmsProfileClassSignature; @@ -512,7 +521,13 @@ typedef enum { cmsSigLabV4toV2 = 0x34203220, // '4 2 ' // Identities - cmsSigIdentityElemType = 0x69646E20 // 'idn ' + cmsSigIdentityElemType = 0x69646E20, // 'idn ' + + // Float to floatPCS + cmsSigLab2FloatPCS = 0x64326C20, // 'd2l ' + cmsSigFloatPCS2Lab = 0x6C326420, // 'l2d ' + cmsSigXYZ2FloatPCS = 0x64327820, // 'd2x ' + cmsSigFloatPCS2XYZ = 0x78326420 // 'x2d ' } cmsStageSignature; @@ -635,7 +650,9 @@ typedef void* cmsHTRANSFORM; // Format of pixel is defined by one cmsUInt32Number, using bit fields as follows // -// A O TTTTT U Y F P X S EEE CCCC BBB +// 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 @@ -743,16 +760,19 @@ typedef void* cmsHTRANSFORM; #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)|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)) @@ -834,8 +854,8 @@ typedef void* cmsHTRANSFORM; #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)|DOSWAP_SH(1)) -#define TYPE_ALabV2_8 (COLORSPACE_SH(PT_LabV2)|CHANNELS_SH(3)|BYTES_SH(1)|EXTRA_SH(1)|DOSWAP_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)) @@ -874,8 +894,16 @@ typedef void* cmsHTRANSFORM; // 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)|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. @@ -884,8 +912,21 @@ typedef void* cmsHTRANSFORM; #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 @@ -1116,6 +1157,10 @@ CMSAPI cmsBool CMSEXPORT cmsIsToneCurveDescending(const cmsToneCurve* CMSAPI cmsInt32Number CMSEXPORT cmsGetToneCurveParametricType(const cmsToneCurve* t); CMSAPI cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Number Precision); +// 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 ------------------------------------------------------------- @@ -1128,6 +1173,7 @@ CMSAPI cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUIn 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); @@ -1188,10 +1234,9 @@ typedef cmsInt32Number (* cmsSAMPLERFLOAT)(register const cmsFloat32Number In[], #define SAMPLER_INSPECT 0x01000000 // For CLUT only -CMSAPI cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, void* Cargo, cmsUInt32Number dwFlags); +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); @@ -1301,6 +1346,7 @@ CMSAPI cmsNAMEDCOLORLIST* CMSEXPORT cmsGetNamedColorList(cmsHTRANSFORM xform); // 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; @@ -1324,6 +1370,27 @@ CMSAPI cmsSEQ* CMSEXPORT cmsAllocProfileSequenceDescription(cmsContext 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); @@ -1336,12 +1403,18 @@ CMSAPI cmsBool CMSEXPORT cmsIsTag(cmsHPROFILE hProfile, cmsTagSignatur 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 cmsInt32Number 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); @@ -1377,9 +1450,9 @@ CMSAPI void CMSEXPORT cmsSetEncodedICCversion(cmsHPROFILE hProfile, #define LCMS_USED_AS_OUTPUT 1 #define LCMS_USED_AS_PROOF 2 -CMSAPI cmsBool CMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, cmsUInt32Number Intent, int UsedDirection); +CMSAPI cmsBool CMSEXPORT cmsIsIntentSupported(cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number UsedDirection); CMSAPI cmsBool CMSEXPORT cmsIsMatrixShaper(cmsHPROFILE hProfile); -CMSAPI cmsBool CMSEXPORT cmsIsCLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent, int UsedDirection); +CMSAPI cmsBool CMSEXPORT cmsIsCLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number UsedDirection); // Translate form/to our notation to ICC CMSAPI cmsColorSpaceSignature CMSEXPORT _cmsICCcolorSpace(int OurNotation); @@ -1528,7 +1601,6 @@ CMSAPI cmsUInt32Number CMSEXPORT cmsGetSupportedIntents(cmsUInt32Number nMax, c #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 @@ -1626,14 +1698,32 @@ CMSAPI void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform, void * OutputBuffer, cmsUInt32Number Size); +CMSAPI void CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM Transform, + const void * InputBuffer, + void * OutputBuffer, + cmsUInt32Number Size, + cmsUInt32Number Stride); + + CMSAPI void CMSEXPORT cmsSetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]); CMSAPI void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number NewAlarm[cmsMAXCHANNELS]); // Adaptation state for absolute colorimetric intent CMSAPI cmsFloat64Number CMSEXPORT cmsSetAdaptationState(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 ---------------------------------------------------- @@ -1677,12 +1767,15 @@ CMSAPI cmsBool CMSEXPORT cmsIT8SetComment(cmsHANDLE hIT8, const char* c 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); @@ -1712,10 +1805,13 @@ CMSAPI cmsBool CMSEXPORT cmsIT8SetDataFormat(cmsHANDLE hIT8, int n, con 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); @@ -1731,6 +1827,7 @@ CMSAPI cmsBool CMSEXPORT cmsGDBCheckPoint(cmsHANDLE hGBD, const cmsCIEL // 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); diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h index 53a3a4639a7..9477aa33cfc 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2011 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"), @@ -75,16 +75,18 @@ # define M_LOG10E 0.434294481903251827651 #endif -// BorlandC 5.5 is broken on that -#ifdef __BORLANDC__ +// BorlandC 5.5, VC2003 are broken on that +#if defined(__BORLANDC__) || (_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 _cmsSIZEOFLONGMINUS1 (sizeof(cmsUInt32Number)-1) -#define _cmsALIGNLONG(x) (((x)+_cmsSIZEOFLONGMINUS1) & ~(_cmsSIZEOFLONGMINUS1)) +#define _cmsALIGNLONG(x) (((x)+(sizeof(cmsUInt32Number)-1)) & ~(sizeof(cmsUInt32Number)-1)) + +// Alignment to memory pointer +#define _cmsALIGNMEM(x) (((x)+(sizeof(void *) - 1)) & ~(sizeof(void *) - 1)) // Maximum encodeable values in floating point #define MAX_ENCODEABLE_XYZ (1.0 + 32767.0/32768.0) @@ -94,7 +96,7 @@ #define MAX_ENCODEABLE_ab4 (127.0) // Maximum of channels for internal pipeline evaluation -#define MAX_STAGE_CHANNELS 128 +#define MAX_STAGE_CHANNELS 128 // Unused parameter warning supression #define cmsUNUSED_PARAMETER(x) ((void)x) @@ -117,36 +119,6 @@ # endif #endif -// Pthreads. In windows we use the native WIN32 API instead -#ifdef CMS_DONT_USE_PTHREADS -typedef int LCMS_RWLOCK_T; -# define LCMS_CREATE_LOCK(x) -# define LCMS_FREE_LOCK(x) -# define LCMS_READ_LOCK(x) -# define LCMS_WRITE_LOCK(x) -# define LCMS_UNLOCK(x) -#else -#ifdef CMS_IS_WINDOWS_ -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include - typedef CRITICAL_SECTION LCMS_RWLOCK_T; -# define LCMS_CREATE_LOCK(x) InitializeCriticalSection((x)) -# define LCMS_FREE_LOCK(x) DeleteCriticalSection((x)) -# define LCMS_READ_LOCK(x) EnterCriticalSection((x)) -# define LCMS_WRITE_LOCK(x) EnterCriticalSection((x)) -# define LCMS_UNLOCK(x) LeaveCriticalSection((x)) -#else -# include - typedef pthread_rwlock_t LCMS_RWLOCK_T; -# define LCMS_CREATE_LOCK(x) pthread_rwlock_init((x), NULL) -# define LCMS_FREE_LOCK(x) pthread_rwlock_destroy((x)) -# define LCMS_READ_LOCK(x) pthread_rwlock_rdlock((x)) -# define LCMS_WRITE_LOCK(x) pthread_rwlock_wrlock((x)) -# define LCMS_UNLOCK(x) pthread_rwlock_unlock((x)) -#endif -#endif // A fast way to convert from/to 16 <-> 8 bits #define FROM_8_TO_16(rgb) (cmsUInt16Number) ((((cmsUInt16Number) (rgb)) << 8)|(rgb)) @@ -253,6 +225,8 @@ cmsBool _cmsRegisterMultiProcessElementPlugin(cmsPluginBase* Plugin); // Optimization cmsBool _cmsRegisterOptimizationPlugin(cmsPluginBase* Plugin); +// Transform +cmsBool _cmsRegisterTransformPlugin(cmsPluginBase* Plugin); // --------------------------------------------------------------------------------------------------------- @@ -396,6 +370,7 @@ void _cmsTagSignature2String(char String[5], cmsTagSignature sig cmsInterpParams* _cmsComputeInterpParams(cmsContext ContextID, int nSamples, int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags); cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID, const cmsUInt32Number nSamples[], int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags); void _cmsFreeInterpParams(cmsInterpParams* p); +cmsBool _cmsSetInterpolationRoutine(cmsInterpParams* p); // Curves ---------------------------------------------------------------------------------------------------------------- @@ -443,37 +418,6 @@ struct _cmsStage_struct { struct _cmsStage_struct* Next; }; -// 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; - // Special Stages (cannot be saved) cmsStage* _cmsStageAllocLab2XYZ(cmsContext ContextID); @@ -482,9 +426,13 @@ cmsStage* _cmsStageAllocLabPrelin(cmsContext ContextID); cmsStage* _cmsStageAllocLabV2ToV4(cmsContext ContextID); cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID); cmsStage* _cmsStageAllocLabV4ToV2(cmsContext ContextID); -cmsStage* _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList); +cmsStage* _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList, cmsBool UsePCS); cmsStage* _cmsStageAllocIdentityCurves(cmsContext ContextID, int nChannels); cmsStage* _cmsStageAllocIdentityCLut(cmsContext ContextID, int nChan); +cmsStage* _cmsStageNormalizeFromLabFloat(cmsContext ContextID); +cmsStage* _cmsStageNormalizeFromXyzFloat(cmsContext ContextID); +cmsStage* _cmsStageNormalizeToLabFloat(cmsContext ContextID); +cmsStage* _cmsStageNormalizeToXyzFloat(cmsContext ContextID); // For curve set only cmsToneCurve** _cmsStageGetPtrToCurveSet(const cmsStage* mpe); @@ -505,12 +453,12 @@ struct _cmsPipeline_struct { _cmsOPTeval16Fn Eval16Fn; _cmsPipelineEvalFloatFn EvalFloatFn; - _cmsOPTfreeDataFn FreeDataFn; - _cmsOPTdupDataFn DupDataFn; + _cmsFreeUserDataFn FreeDataFn; + _cmsDupUserDataFn DupDataFn; cmsContext ContextID; // Environment - cmsBool SaveAs8Bits; // Implemntation-specific: save as 8 bits if possible + cmsBool SaveAs8Bits; // Implementation-specific: save as 8 bits if possible }; // LUT reading & creation ------------------------------------------------------------------------------------------- @@ -573,6 +521,8 @@ cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID, // Formatters ------------------------------------------------------------------------------------------------------------ +#define cmsFLAGS_CAN_CHANGE_FORMATTER 0x02000000 // Allow change buffer format + cmsBool _cmsFormatterIsFloat(cmsUInt32Number Type); cmsBool _cmsFormatterIs8bit(cmsUInt32Number Type); @@ -581,21 +531,27 @@ cmsFormatter _cmsGetFormatter(cmsUInt32Number Type, // Specific type cmsUInt32Number dwFlags); +#ifndef CMS_NO_HALF_SUPPORT + +// Half float +cmsFloat32Number _cmsHalf2Float(cmsUInt16Number h); +cmsUInt16Number _cmsFloat2Half(cmsFloat32Number flt); + +#endif + // Transform logic ------------------------------------------------------------------------------------------------------ struct _cmstransform_struct; -// Full xform -typedef void (* _cmsTransformFn)(struct _cmstransform_struct *Transform, - const void* InputBuffer, - void* OutputBuffer, cmsUInt32Number Size); - typedef struct { - cmsUInt32Number InputFormat, OutputFormat; // Keep formats for further reference - cmsUInt32Number StrideIn, StrideOut; // Planar support + // 1-pixel cache (16 bits only) + cmsUInt16Number CacheIn[cmsMAXCHANNELS]; + cmsUInt16Number CacheOut[cmsMAXCHANNELS]; + +} _cmsCACHE; + -} cmsFormatterInfo; // Transformation typedef struct _cmstransform_struct { @@ -612,17 +568,13 @@ typedef struct _cmstransform_struct { cmsFormatterFloat FromInputFloat; cmsFormatterFloat ToOutputFloat; - // 1-pixel cache (16 bits only) - cmsUInt16Number CacheIn[cmsMAXCHANNELS]; - cmsUInt16Number CacheOut[cmsMAXCHANNELS]; + // 1-pixel cache seed for zero as input (16 bits, read only) + _cmsCACHE Cache; - // Semaphor for cache - LCMS_RWLOCK_T rwlock; - - // A MPE LUT holding the full (optimized) transform + // A Pipeline holding the full (optimized) transform cmsPipeline* Lut; - // A MPE LUT holding the gamut check. It goes from the input space to bilevel + // A Pipeline holding the gamut check. It goes from the input space to bilevel cmsPipeline* GamutCheck; // Colorant tables @@ -645,6 +597,10 @@ typedef struct _cmstransform_struct { // 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; + } _cmsTRANSFORM; // -------------------------------------------------------------------------------------------------- diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_plugin.h b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_plugin.h index dd1a6d2ed16..1df7cf79b8d 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_plugin.h +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_plugin.h @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2010 Marti Maria Saguer +// Copyright (c) 1998-2011 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"), @@ -144,6 +144,7 @@ struct _cms_io_handler { cmsContext ContextID; cmsUInt32Number UsedSpace; + cmsUInt32Number ReportedSize; char PhysicalFile[cmsMAX_PATH]; cmsUInt32Number (* Read)(struct _cms_io_handler* iohandler, void *Buffer, @@ -159,7 +160,7 @@ struct _cms_io_handler { // Endianess adjust functions CMSAPI cmsUInt16Number CMSEXPORT _cmsAdjustEndianess16(cmsUInt16Number Word); CMSAPI cmsUInt32Number CMSEXPORT _cmsAdjustEndianess32(cmsUInt32Number Value); -CMSAPI void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number QWord); +CMSAPI void CMSEXPORT _cmsAdjustEndianess64(cmsUInt64Number* Result, cmsUInt64Number* QWord); // Helper IO functions CMSAPI cmsBool CMSEXPORT _cmsReadUInt8Number(cmsIOHANDLER* io, cmsUInt8Number* n); @@ -175,7 +176,7 @@ CMSAPI cmsBool CMSEXPORT _cmsWriteUInt8Number(cmsIOHANDLER* io, cmsUI 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 _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); @@ -209,6 +210,11 @@ CMSAPI cmsS15Fixed16Number CMSEXPORT _cmsDoubleTo15Fixed16(cmsFloat64Number v); 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); //---------------------------------------------------------------------------------------------------------- @@ -224,6 +230,7 @@ CMSAPI void CMSEXPORT _cmsDecodeDateTimeNumber(const cmsDateTimeN #define cmsPluginRenderingIntentSig 0x696E7448 // 'intH' #define cmsPluginMultiProcessElementSig 0x6D706548 // 'mpeH' #define cmsPluginOptimizationSig 0x6F707448 // 'optH' +#define cmsPluginTransformSig 0x7A666D48 // 'xfmH' typedef struct _cmsPluginBaseStruct { @@ -414,8 +421,9 @@ typedef struct _cms_typehandler_struct { void (* FreePtr)(struct _cms_typehandler_struct* self, void *Ptr); - // The calling thread - cmsContext ContextID; + // Additional parameters used by the calling thread + cmsContext ContextID; + cmsUInt32Number ICCVersion; } cmsTagTypeHandler; @@ -513,6 +521,39 @@ typedef struct { } 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 @@ -523,9 +564,6 @@ typedef void (* _cmsOPTeval16Fn)(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register const void* Data); -typedef void (* _cmsOPTfreeDataFn)(cmsContext ContextID, void* Data); -typedef void* (* _cmsOPTdupDataFn)(cmsContext ContextID, const void* Data); - typedef cmsBool (* _cmsOPToptimizeFn)(cmsPipeline** Lut, cmsUInt32Number Intent, @@ -539,8 +577,8 @@ typedef cmsBool (* _cmsOPToptimizeFn)(cmsPipeline** Lut, CMSAPI void CMSEXPORT _cmsPipelineSetOptimizationParameters(cmsPipeline* Lut, _cmsOPTeval16Fn Eval16, void* PrivateData, - _cmsOPTfreeDataFn FreePrivateDataFn, - _cmsOPTdupDataFn DupPrivateDataFn); + _cmsFreeUserDataFn FreePrivateDataFn, + _cmsDupUserDataFn DupPrivateDataFn); typedef struct { cmsPluginBase base; @@ -551,6 +589,39 @@ typedef struct { } cmsPluginOptimization; //---------------------------------------------------------------------------------------------------------- +// Full xform +typedef void (* _cmsTransformFn)(struct _cmstransform_struct *CMMcargo, + const void* InputBuffer, + void* OutputBuffer, + cmsUInt32Number Size, + cmsUInt32Number Stride); + +typedef cmsBool (* _cmsTransformFactory)(_cmsTransformFn* 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); + +typedef struct { + cmsPluginBase base; + + // Transform entry point + _cmsTransformFactory Factory; + +} cmsPluginTransform; + #ifndef CMS_USE_CPP_API # ifdef __cplusplus From d96d10ded0b7968f9cd727758fe98d49d3700c1d Mon Sep 17 00:00:00 2001 From: Anton Litvinov Date: Wed, 24 Oct 2012 18:27:14 +0400 Subject: [PATCH 04/59] 7193219: JComboBox serialization fails in JDK 1.7 Reviewed-by: rupashka, anthony --- .../classes/javax/swing/AncestorNotifier.java | 4 +- .../AncestorNotifier/7193219/bug7193219.java | 83 +++++++++++++++++++ 2 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 jdk/test/javax/swing/AncestorNotifier/7193219/bug7193219.java diff --git a/jdk/src/share/classes/javax/swing/AncestorNotifier.java b/jdk/src/share/classes/javax/swing/AncestorNotifier.java index 288d7fdb599..f3cfdd9d0ba 100644 --- a/jdk/src/share/classes/javax/swing/AncestorNotifier.java +++ b/jdk/src/share/classes/javax/swing/AncestorNotifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import java.io.Serializable; @SuppressWarnings("serial") class AncestorNotifier implements ComponentListener, PropertyChangeListener, Serializable { - Component firstInvisibleAncestor; + transient Component firstInvisibleAncestor; EventListenerList listenerList = new EventListenerList(); JComponent root; diff --git a/jdk/test/javax/swing/AncestorNotifier/7193219/bug7193219.java b/jdk/test/javax/swing/AncestorNotifier/7193219/bug7193219.java new file mode 100644 index 00000000000..0db4839dc50 --- /dev/null +++ b/jdk/test/javax/swing/AncestorNotifier/7193219/bug7193219.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 7193219 + @summary JComboBox serialization fails in JDK 1.7 + @author Anton Litvinov +*/ + +import java.io.*; + +import javax.swing.*; + +public class bug7193219 { + private static byte[] serializeGUI() { + // Create and set up the window. + JFrame frame = new JFrame("Serialization"); + JPanel mainPanel = new JPanel(); + + /** + * If JComboBox is replaced with other component like JLabel + * The issue does not happen. + */ + JComboBox status = new JComboBox(); + status.addItem("123"); + mainPanel.add(status); + frame.getContentPane().add(mainPanel); + frame.pack(); + + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(mainPanel); + oos.flush(); + frame.dispose(); + return baos.toByteArray(); + } catch (IOException ioe) { + throw new RuntimeException(ioe); + } + } + + private static void deserializeGUI(byte[] serializedData) { + try { + ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(serializedData)); + JPanel mainPanel = (JPanel)ois.readObject(); + JFrame frame = new JFrame("Deserialization"); + frame.getContentPane().add(mainPanel); + frame.pack(); + frame.dispose(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + deserializeGUI(serializeGUI()); + } + }); + } +} From b01d15feb09f2c912dbf7dd07ceff3aa608a9f60 Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Wed, 24 Oct 2012 08:25:29 -0700 Subject: [PATCH 05/59] 8001466: Nightly regression test failure of SSLSocketSNISensitive.java Reviewed-by: weijun --- .../net/ssl/ServerName/SSLSocketSNISensitive.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/jdk/test/sun/security/ssl/javax/net/ssl/ServerName/SSLSocketSNISensitive.java b/jdk/test/sun/security/ssl/javax/net/ssl/ServerName/SSLSocketSNISensitive.java index 4c50c305704..03a841bfd85 100644 --- a/jdk/test/sun/security/ssl/javax/net/ssl/ServerName/SSLSocketSNISensitive.java +++ b/jdk/test/sun/security/ssl/javax/net/ssl/ServerName/SSLSocketSNISensitive.java @@ -267,6 +267,9 @@ public class SSLSocketSNISensitive { SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept(); try { + sslSocket.setSoTimeout(5000); + sslSocket.setSoLinger(true, 5); + InputStream sslIS = sslSocket.getInputStream(); OutputStream sslOS = sslSocket.getOutputStream(); @@ -312,6 +315,9 @@ public class SSLSocketSNISensitive { sslSocket.setSSLParameters(params); try { + sslSocket.setSoTimeout(5000); + sslSocket.setSoLinger(true, 5); + InputStream sslIS = sslSocket.getInputStream(); OutputStream sslOS = sslSocket.getOutputStream(); @@ -519,7 +525,7 @@ public class SSLSocketSNISensitive { * * Release the client, if not active already... */ - System.err.println("Server died..."); + System.err.println("Server died, because of " + e); serverReady = true; serverException = e; } @@ -547,7 +553,7 @@ public class SSLSocketSNISensitive { /* * Our client thread just died. */ - System.err.println("Client died..."); + System.err.println("Client died, because of " + e); clientException = e; } } From 3e4e347c260ddf7f01d8f82303053563b128bbba Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Wed, 24 Oct 2012 20:44:07 +0100 Subject: [PATCH 06/59] 6976971: TEST: javax/management/remote/mandatory/URLTest.java should be re-integrated Reviewed-by: alanb --- jdk/test/javax/management/remote/mandatory/URLTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/jdk/test/javax/management/remote/mandatory/URLTest.java b/jdk/test/javax/management/remote/mandatory/URLTest.java index 4649ec580c6..7e160d05448 100644 --- a/jdk/test/javax/management/remote/mandatory/URLTest.java +++ b/jdk/test/javax/management/remote/mandatory/URLTest.java @@ -24,8 +24,6 @@ /* * @test * @bug 5057532 - * @ignore Test will fail until 6338951 is resolved (java.net.URI now - * accepts "http://-a"). * @summary Tests that host names are parsed correctly in URLs * @author Eamonn McManus * @run clean URLTest From 3877e3dda4e4a886cbca66c7cdc9bb3fad553ffa Mon Sep 17 00:00:00 2001 From: John Zavgren Date: Wed, 24 Oct 2012 21:20:40 +0100 Subject: [PATCH 07/59] 8000203: File descriptor leak in src/solaris/native/java/net/net_util_md.c Reviewed-by: dsamersoff, khazra, chegar --- jdk/src/solaris/native/java/net/net_util_md.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/jdk/src/solaris/native/java/net/net_util_md.c b/jdk/src/solaris/native/java/net/net_util_md.c index 7df6f3e9823..c700cfd0b75 100644 --- a/jdk/src/solaris/native/java/net/net_util_md.c +++ b/jdk/src/solaris/native/java/net/net_util_md.c @@ -546,6 +546,7 @@ static void initLoopbackRoutes() { char dest_str[40]; struct in6_addr dest_addr; char device[16]; + struct loopback_route *loRoutesTemp; if (loRoutes != 0) { free (loRoutes); @@ -606,11 +607,15 @@ static void initLoopbackRoutes() { continue; } else { if (nRoutes == loRoutes_size) { - loRoutes = realloc (loRoutes, loRoutes_size * - sizeof (struct loopback_route) * 2); - if (loRoutes == 0) { - return ; + loRoutesTemp = realloc (loRoutes, loRoutes_size * + sizeof (struct loopback_route) * 2); + + if (loRoutesTemp == 0) { + free(loRoutes); + fclose (f); + return; } + loRoutes=loRoutesTemp; loRoutes_size *= 2; } memcpy (&loRoutes[nRoutes].addr,&dest_addr,sizeof(struct in6_addr)); From 6036ad08e5c5dba188fbb66716d9556af2e36b3c Mon Sep 17 00:00:00 2001 From: Oleg Pekhovskiy Date: Thu, 25 Oct 2012 09:55:33 +0400 Subject: [PATCH 08/59] 8000486: REGRESSION: Three java2d tests fail since jdk8b58 on Windows 7 with NullPointerException Reviewed-by: flar, art --- jdk/src/windows/classes/sun/java2d/ScreenUpdateManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/windows/classes/sun/java2d/ScreenUpdateManager.java b/jdk/src/windows/classes/sun/java2d/ScreenUpdateManager.java index 27da53ef284..d15e28cb0ad 100644 --- a/jdk/src/windows/classes/sun/java2d/ScreenUpdateManager.java +++ b/jdk/src/windows/classes/sun/java2d/ScreenUpdateManager.java @@ -111,7 +111,7 @@ public class ScreenUpdateManager { SurfaceData oldsd) { SurfaceData surfaceData = peer.getSurfaceData(); - if (surfaceData.isValid()) { + if (surfaceData == null || surfaceData.isValid()) { return surfaceData; } peer.replaceSurfaceData(); From bf6c304c44d4013fb7093dc05086b4fd3d3c0fed Mon Sep 17 00:00:00 2001 From: Oleg Pekhovskiy Date: Thu, 25 Oct 2012 19:50:30 +0400 Subject: [PATCH 09/59] 7082294: nsk/regression/b4265661 crashes on windows Reviewed-by: art, anthony --- jdk/src/windows/native/sun/windows/awt_Font.cpp | 8 +++++--- jdk/src/windows/native/sun/windows/awt_Toolkit.cpp | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/jdk/src/windows/native/sun/windows/awt_Font.cpp b/jdk/src/windows/native/sun/windows/awt_Font.cpp index d07cdae0467..185514c1972 100644 --- a/jdk/src/windows/native/sun/windows/awt_Font.cpp +++ b/jdk/src/windows/native/sun/windows/awt_Font.cpp @@ -150,6 +150,7 @@ AwtFont::AwtFont(int num, JNIEnv *env, jobject javaFont) AwtFont::~AwtFont() { + delete[] m_hFont; } void AwtFont::Dispose() { @@ -160,11 +161,12 @@ void AwtFont::Dispose() { /* NOTE: delete of windows HFONT happens in FontCache::Remove only when the final reference to the font is disposed */ } else if (font != NULL) { - // if font was not in cache, its not shared and we delete it now - VERIFY(::DeleteObject(font)); + // if font was not in cache, its not shared and we delete it now + DASSERT(::GetObjectType(font) == OBJ_FONT); + VERIFY(::DeleteObject(font)); } + m_hFont[i] = NULL; } - delete[] m_hFont; AwtObject::Dispose(); } diff --git a/jdk/src/windows/native/sun/windows/awt_Toolkit.cpp b/jdk/src/windows/native/sun/windows/awt_Toolkit.cpp index 913540399b5..e8b2d51931a 100644 --- a/jdk/src/windows/native/sun/windows/awt_Toolkit.cpp +++ b/jdk/src/windows/native/sun/windows/awt_Toolkit.cpp @@ -534,7 +534,6 @@ BOOL AwtToolkit::Dispose() { D3DInitializer::GetInstance().Clean(); AwtObjectList::Cleanup(); - AwtFont::Cleanup(); awt_dnd_uninitialize(); awt_clipboard_uninitialize((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2)); @@ -554,6 +553,8 @@ BOOL AwtToolkit::Dispose() { ::DispatchMessage(&msg); } + AwtFont::Cleanup(); + HWND toolkitHWndToDestroy = tk.m_toolkitHWnd; tk.m_toolkitHWnd = 0; VERIFY(::DestroyWindow(toolkitHWndToDestroy) != NULL); From fc938fcbd971ff03c3d33a618ae98086d77f9db0 Mon Sep 17 00:00:00 2001 From: Harold Seigel Date: Thu, 25 Oct 2012 16:33:15 -0400 Subject: [PATCH 10/59] 7188234: Deprecate VM command line options Remove support for the UseVectoredExceptions flag Reviewed-by: jcoomes, kamg --- hotspot/src/os/windows/vm/os_windows.cpp | 78 +++---------------- .../src/os_cpu/bsd_x86/vm/globals_bsd_x86.hpp | 2 - .../os_cpu/bsd_zero/vm/globals_bsd_zero.hpp | 1 - .../linux_sparc/vm/globals_linux_sparc.hpp | 2 - .../os_cpu/linux_x86/vm/globals_linux_x86.hpp | 2 - .../linux_zero/vm/globals_linux_zero.hpp | 1 - .../vm/globals_solaris_sparc.hpp | 2 - .../solaris_x86/vm/globals_solaris_x86.hpp | 2 - .../windows_x86/vm/globals_windows_x86.hpp | 2 - .../os_cpu/windows_x86/vm/os_windows_x86.cpp | 3 - hotspot/src/share/vm/runtime/arguments.cpp | 1 + hotspot/src/share/vm/runtime/globals.hpp | 3 - 12 files changed, 10 insertions(+), 89 deletions(-) diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index dc31e27a6b7..420368f1010 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -22,7 +22,7 @@ * */ -// Must be at least Windows 2000 or XP to use VectoredExceptions and IsDebuggerPresent +// Must be at least Windows 2000 or XP to use IsDebuggerPresent #define _WIN32_WINNT 0x500 // no precompiled headers @@ -110,10 +110,6 @@ static FILETIME process_exit_time; static FILETIME process_user_time; static FILETIME process_kernel_time; -#ifdef _WIN64 -PVOID topLevelVectoredExceptionHandler = NULL; -#endif - #ifdef _M_IA64 #define __CPU__ ia64 #elif _M_AMD64 @@ -136,12 +132,6 @@ BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved) { case DLL_PROCESS_DETACH: if(ForceTimeHighResolution) timeEndPeriod(1L); -#ifdef _WIN64 - if (topLevelVectoredExceptionHandler != NULL) { - RemoveVectoredExceptionHandler(topLevelVectoredExceptionHandler); - topLevelVectoredExceptionHandler = NULL; - } -#endif break; default: break; @@ -408,20 +398,14 @@ static unsigned __stdcall java_start(Thread* thread) { } - if (UseVectoredExceptions) { - // If we are using vectored exception we don't need to set a SEH - thread->run(); - } - else { - // Install a win32 structured exception handler around every thread created - // by VM, so VM can genrate error dump when an exception occurred in non- - // Java thread (e.g. VM thread). - __try { - thread->run(); - } __except(topLevelExceptionFilter( - (_EXCEPTION_POINTERS*)_exception_info())) { - // Nothing to do. - } + // Install a win32 structured exception handler around every thread created + // by VM, so VM can genrate error dump when an exception occurred in non- + // Java thread (e.g. VM thread). + __try { + thread->run(); + } __except(topLevelExceptionFilter( + (_EXCEPTION_POINTERS*)_exception_info())) { + // Nothing to do. } // One less thread is executing @@ -2489,16 +2473,6 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { } #endif -#ifdef _WIN64 - // Windows will sometimes generate an access violation - // when we call malloc. Since we use VectoredExceptions - // on 64 bit platforms, we see this exception. We must - // pass this exception on so Windows can recover. - // We check to see if the pc of the fault is in NTDLL.DLL - // if so, we pass control on to Windows for handling. - if (UseVectoredExceptions && _addr_in_ntdll(pc)) return EXCEPTION_CONTINUE_SEARCH; -#endif - // Stack overflow or null pointer exception in native code. report_error(t, exception_code, pc, exceptionInfo->ExceptionRecord, exceptionInfo->ContextRecord); @@ -2527,30 +2501,8 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { } if (exception_code != EXCEPTION_BREAKPOINT) { -#ifndef _WIN64 report_error(t, exception_code, pc, exceptionInfo->ExceptionRecord, exceptionInfo->ContextRecord); -#else - // Itanium Windows uses a VectoredExceptionHandler - // Which means that C++ programatic exception handlers (try/except) - // will get here. Continue the search for the right except block if - // the exception code is not a fatal code. - switch ( exception_code ) { - case EXCEPTION_ACCESS_VIOLATION: - case EXCEPTION_STACK_OVERFLOW: - case EXCEPTION_ILLEGAL_INSTRUCTION: - case EXCEPTION_ILLEGAL_INSTRUCTION_2: - case EXCEPTION_INT_OVERFLOW: - case EXCEPTION_INT_DIVIDE_BY_ZERO: - case EXCEPTION_UNCAUGHT_CXX_EXCEPTION: - { report_error(t, exception_code, pc, exceptionInfo->ExceptionRecord, - exceptionInfo->ContextRecord); - } - break; - default: - break; - } -#endif } return EXCEPTION_CONTINUE_SEARCH; } @@ -3706,18 +3658,6 @@ jint os::init_2(void) { // Setup Windows Exceptions - // On Itanium systems, Structured Exception Handling does not - // work since stack frames must be walkable by the OS. Since - // much of our code is dynamically generated, and we do not have - // proper unwind .xdata sections, the system simply exits - // rather than delivering the exception. To work around - // this we use VectorExceptions instead. -#ifdef _WIN64 - if (UseVectoredExceptions) { - topLevelVectoredExceptionHandler = AddVectoredExceptionHandler( 1, topLevelExceptionFilter); - } -#endif - // for debugging float code generation bugs if (ForceFloatExceptions) { #ifndef _WIN64 diff --git a/hotspot/src/os_cpu/bsd_x86/vm/globals_bsd_x86.hpp b/hotspot/src/os_cpu/bsd_x86/vm/globals_bsd_x86.hpp index 5a19fed3f58..3a8d42ab68e 100644 --- a/hotspot/src/os_cpu/bsd_x86/vm/globals_bsd_x86.hpp +++ b/hotspot/src/os_cpu/bsd_x86/vm/globals_bsd_x86.hpp @@ -48,7 +48,5 @@ define_pd_global(uintx, JVMInvokeMethodSlack, 8192); // Used on 64 bit platforms for UseCompressedOops base address or CDS define_pd_global(uintx, HeapBaseMinAddress, 2*G); -// Only used on 64 bit Windows platforms -define_pd_global(bool, UseVectoredExceptions, false); #endif // OS_CPU_BSD_X86_VM_GLOBALS_BSD_X86_HPP diff --git a/hotspot/src/os_cpu/bsd_zero/vm/globals_bsd_zero.hpp b/hotspot/src/os_cpu/bsd_zero/vm/globals_bsd_zero.hpp index 6b1f6af5efc..9c988eb743b 100644 --- a/hotspot/src/os_cpu/bsd_zero/vm/globals_bsd_zero.hpp +++ b/hotspot/src/os_cpu/bsd_zero/vm/globals_bsd_zero.hpp @@ -41,7 +41,6 @@ define_pd_global(intx, VMThreadStackSize, 512); define_pd_global(intx, CompilerThreadStackSize, 0); define_pd_global(uintx, JVMInvokeMethodSlack, 8192); -define_pd_global(bool, UseVectoredExceptions, false); // Used on 64 bit platforms for UseCompressedOops base address or CDS define_pd_global(uintx, HeapBaseMinAddress, 2*G); diff --git a/hotspot/src/os_cpu/linux_sparc/vm/globals_linux_sparc.hpp b/hotspot/src/os_cpu/linux_sparc/vm/globals_linux_sparc.hpp index ab9d8cdeb25..4ac5ead1946 100644 --- a/hotspot/src/os_cpu/linux_sparc/vm/globals_linux_sparc.hpp +++ b/hotspot/src/os_cpu/linux_sparc/vm/globals_linux_sparc.hpp @@ -35,7 +35,5 @@ define_pd_global(intx, CompilerThreadStackSize, 0); // Used on 64 bit platforms for UseCompressedOops base address or CDS define_pd_global(uintx, HeapBaseMinAddress, CONST64(4)*G); -// Only used on 64 bit Windows platforms -define_pd_global(bool, UseVectoredExceptions, false); #endif // OS_CPU_LINUX_SPARC_VM_GLOBALS_LINUX_SPARC_HPP diff --git a/hotspot/src/os_cpu/linux_x86/vm/globals_linux_x86.hpp b/hotspot/src/os_cpu/linux_x86/vm/globals_linux_x86.hpp index a7c94c00f82..b11a6f3aa27 100644 --- a/hotspot/src/os_cpu/linux_x86/vm/globals_linux_x86.hpp +++ b/hotspot/src/os_cpu/linux_x86/vm/globals_linux_x86.hpp @@ -46,7 +46,5 @@ define_pd_global(uintx,JVMInvokeMethodSlack, 8192); // Used on 64 bit platforms for UseCompressedOops base address or CDS define_pd_global(uintx,HeapBaseMinAddress, 2*G); -// Only used on 64 bit Windows platforms -define_pd_global(bool, UseVectoredExceptions, false); #endif // OS_CPU_LINUX_X86_VM_GLOBALS_LINUX_X86_HPP diff --git a/hotspot/src/os_cpu/linux_zero/vm/globals_linux_zero.hpp b/hotspot/src/os_cpu/linux_zero/vm/globals_linux_zero.hpp index 14003011d3e..56495d176d1 100644 --- a/hotspot/src/os_cpu/linux_zero/vm/globals_linux_zero.hpp +++ b/hotspot/src/os_cpu/linux_zero/vm/globals_linux_zero.hpp @@ -41,7 +41,6 @@ define_pd_global(intx, VMThreadStackSize, 512); define_pd_global(intx, CompilerThreadStackSize, 0); define_pd_global(uintx, JVMInvokeMethodSlack, 8192); -define_pd_global(bool, UseVectoredExceptions, false); // Used on 64 bit platforms for UseCompressedOops base address or CDS define_pd_global(uintx, HeapBaseMinAddress, 2*G); diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/globals_solaris_sparc.hpp b/hotspot/src/os_cpu/solaris_sparc/vm/globals_solaris_sparc.hpp index 76695e9442c..e6cb0dddb01 100644 --- a/hotspot/src/os_cpu/solaris_sparc/vm/globals_solaris_sparc.hpp +++ b/hotspot/src/os_cpu/solaris_sparc/vm/globals_solaris_sparc.hpp @@ -39,8 +39,6 @@ define_pd_global(uintx, HeapBaseMinAddress, CONST64(4)*G); #else define_pd_global(uintx, HeapBaseMinAddress, 2*G); #endif -// Only used on 64 bit Windows platforms -define_pd_global(bool, UseVectoredExceptions, false); diff --git a/hotspot/src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp b/hotspot/src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp index 780df544cc4..5d99a09c447 100644 --- a/hotspot/src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp +++ b/hotspot/src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp @@ -45,7 +45,5 @@ define_pd_global(intx, CompilerThreadStackSize, 0); // Used on 64 bit platforms for UseCompressedOops base address or CDS define_pd_global(uintx,HeapBaseMinAddress, 256*M); -// Only used on 64 bit Windows platforms -define_pd_global(bool, UseVectoredExceptions, false); #endif // OS_CPU_SOLARIS_X86_VM_GLOBALS_SOLARIS_X86_HPP diff --git a/hotspot/src/os_cpu/windows_x86/vm/globals_windows_x86.hpp b/hotspot/src/os_cpu/windows_x86/vm/globals_windows_x86.hpp index 57e0ac34c75..f4167f5eb5c 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/globals_windows_x86.hpp +++ b/hotspot/src/os_cpu/windows_x86/vm/globals_windows_x86.hpp @@ -47,7 +47,5 @@ define_pd_global(uintx, JVMInvokeMethodSlack, 8192); // Used on 64 bit platforms for UseCompressedOops base address or CDS define_pd_global(uintx, HeapBaseMinAddress, 2*G); -// Only used on 64 bit Windows platforms -define_pd_global(bool, UseVectoredExceptions, false); #endif // OS_CPU_WINDOWS_X86_VM_GLOBALS_WINDOWS_X86_HPP diff --git a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp index 434929f30d2..d0fad7da799 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp +++ b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp @@ -175,9 +175,6 @@ bool os::register_code_area(char *low, char *high) { PRUNTIME_FUNCTION prt; PUNWIND_INFO_EH_ONLY punwind; - // If we are using Vectored Exceptions we don't need this registration - if (UseVectoredExceptions) return true; - BufferBlob* blob = BufferBlob::create("CodeCache Exception Handler", sizeof(DynamicCodeData)); CodeBuffer cb(blob); MacroAssembler* masm = new MacroAssembler(&cb); diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 6da63245335..79fc67876b3 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -257,6 +257,7 @@ static ObsoleteFlag obsolete_jvm_flags[] = { { "MaxPermHeapExpansion", JDK_Version::jdk(8), JDK_Version::jdk(9) }, { "CMSRevisitStackSize", JDK_Version::jdk(8), JDK_Version::jdk(9) }, { "PrintRevisitStats", JDK_Version::jdk(8), JDK_Version::jdk(9) }, + { "UseVectoredExceptions", JDK_Version::jdk(8), JDK_Version::jdk(9) }, #ifdef PRODUCT { "DesiredMethodLimit", JDK_Version::jdk_update(7, 2), JDK_Version::jdk(8) }, diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index e783883ebe0..ad48aa1ae24 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -851,9 +851,6 @@ class CommandLineFlags { develop(bool, BreakAtWarning, false, \ "Execute breakpoint upon encountering VM warning") \ \ - product_pd(bool, UseVectoredExceptions, \ - "Temp Flag - Use Vectored Exceptions rather than SEH (Windows Only)") \ - \ develop(bool, TraceVMOperation, false, \ "Trace vm operations") \ \ From 4e5ebae2d3065904a4c06285ddb3675991f22cef Mon Sep 17 00:00:00 2001 From: Harold Seigel Date: Thu, 25 Oct 2012 16:33:40 -0400 Subject: [PATCH 11/59] 7191817: -XX:+UseSerialGC -XX:+UseLargePages crashes with SIGFPE on MacOS X Disable -XX:+UseLargePages for MacOS X Reviewed-by: dholmes, coleenp, sla --- hotspot/src/share/vm/runtime/arguments.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 79fc67876b3..d27bf0ef47d 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -2569,7 +2569,9 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, FLAG_SET_CMDLINE(uintx, MaxNewSize, NewSize); } +#ifndef _ALLBSD_SOURCE // UseLargePages is not yet supported on BSD. FLAG_SET_DEFAULT(UseLargePages, true); +#endif // Increase some data structure sizes for efficiency FLAG_SET_CMDLINE(uintx, BaseFootPrintEstimate, MaxHeapSize); @@ -3134,6 +3136,10 @@ jint Arguments::parse(const JavaVMInitArgs* args) { UNSUPPORTED_OPTION(UseG1GC, "G1 GC"); #endif +#ifdef _ALLBSD_SOURCE // UseLargePages is not yet supported on BSD. + UNSUPPORTED_OPTION(UseLargePages, "-XX:+UseLargePages"); +#endif + #if !INCLUDE_ALTERNATE_GCS if (UseParallelGC) { warning("Parallel GC is not supported in this VM. Using Serial GC."); From 07f94ef8bc8eee8c827e20fa3bfad977a2c5b252 Mon Sep 17 00:00:00 2001 From: Jim Gish Date: Thu, 25 Oct 2012 15:04:09 -0700 Subject: [PATCH 12/59] 7159567: inconsistent configuration of MemoryHandler Reviewed-by: mchung, alanb --- .../java/util/logging/ConsoleHandler.java | 35 ++-- .../java/util/logging/FileHandler.java | 61 ++++--- .../java/util/logging/MemoryHandler.java | 65 +++++--- .../java/util/logging/SocketHandler.java | 42 +++-- .../java/util/logging/StreamHandler.java | 36 ++-- .../java/util/logging/MemoryHandlerTest.java | 156 ++++++++++++++++++ .../java/util/logging/MemoryHandlerTest.props | 9 + 7 files changed, 321 insertions(+), 83 deletions(-) create mode 100644 jdk/test/java/util/logging/MemoryHandlerTest.java create mode 100644 jdk/test/java/util/logging/MemoryHandlerTest.props diff --git a/jdk/src/share/classes/java/util/logging/ConsoleHandler.java b/jdk/src/share/classes/java/util/logging/ConsoleHandler.java index 8cbff20010b..e0e70a5e689 100644 --- a/jdk/src/share/classes/java/util/logging/ConsoleHandler.java +++ b/jdk/src/share/classes/java/util/logging/ConsoleHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. * 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,26 +35,39 @@ import java.net.*; *

* Configuration: * By default each ConsoleHandler is initialized using the following - * LogManager configuration properties. If properties are not defined + * LogManager configuration properties where + * refers to the fully-qualified class name of the handler. + * If properties are not defined * (or have invalid values) then the specified default values are used. *

    - *
  • java.util.logging.ConsoleHandler.level + *
  • <handler-name>.level * specifies the default level for the Handler - * (defaults to Level.INFO). - *
  • java.util.logging.ConsoleHandler.filter + * (defaults to Level.INFO).
  • + *
  • <handler-name>.filter * specifies the name of a Filter class to use - * (defaults to no Filter). - *
  • java.util.logging.ConsoleHandler.formatter + * (defaults to no Filter).
  • + *
  • <handler-name>.formatter * specifies the name of a Formatter class to use - * (defaults to java.util.logging.SimpleFormatter). - *
  • java.util.logging.ConsoleHandler.encoding + * (defaults to java.util.logging.SimpleFormatter).
  • + *
  • <handler-name>.encoding * the name of the character set encoding to use (defaults to - * the default platform encoding). + * the default platform encoding).
  • + *
+ *

+ * For example, the properties for {@code ConsoleHandler} would be: + *

    + *
  • java.util.logging.ConsoleHandler.level=INFO
  • + *
  • java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
  • + *
+ *

+ * For a custom handler, e.g. com.foo.MyHandler, the properties would be: + *

    + *
  • com.foo.MyHandler.level=INFO
  • + *
  • com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter
  • *
*

* @since 1.4 */ - public class ConsoleHandler extends StreamHandler { // Private method to configure a ConsoleHandler from LogManager // properties and/or default values as specified in the class diff --git a/jdk/src/share/classes/java/util/logging/FileHandler.java b/jdk/src/share/classes/java/util/logging/FileHandler.java index fb3b67c4d92..4602fb5654f 100644 --- a/jdk/src/share/classes/java/util/logging/FileHandler.java +++ b/jdk/src/share/classes/java/util/logging/FileHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. * 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,45 +48,58 @@ import java.security.*; *

* Configuration: * By default each FileHandler is initialized using the following - * LogManager configuration properties. If properties are not defined + * LogManager configuration properties where <handler-name> + * refers to the fully-qualified class name of the handler. + * If properties are not defined * (or have invalid values) then the specified default values are used. *

    - *
  • java.util.logging.FileHandler.level + *
  • <handler-name>.level * specifies the default level for the Handler - * (defaults to Level.ALL). - *
  • java.util.logging.FileHandler.filter + * (defaults to Level.ALL).
  • + *
  • <handler-name>.filter * specifies the name of a Filter class to use - * (defaults to no Filter). - *
  • java.util.logging.FileHandler.formatter + * (defaults to no Filter).
  • + *
  • <handler-name>.formatter * specifies the name of a Formatter class to use - * (defaults to java.util.logging.XMLFormatter) - *
  • java.util.logging.FileHandler.encoding + * (defaults to java.util.logging.XMLFormatter)
  • + *
  • <handler-name>.encoding * the name of the character set encoding to use (defaults to - * the default platform encoding). - *
  • java.util.logging.FileHandler.limit + * the default platform encoding).
  • + *
  • <handler-name>.limit * specifies an approximate maximum amount to write (in bytes) * to any one file. If this is zero, then there is no limit. - * (Defaults to no limit). - *
  • java.util.logging.FileHandler.count - * specifies how many output files to cycle through (defaults to 1). - *
  • java.util.logging.FileHandler.pattern + * (Defaults to no limit).
  • + *
  • <handler-name>.count + * specifies how many output files to cycle through (defaults to 1).
  • + *
  • <handler-name>.pattern * specifies a pattern for generating the output file name. See - * below for details. (Defaults to "%h/java%u.log"). - *
  • java.util.logging.FileHandler.append + * below for details. (Defaults to "%h/java%u.log").
  • + *
  • <handler-name>.append * specifies whether the FileHandler should append onto - * any existing files (defaults to false). + * any existing files (defaults to false).
  • *
*

+ * For example, the properties for {@code FileHandler} would be: + *

    + *
  • java.util.logging.FileHandler.level=INFO
  • + *
  • java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
  • + *
+ *

+ * For a custom handler, e.g. com.foo.MyHandler, the properties would be: + *

    + *
  • com.foo.MyHandler.level=INFO
  • + *
  • com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter
  • + *
*

* A pattern consists of a string that includes the following special * components that will be replaced at runtime: *

    - *
  • "/" the local pathname separator - *
  • "%t" the system temporary directory - *
  • "%h" the value of the "user.home" system property - *
  • "%g" the generation number to distinguish rotated logs - *
  • "%u" a unique number to resolve conflicts - *
  • "%%" translates to a single percent sign "%" + *
  • "/" the local pathname separator
  • + *
  • "%t" the system temporary directory
  • + *
  • "%h" the value of the "user.home" system property
  • + *
  • "%g" the generation number to distinguish rotated logs
  • + *
  • "%u" a unique number to resolve conflicts
  • + *
  • "%%" translates to a single percent sign "%"
  • *
* If no "%g" field has been specified and the file count is greater * than one, then the generation number will be added to the end of diff --git a/jdk/src/share/classes/java/util/logging/MemoryHandler.java b/jdk/src/share/classes/java/util/logging/MemoryHandler.java index 2c297301d92..df6382eb286 100644 --- a/jdk/src/share/classes/java/util/logging/MemoryHandler.java +++ b/jdk/src/share/classes/java/util/logging/MemoryHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,36 +39,50 @@ package java.util.logging; *
    *
  • * An incoming LogRecord has a type that is greater than - * a pre-defined level, the pushLevel. + * a pre-defined level, the pushLevel.
  • *
  • - * An external class calls the push method explicitly. + * An external class calls the push method explicitly.
  • *
  • * A subclass overrides the log method and scans each incoming * LogRecord and calls push if a record matches some - * desired criteria. + * desired criteria.
  • *
*

* Configuration: * By default each MemoryHandler is initialized using the following - * LogManager configuration properties. If properties are not defined + * LogManager configuration properties where <handler-name> + * refers to the fully-qualified class name of the handler. + * If properties are not defined * (or have invalid values) then the specified default values are used. * If no default value is defined then a RuntimeException is thrown. *

    - *
  • java.util.logging.MemoryHandler.level + *
  • <handler-name>.level * specifies the level for the Handler - * (defaults to Level.ALL). - *
  • java.util.logging.MemoryHandler.filter + * (defaults to Level.ALL).
  • + *
  • <handler-name>.filter * specifies the name of a Filter class to use - * (defaults to no Filter). - *
  • java.util.logging.MemoryHandler.size - * defines the buffer size (defaults to 1000). - *
  • java.util.logging.MemoryHandler.push - * defines the pushLevel (defaults to level.SEVERE). - *
  • java.util.logging.MemoryHandler.target + * (defaults to no Filter).
  • + *
  • <handler-name>.size + * defines the buffer size (defaults to 1000).
  • + *
  • <handler-name>.push + * defines the pushLevel (defaults to level.SEVERE).
  • + *
  • <handler-name>.target * specifies the name of the target Handler class. - * (no default). + * (no default).
  • *
- * + *

+ * For example, the properties for {@code MemoryHandler} would be: + *

    + *
  • java.util.logging.MemoryHandler.level=INFO
  • + *
  • java.util.logging.MemoryHandler.formatter=java.util.logging.SimpleFormatter
  • + *
+ *

+ * For a custom handler, e.g. com.foo.MyHandler, the properties would be: + *

    + *
  • com.foo.MyHandler.level=INFO
  • + *
  • com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter
  • + *
+ *

* @since 1.4 */ @@ -80,7 +94,7 @@ public class MemoryHandler extends Handler { private LogRecord buffer[]; int start, count; - // Private method to configure a ConsoleHandler from LogManager + // Private method to configure a MemoryHandler from LogManager // properties and/or default values as specified in the class // javadoc. private void configure() { @@ -106,14 +120,19 @@ public class MemoryHandler extends Handler { configure(); sealed = true; - String name = "???"; + LogManager manager = LogManager.getLogManager(); + String handlerName = getClass().getName(); + String targetName = manager.getProperty(handlerName+".target"); + if (targetName == null) { + throw new RuntimeException("The handler " + handlerName + + " does not specify a target"); + } + Class clz; try { - LogManager manager = LogManager.getLogManager(); - name = manager.getProperty("java.util.logging.MemoryHandler.target"); - Class clz = ClassLoader.getSystemClassLoader().loadClass(name); + clz = ClassLoader.getSystemClassLoader().loadClass(targetName); target = (Handler) clz.newInstance(); - } catch (Exception ex) { - throw new RuntimeException("MemoryHandler can't load handler \"" + name + "\"" , ex); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { + throw new RuntimeException("MemoryHandler can't load handler target \"" + targetName + "\"" , e); } init(); } diff --git a/jdk/src/share/classes/java/util/logging/SocketHandler.java b/jdk/src/share/classes/java/util/logging/SocketHandler.java index f2e796d61a4..d7f2f31adbd 100644 --- a/jdk/src/share/classes/java/util/logging/SocketHandler.java +++ b/jdk/src/share/classes/java/util/logging/SocketHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. * 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,25 +37,39 @@ import java.net.*; *

* Configuration: * By default each SocketHandler is initialized using the following - * LogManager configuration properties. If properties are not defined + * LogManager configuration properties where <handler-name> + * refers to the fully-qualified class name of the handler. + * If properties are not defined * (or have invalid values) then the specified default values are used. *

    - *
  • java.util.logging.SocketHandler.level + *
  • <handler-name>.level * specifies the default level for the Handler - * (defaults to Level.ALL). - *
  • java.util.logging.SocketHandler.filter + * (defaults to Level.ALL).
  • + *
  • <handler-name>.filter * specifies the name of a Filter class to use - * (defaults to no Filter). - *
  • java.util.logging.SocketHandler.formatter + * (defaults to no Filter).
  • + *
  • <handler-name>.formatter * specifies the name of a Formatter class to use - * (defaults to java.util.logging.XMLFormatter). - *
  • java.util.logging.SocketHandler.encoding + * (defaults to java.util.logging.XMLFormatter).
  • + *
  • <handler-name>.encoding * the name of the character set encoding to use (defaults to - * the default platform encoding). - *
  • java.util.logging.SocketHandler.host - * specifies the target host name to connect to (no default). - *
  • java.util.logging.SocketHandler.port - * specifies the target TCP port to use (no default). + * the default platform encoding).
  • + *
  • <handler-name>.host + * specifies the target host name to connect to (no default).
  • + *
  • <handler-name>.port + * specifies the target TCP port to use (no default).
  • + *
+ *

+ * For example, the properties for {@code SocketHandler} would be: + *

    + *
  • java.util.logging.SocketHandler.level=INFO
  • + *
  • java.util.logging.SocketHandler.formatter=java.util.logging.SimpleFormatter
  • + *
+ *

+ * For a custom handler, e.g. com.foo.MyHandler, the properties would be: + *

    + *
  • com.foo.MyHandler.level=INFO
  • + *
  • com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter
  • *
*

* The output IO stream is buffered, but is flushed after each diff --git a/jdk/src/share/classes/java/util/logging/StreamHandler.java b/jdk/src/share/classes/java/util/logging/StreamHandler.java index 9ed9e57b768..a8b74c422cd 100644 --- a/jdk/src/share/classes/java/util/logging/StreamHandler.java +++ b/jdk/src/share/classes/java/util/logging/StreamHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,23 +38,37 @@ import java.io.*; *

* Configuration: * By default each StreamHandler is initialized using the following - * LogManager configuration properties. If properties are not defined + * LogManager configuration properties where <handler-name> + * refers to the fully-qualified class name of the handler. + * If properties are not defined * (or have invalid values) then the specified default values are used. *

    - *
  • java.util.logging.StreamHandler.level + *
  • <handler-name>.level * specifies the default level for the Handler - * (defaults to Level.INFO). - *
  • java.util.logging.StreamHandler.filter + * (defaults to Level.INFO).
  • + *
  • <handler-name>.filter * specifies the name of a Filter class to use - * (defaults to no Filter). - *
  • java.util.logging.StreamHandler.formatter + * (defaults to no Filter).
  • + *
  • <handler-name>.formatter * specifies the name of a Formatter class to use - * (defaults to java.util.logging.SimpleFormatter). - *
  • java.util.logging.StreamHandler.encoding + * (defaults to java.util.logging.SimpleFormatter).
  • + *
  • <handler-name>.encoding * the name of the character set encoding to use (defaults to - * the default platform encoding). + * the default platform encoding).
  • *
- * + *

+ * For example, the properties for {@code StreamHandler} would be: + *

    + *
  • java.util.logging.StreamHandler.level=INFO
  • + *
  • java.util.logging.StreamHandler.formatter=java.util.logging.SimpleFormatter
  • + *
+ *

+ * For a custom handler, e.g. com.foo.MyHandler, the properties would be: + *

    + *
  • com.foo.MyHandler.level=INFO
  • + *
  • com.foo.MyHandler.formatter=java.util.logging.SimpleFormatter
  • + *
+ *

* @since 1.4 */ diff --git a/jdk/test/java/util/logging/MemoryHandlerTest.java b/jdk/test/java/util/logging/MemoryHandlerTest.java new file mode 100644 index 00000000000..026e571859f --- /dev/null +++ b/jdk/test/java/util/logging/MemoryHandlerTest.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 7159567 + * @summary Test of configuring a MemoryHandler sub-class handler target via logging.properties + * @run main/othervm MemoryHandlerTest + */ +import java.io.File; +import java.io.IOException; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogManager; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +import java.util.logging.MemoryHandler; + +public class MemoryHandlerTest { + + static final String CFG_FILE_PROP = "java.util.logging.config.file"; + static final String LM_PROP_FNAME = "MemoryHandlerTest.props"; + static Logger logger; + + public static void main(String... args) throws IOException { + // load logging.propertes for the test + String tstSrc = System.getProperty("test.src", "."); + File fname = new File(tstSrc, LM_PROP_FNAME); + String prop = fname.getCanonicalPath(); + System.setProperty(CFG_FILE_PROP, prop); + LogManager logMgr = LogManager.getLogManager(); + // create a logger + logger = Logger.getLogger(MemoryHandlerTest.class.getName()); + // don't have parent handlers get log messages + logger.setUseParentHandlers(false); + // + // Test 1,2: create a CustomMemoryHandler which in the config has + // specified a target of CustomTargetHandler. (1) Make sure that it + // is created and (2) that the target handler is loaded. + // + CustomMemoryHandler cmh = new CustomMemoryHandler(); + try { + logger.addHandler(cmh); + } catch (RuntimeException rte) { + throw new RuntimeException( + "Test Failed: did not load java.util.logging.ConsoleHandler as expected", + rte); + } + // if we get here and our config has been processed properly, then we + // should have loaded our target handler + if (CustomTargetHandler.numLoaded !=1) { + throw new RuntimeException( + "Test failed: did not load CustomTargetHandler as expected"); + } + // + // Test 3: try to add a handler with no target. This should fail with + // an exception + CustomMemoryHandlerNoTarget cmhnt = null; + try { + cmhnt = new CustomMemoryHandlerNoTarget(); + } catch (RuntimeException re) { + // expected -- no target specified + System.out.println("Info: " + re.getMessage() + " as expected."); + } + if (cmhnt != null) { + throw new RuntimeException( + "Test Failed: erroneously loaded CustomMemoryHandlerNoTarget"); + } + + // Test 4: log a message and check that the target handler is actually used + logger.log(Level.WARNING, "Unused"); + if (CustomTargetHandler.numPublished != 1) { + throw new RuntimeException("Test failed: CustomTargetHandler was not used"); + } + + // Test 5: make sure that SimpleTargetHandler hasn't been erroneously called + if (SimpleTargetHandler.numPublished != 0) { + throw new RuntimeException("Test failed: SimpleTargetHandler has been used"); + } + + // Test 6: try using SimpleTargetHanlder via standard MemoryHandler + // (which has target set to SimpleTargetHandler) + MemoryHandler mh = new MemoryHandler(); + mh.publish(new LogRecord(Level.INFO, "Unused msg to MemoryHandler")); + // see if it made it to the SimpleTargetHandler + if (SimpleTargetHandler.numPublished != 1) { + throw new RuntimeException("Test failed: SimpleTargetHandler was not used"); + } + } + + public static class CustomMemoryHandler extends MemoryHandler { + } + + public static class CustomMemoryHandlerNoTarget extends MemoryHandler { + } + + public static class CustomTargetHandler extends Handler { + + public static int numPublished; + public static int numLoaded; + + public CustomTargetHandler() { + numLoaded++; + } + + @Override + public void publish(LogRecord unused) { + numPublished++; + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + } + } + + public static class SimpleTargetHandler extends Handler { + public static int numPublished; + + @Override + public void publish(LogRecord unused) { + numPublished++; + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + } + } +} diff --git a/jdk/test/java/util/logging/MemoryHandlerTest.props b/jdk/test/java/util/logging/MemoryHandlerTest.props new file mode 100644 index 00000000000..4860569ebbc --- /dev/null +++ b/jdk/test/java/util/logging/MemoryHandlerTest.props @@ -0,0 +1,9 @@ +.level= INFO +MemoryHandlerTest$CustomMemoryHandler.push=WARNING +MemoryHandlerTest$CustomMemoryHandlerNoTarget.push=WARNING +MemoryHandlerTest$CustomMemoryHandler.target=MemoryHandlerTest$CustomTargetHandler +handlers=java.util.logging.ConsoleHandler,MemoryHandlerTest$CustomMemoryHandler,MemoryHandlerTest$CustomMemoryHandlerNoTarget +java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter +java.util.logging.ConsoleHandler.level = INFO +java.util.logging.MemoryHandler.target=MemoryHandlerTest$SimpleTargetHandler +java.util.logging.MemoryHandler.push = INFO From 78aeafc1a2dca303f39987b1ba08de95e35f7028 Mon Sep 17 00:00:00 2001 From: Dan Xu Date: Thu, 25 Oct 2012 15:42:49 -0700 Subject: [PATCH 13/59] 8001565: (fs) Typo Path.endsWith(String) javadoc Reviewed-by: mchung, jgish, lancea --- jdk/src/share/classes/java/nio/file/Path.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/src/share/classes/java/nio/file/Path.java b/jdk/src/share/classes/java/nio/file/Path.java index eec1e631c35..a7933a34815 100644 --- a/jdk/src/share/classes/java/nio/file/Path.java +++ b/jdk/src/share/classes/java/nio/file/Path.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -297,7 +297,7 @@ public interface Path * @param other * the given path string * - * @return {@code true} if this path starts with the given path; otherwise + * @return {@code true} if this path ends with the given path; otherwise * {@code false} * * @throws InvalidPathException From 020472d122136a64f800ba84e1d6a49e499dac72 Mon Sep 17 00:00:00 2001 From: Robert Field Date: Thu, 25 Oct 2012 17:34:24 -0700 Subject: [PATCH 14/59] 8000806: Implement runtime lambda metafactory Implement lambda invokedynamic bootstrap by generating at runtime an inner class that implements the functional interface Reviewed-by: twisti --- .../AbstractValidatingLambdaMetafactory.java | 376 ++++++++++++++++ .../invoke/InnerClassLambdaMetafactory.java | 402 ++++++++++++++++++ .../invoke/LambdaConversionException.java | 50 +++ .../java/lang/invoke/LambdaMetafactory.java | 178 ++++++++ .../java/lang/invoke/MagicLambdaImpl.java | 39 ++ .../invoke/TypeConvertingMethodAdapter.java | 267 ++++++++++++ 6 files changed, 1312 insertions(+) create mode 100644 jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java create mode 100644 jdk/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java create mode 100644 jdk/src/share/classes/java/lang/invoke/LambdaConversionException.java create mode 100644 jdk/src/share/classes/java/lang/invoke/LambdaMetafactory.java create mode 100644 jdk/src/share/classes/java/lang/invoke/MagicLambdaImpl.java create mode 100644 jdk/src/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java diff --git a/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java b/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java new file mode 100644 index 00000000000..516443dc186 --- /dev/null +++ b/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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.lang.invoke; + +import java.io.Serializable; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import sun.invoke.util.Wrapper; +import static sun.invoke.util.Wrapper.*; + +/** + * Abstract implementation of a meta-factory which provides parameter unrolling and input validation. + * + * @author Robert Field + */ +/*non-public*/ abstract class AbstractValidatingLambdaMetafactory { + + /* + * For context, the comments for the following fields are marked in quotes with their values, given this program: + * interface II { Object foo(T x); } + * interface JJ extends II { } + * class CC { String impl(int i) { return "impl:"+i; }} + * class X { + * public static void main(String[] args) { + * JJ iii = (new CC())::impl; + * System.out.printf(">>> %s\n", iii.foo(44)); + * }} + */ + final Class targetClass; // The class calling the meta-factory via invokedynamic "class X" + final MethodType invokedType; // The type of the invoked method "(CC)II" + final Class samBase; // The type of the returned instance "interface JJ" + final boolean isSerializable; // Should the returned instance be serializable + final MethodHandleInfo samInfo; // Info about the SAM method handle "MethodHandleInfo[9 II.foo(Object)Object]" + final Class samClass; // Interface containing the SAM method "interface II" + final MethodType samMethodType; // Type of the SAM method "(Object)Object" + final MethodHandleInfo implInfo; // Info about the implementation method handle "MethodHandleInfo[5 CC.impl(int)String]" + final int implKind; // Invocation kind for implementation "5"=invokevirtual + final boolean implIsInstanceMethod; // Is the implementation an instance method "true" + final Class implDefiningClass; // Type defining the implementation "class CC" + final MethodType implMethodType; // Type of the implementation method "(int)String" + final MethodType instantiatedMethodType; // Instantiated erased functional interface method type "(Integer)Object" + + + /** + * Meta-factory constructor. + * + * @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges + * of the caller. + * @param invokedType Stacked automatically by VM; the signature of the invoked method, which includes the + * expected static type of the returned lambda object, and the static types of the captured + * arguments for the lambda. In the event that the implementation method is an instance method, + * the first argument in the invocation signature will correspond to the receiver. + * @param samMethod The primary method in the functional interface to which the lambda or method reference is + * being converted, represented as a method handle. + * @param implMethod The implementation method which should be called (with suitable adaptation of argument + * types, return types, and adjustment for captured arguments) when methods of the resulting + * functional interface instance are invoked. + * @param instantiatedMethodType The signature of the SAM method from the functional interface's perspective + * @throws ReflectiveOperationException + */ + AbstractValidatingLambdaMetafactory(MethodHandles.Lookup caller, + MethodType invokedType, + MethodHandle samMethod, + MethodHandle implMethod, + MethodType instantiatedMethodType) + throws ReflectiveOperationException { + this.targetClass = caller.lookupClass(); + this.invokedType = invokedType; + + this.samBase = invokedType.returnType(); + this.isSerializable = Serializable.class.isAssignableFrom(samBase); + + this.samInfo = new MethodHandleInfo(samMethod); + this.samClass = samInfo.getDeclaringClass(); + this.samMethodType = samInfo.getMethodType(); + + this.implInfo = new MethodHandleInfo(implMethod); + this.implKind = implInfo.getReferenceKind() == MethodHandleInfo.REF_invokeSpecial? MethodHandleInfo.REF_invokeVirtual : implInfo.getReferenceKind(); // @@@ Temp work-around to hotspot incorrectly converting to invokespecial + this.implIsInstanceMethod = + implKind == MethodHandleInfo.REF_invokeVirtual || + implKind == MethodHandleInfo.REF_invokeSpecial || + implKind == MethodHandleInfo.REF_invokeInterface; + this.implDefiningClass = implInfo.getDeclaringClass(); + this.implMethodType = implInfo.getMethodType(); + + this.instantiatedMethodType = instantiatedMethodType; + } + + /** + * Build the CallSite. + * + * @return a CallSite, which, when invoked, will return an instance of the + * functional interface + * @throws ReflectiveOperationException + */ + abstract CallSite buildCallSite() throws ReflectiveOperationException, LambdaConversionException; + + /** + * Check the meta-factory arguments for errors + * @throws LambdaConversionException if there are improper conversions + */ + void validateMetafactoryArgs() throws LambdaConversionException { + // Check target type is a subtype of class where SAM method is defined + if (!samClass.isAssignableFrom(samBase)) { + throw new LambdaConversionException(String.format("Invalid target type %s for lambda conversion; not a subtype of functional interface %s", + samBase.getName(), samClass.getName())); + } + + switch (implKind) { + case MethodHandleInfo.REF_invokeInterface: + case MethodHandleInfo.REF_invokeVirtual: + case MethodHandleInfo.REF_invokeStatic: + case MethodHandleInfo.REF_newInvokeSpecial: + case MethodHandleInfo.REF_invokeSpecial: + break; + default: + throw new LambdaConversionException(String.format("Unsupported MethodHandle kind: %s", implInfo)); + } + + // Check arity: optional-receiver + captured + SAM == impl + final int implArity = implMethodType.parameterCount(); + final int receiverArity = implIsInstanceMethod ? 1 : 0; + final int capturedArity = invokedType.parameterCount(); + final int samArity = samMethodType.parameterCount(); + final int instantiatedArity = instantiatedMethodType.parameterCount(); + if (implArity + receiverArity != capturedArity + samArity) { + throw new LambdaConversionException(String.format("Incorrect number of parameters for %s method %s; %d captured parameters, %d functional interface parameters, %d implementation parameters", + implIsInstanceMethod ? "instance" : "static", implInfo, + capturedArity, samArity, implArity)); + } + if (instantiatedArity != samArity) { + throw new LambdaConversionException(String.format("Incorrect number of parameters for %s method %s; %d functional interface parameters, %d SAM method parameters", + implIsInstanceMethod ? "instance" : "static", implInfo, + instantiatedArity, samArity)); + } + + // If instance: first captured arg (receiver) must be subtype of class where impl method is defined + final int capturedStart; + final int samStart; + if (implIsInstanceMethod) { + final Class receiverClass; + + // implementation is an instance method, adjust for receiver in captured variables / SAM arguments + if (capturedArity == 0) { + // receiver is function parameter + capturedStart = 0; + samStart = 1; + receiverClass = instantiatedMethodType.parameterType(0); + } else { + // receiver is a captured variable + capturedStart = 1; + samStart = 0; + receiverClass = invokedType.parameterType(0); + } + + // check receiver type + if (!implDefiningClass.isAssignableFrom(receiverClass)) { + throw new LambdaConversionException(String.format("Invalid receiver type %s; not a subtype of implementation type %s", + receiverClass, implDefiningClass)); + } + } else { + // no receiver + capturedStart = 0; + samStart = 0; + } + + // Check for exact match on non-receiver captured arguments + final int implFromCaptured = capturedArity - capturedStart; + for (int i=0; i implParamType = implMethodType.parameterType(i); + Class capturedParamType = invokedType.parameterType(i + capturedStart); + if (!capturedParamType.equals(implParamType)) { + throw new LambdaConversionException( + String.format("Type mismatch in captured lambda parameter %d: expecting %s, found %s", i, capturedParamType, implParamType)); + } + } + // Check for adaptation match on SAM arguments + final int samOffset = samStart - implFromCaptured; + for (int i=implFromCaptured; i implParamType = implMethodType.parameterType(i); + Class instantiatedParamType = instantiatedMethodType.parameterType(i + samOffset); + if (!isAdaptableTo(instantiatedParamType, implParamType, true)) { + throw new LambdaConversionException( + String.format("Type mismatch for lambda argument %d: %s is not convertible to %s", i, instantiatedParamType, implParamType)); + } + } + + // Adaptation match: return type + Class expectedType = instantiatedMethodType.returnType(); + Class actualReturnType = + (implKind == MethodHandleInfo.REF_newInvokeSpecial) + ? implDefiningClass + : implMethodType.returnType(); + if (!isAdaptableToAsReturn(actualReturnType, expectedType)) { + throw new LambdaConversionException( + String.format("Type mismatch for lambda return: %s is not convertible to %s", actualReturnType, expectedType)); + } + } + + /** + * Check type adaptability + * @param fromType + * @param toType + * @param strict If true, do strict checks, else allow that fromType may be parameterized + * @return True if 'fromType' can be passed to an argument of 'toType' + */ + private boolean isAdaptableTo(Class fromType, Class toType, boolean strict) { + if (fromType.equals(toType)) { + return true; + } + if (fromType.isPrimitive()) { + Wrapper wfrom = forPrimitiveType(fromType); + if (toType.isPrimitive()) { + // both are primitive: widening + Wrapper wto = forPrimitiveType(toType); + return wto.isConvertibleFrom(wfrom); + } else { + // from primitive to reference: boxing + return toType.isAssignableFrom(wfrom.wrapperType()); + } + } else { + if (toType.isPrimitive()) { + // from reference to primitive: unboxing + Wrapper wfrom; + if (isWrapperType(fromType) && (wfrom = forWrapperType(fromType)).primitiveType().isPrimitive()) { + // fromType is a primitive wrapper; unbox+widen + Wrapper wto = forPrimitiveType(toType); + return wto.isConvertibleFrom(wfrom); + } else { + // must be convertible to primitive + return !strict; + } + } else { + // both are reference types: fromType should be a superclass of toType. + return strict? toType.isAssignableFrom(fromType) : true; + } + } + } + + /** + * Check type adaptability for return types -- special handling of void type) and parameterized fromType + * @param fromType + * @param toType + * @return True if 'fromType' can be converted to 'toType' + */ + private boolean isAdaptableToAsReturn(Class fromType, Class toType) { + return toType.equals(void.class) + || !fromType.equals(void.class) && isAdaptableTo(fromType, toType, false); + } + + + /*********** Logging support -- for debugging only + static final Executor logPool = Executors.newSingleThreadExecutor(); // @@@ For debugging only + protected static void log(final String s) { + MethodHandleProxyLambdaMetafactory.logPool.execute(new Runnable() { + @Override + public void run() { + System.out.println(s); + } + }); + } + + protected static void log(final String s, final Throwable e) { + MethodHandleProxyLambdaMetafactory.logPool.execute(new Runnable() { + @Override + public void run() { + System.out.println(s); + e.printStackTrace(System.out); + } + }); + } + ***********************/ + + /** + * Find the SAM method and corresponding methods which should be bridged. SAM method and those to be bridged + * will have the same name and number of parameters. Check for matching default methods (non-abstract), they + * should not be bridged-over and indicate a complex bridging situation. + */ + class MethodAnalyzer { + private final Method[] methods = samBase.getMethods(); + private final List methodsFound = new ArrayList<>(methods.length); + + private Method samMethod = null; + private final List methodsToBridge = new ArrayList<>(methods.length); + private boolean defaultMethodFound = false; + + MethodAnalyzer() { + String samMethodName = samInfo.getName(); + Class[] samParamTypes = samMethodType.parameterArray(); + int samParamLength = samParamTypes.length; + Class samReturnType = samMethodType.returnType(); + Class objectClass = Object.class; + + for (Method m : methods) { + if (m.getName().equals(samMethodName) && m.getDeclaringClass() != objectClass) { + Class[] mParamTypes = m.getParameterTypes(); + if (mParamTypes.length == samParamLength) { + if (Modifier.isAbstract(m.getModifiers())) { + // Exclude methods with duplicate signatures + if (methodUnique(m)) { + if (m.getReturnType().equals(samReturnType) && Arrays.equals(mParamTypes, samParamTypes)) { + // Exact match, this is the SAM method signature + samMethod = m; + } else { + methodsToBridge.add(m); + } + } + } else { + // This is a default method, flag for special processing + defaultMethodFound = true; + // Ignore future matching abstracts. + // Note, due to reabstraction, this is really a punt, hence pass-off to VM + methodUnique(m); + } + } + } + } + } + + Method getSamMethod() { + return samMethod; + } + + List getMethodsToBridge() { + return methodsToBridge; + } + + boolean wasDefaultMethodFound() { + return defaultMethodFound; + } + + /** + * Search the list of previously found methods to determine if there is a method with the same signature + * (return and parameter types) as the specified method. If it wasn't found before, add to the found list. + * + * @param m The method to match + * @return False if the method was found, True otherwise + */ + private boolean methodUnique(Method m) { + Class[] ptypes = m.getParameterTypes(); + Class rtype = m.getReturnType(); + for (Method md : methodsFound) { + if (md.getReturnType().equals(rtype) && Arrays.equals(ptypes, md.getParameterTypes())) { + return false; + } + } + methodsFound.add(m); + return true; + } + } +} diff --git a/jdk/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java b/jdk/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java new file mode 100644 index 00000000000..d41a62d3952 --- /dev/null +++ b/jdk/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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.lang.invoke; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.reflect.Method; +import java.security.ProtectionDomain; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Level; +import java.util.logging.Logger; +import jdk.internal.org.objectweb.asm.*; +import static jdk.internal.org.objectweb.asm.Opcodes.*; +import sun.misc.Unsafe; + +/** + * InnerClassLambdaMetafactory + */ +/*non-public*/ final class InnerClassLambdaMetafactory extends AbstractValidatingLambdaMetafactory { + private static final int CLASSFILE_VERSION = 51; + private static final Type TYPE_VOID = Type.getType(void.class); + private static final String METHOD_DESCRIPTOR_VOID = Type.getMethodDescriptor(Type.VOID_TYPE); + private static final String NAME_MAGIC_ACCESSOR_IMPL = "java/lang/invoke/MagicLambdaImpl"; + private static final String NAME_SERIALIZABLE = "java/io/Serializable"; + private static final String NAME_CTOR = ""; + + //Serialization support + private static final String NAME_SERIALIZED_LAMBDA = "com/oracle/java/lang/invoke/SerializedLambdaImpl"; + private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;"; + private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace"; + private static final String NAME_OBJECT = "java/lang/Object"; + + // Used to ensure that each spun class name is unique + private static final AtomicInteger counter = new AtomicInteger(0); + + // See context values in AbstractValidatingLambdaMetafactory + private final String implMethodClassName; // Name of type containing implementation "CC" + private final String implMethodName; // Name of implementation method "impl" + private final String implMethodDesc; // Type descriptor for implementation methods "(I)Ljava/lang/String;" + private final Type[] implMethodArgumentTypes; // ASM types for implementaion method parameters + private final Type implMethodReturnType; // ASM type for implementaion method return type "Ljava/lang/String;" + private final MethodType constructorType; // Generated class constructor type "(CC)void" + private final String constructorDesc; // Type descriptor for constructor "(LCC;)V" + private final ClassWriter cw; // ASM class writer + private final Type[] argTypes; // ASM types for the constructor arguments + private final String[] argNames; // Generated names for the constructor arguments + private final String lambdaClassName; // Generated name for the generated class "X$$Lambda$1" + private final Type[] instantiatedArgumentTypes; // ASM types for the functional interface arguments + + /** + * Meta-factory constructor. + * + * @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges + * of the caller. + * @param invokedType Stacked automatically by VM; the signature of the invoked method, which includes the + * expected static type of the returned lambda object, and the static types of the captured + * arguments for the lambda. In the event that the implementation method is an instance method, + * the first argument in the invocation signature will correspond to the receiver. + * @param samMethod The primary method in the functional interface to which the lambda or method reference is + * being converted, represented as a method handle. + * @param implMethod The implementation method which should be called (with suitable adaptation of argument + * types, return types, and adjustment for captured arguments) when methods of the resulting + * functional interface instance are invoked. + * @param instantiatedMethodType The signature of the SAM method from the functional interface's perspective + * @throws ReflectiveOperationException + */ + public InnerClassLambdaMetafactory(MethodHandles.Lookup caller, + MethodType invokedType, + MethodHandle samMethod, + MethodHandle implMethod, + MethodType instantiatedMethodType) + throws ReflectiveOperationException { + super(caller, invokedType, samMethod, implMethod, instantiatedMethodType); + implMethodClassName = implDefiningClass.getName().replace('.', '/'); + implMethodName = implInfo.getName(); + implMethodDesc = implMethodType.toMethodDescriptorString(); + Type implMethodAsmType = Type.getMethodType(implMethodDesc); + implMethodArgumentTypes = implMethodAsmType.getArgumentTypes(); + implMethodReturnType = implMethodAsmType.getReturnType(); + constructorType = invokedType.changeReturnType(Void.TYPE); + constructorDesc = constructorType.toMethodDescriptorString(); + lambdaClassName = targetClass.getName().replace('.', '/') + "$$Lambda$" + counter.incrementAndGet(); + cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); + argTypes = Type.getArgumentTypes(constructorDesc); + argNames = new String[argTypes.length]; + for (int i = 0; i < argTypes.length; i++) { + argNames[i] = "arg$" + (i + 1); + } + instantiatedArgumentTypes = Type.getArgumentTypes(instantiatedMethodType.toMethodDescriptorString()); + + } + + /** + * Build the CallSite. Generate a class file which implements the functional + * interface, define the class, if there are no parameters create an instance + * of the class which the CallSite will return, otherwise, generate handles + * which will call the class' constructor. + * + * @return a CallSite, which, when invoked, will return an instance of the + * functional interface + * @throws ReflectiveOperationException + */ + @Override + CallSite buildCallSite() throws ReflectiveOperationException, LambdaConversionException { + final Class innerClass = spinInnerClass(); + if (invokedType.parameterCount() == 0) { + return new ConstantCallSite(MethodHandles.constant(samBase, innerClass.newInstance())); + } else { + return new ConstantCallSite( + MethodHandles.Lookup.IMPL_LOOKUP + .findConstructor(innerClass, constructorType) + .asType(constructorType.changeReturnType(samBase))); + } + } + + /** + * Generate a class file which implements the functional + * interface, define and return the class. + * + * @return a Class which implements the functional interface + */ + private Class spinInnerClass() throws LambdaConversionException { + String samName = samBase.getName().replace('.', '/'); + + cw.visit(CLASSFILE_VERSION, ACC_PUBLIC + ACC_SUPER, lambdaClassName, null, NAME_MAGIC_ACCESSOR_IMPL, + isSerializable ? new String[]{samName, NAME_SERIALIZABLE} : new String[]{samName}); + + // Generate final fields to be filled in by constructor + for (int i = 0; i < argTypes.length; i++) { + FieldVisitor fv = cw.visitField(ACC_PRIVATE + ACC_FINAL, argNames[i], argTypes[i].getDescriptor(), null, null); + fv.visitEnd(); + } + + generateConstructor(); + + MethodAnalyzer ma = new MethodAnalyzer(); + + // Forward the SAM method + if (ma.getSamMethod() == null) { + throw new LambdaConversionException(String.format("SAM method not found: %s", samMethodType)); + } else { + generateForwardingMethod(ma.getSamMethod(), false); + } + + // Forward the bridges + // @@@ Once the VM can do fail-over, uncomment the default method test + if (!ma.getMethodsToBridge().isEmpty() /* && !ma.wasDefaultMethodFound() */) { + for (Method m : ma.getMethodsToBridge()) { + generateForwardingMethod(m, true); + } + } + + /***** Serialization not yet supported + if (isSerializable) { + String samMethodName = samInfo.getName(); + Type samType = Type.getType(samBase); + generateSerializationMethod(samType, samMethodName); + } + ******/ + + cw.visitEnd(); + + // Define the generated class in this VM. + + final byte[] classBytes = cw.toByteArray(); + + if (System.getProperty("debug.dump.generated") != null) { + System.out.printf("Loaded: %s (%d bytes) %n", lambdaClassName, classBytes.length); + try (FileOutputStream fos = new FileOutputStream(lambdaClassName.replace('/', '.') + ".class")) { + fos.write(classBytes); + } catch (IOException ex) { + Logger.getLogger(InnerClassLambdaMetafactory.class.getName()).log(Level.SEVERE, null, ex); + } + } + + ClassLoader loader = targetClass.getClassLoader(); + ProtectionDomain pd = (loader == null) ? null : targetClass.getProtectionDomain(); + return (Class) Unsafe.getUnsafe().defineClass(lambdaClassName, classBytes, 0, classBytes.length, loader, pd); + } + + /** + * Generate the constructor for the class + */ + private void generateConstructor() { + // Generate constructor + MethodVisitor ctor = cw.visitMethod(ACC_PUBLIC, NAME_CTOR, constructorDesc, null, null); + ctor.visitCode(); + ctor.visitVarInsn(ALOAD, 0); + ctor.visitMethodInsn(INVOKESPECIAL, NAME_MAGIC_ACCESSOR_IMPL, NAME_CTOR, METHOD_DESCRIPTOR_VOID); + int lvIndex = 0; + for (int i = 0; i < argTypes.length; i++) { + ctor.visitVarInsn(ALOAD, 0); + ctor.visitVarInsn(argTypes[i].getOpcode(ILOAD), lvIndex + 1); + lvIndex += argTypes[i].getSize(); + ctor.visitFieldInsn(PUTFIELD, lambdaClassName, argNames[i], argTypes[i].getDescriptor()); + } + ctor.visitInsn(RETURN); + ctor.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored + ctor.visitEnd(); + } + + /** + * Generate the serialization method (if needed) + */ + /****** This code is out of date -- known to be wrong -- and not currently used ****** + private void generateSerializationMethod(Type samType, String samMethodName) { + String samMethodDesc = samMethodType.toMethodDescriptorString(); + TypeConvertingMethodAdapter mv = new TypeConvertingMethodAdapter(cw.visitMethod(ACC_PRIVATE + ACC_FINAL, NAME_METHOD_WRITE_REPLACE, DESCR_METHOD_WRITE_REPLACE, null, null)); + + mv.visitCode(); + mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA); + mv.dup(); + mv.visitLdcInsn(samType); + mv.visitLdcInsn(samMethodName); + mv.visitLdcInsn(samMethodDesc); + mv.visitLdcInsn(Type.getType(implDefiningClass)); + mv.visitLdcInsn(implMethodName); + mv.visitLdcInsn(implMethodDesc); + + mv.iconst(argTypes.length); + mv.visitTypeInsn(ANEWARRAY, NAME_OBJECT); + for (int i = 0; i < argTypes.length; i++) { + mv.dup(); + mv.iconst(i); + mv.visitVarInsn(ALOAD, 0); + mv.getfield(lambdaClassName, argNames[i], argTypes[i].getDescriptor()); + mv.boxIfPrimitive(argTypes[i]); + mv.visitInsn(AASTORE); + } + mv.invokespecial(NAME_SERIALIZED_LAMBDA, NAME_CTOR, + "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V"); + mv.visitInsn(ARETURN); + mv.visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored + mv.visitEnd(); + } + ********/ + + /** + * Generate a method which calls the lambda implementation method, + * converting arguments, as needed. + * @param m The method whose signature should be generated + * @param isBridge True if this methods should be flagged as a bridge + */ + private void generateForwardingMethod(Method m, boolean isBridge) { + Class[] exceptionTypes = m.getExceptionTypes(); + String[] exceptionNames = new String[exceptionTypes.length]; + for (int i = 0; i < exceptionTypes.length; i++) { + exceptionNames[i] = exceptionTypes[i].getName().replace('.', '/'); + } + String methodDescriptor = Type.getMethodDescriptor(m); + int access = isBridge? ACC_PUBLIC | ACC_BRIDGE : ACC_PUBLIC; + MethodVisitor mv = cw.visitMethod(access, m.getName(), methodDescriptor, null, exceptionNames); + new ForwardingMethodGenerator(mv).generate(m); + } + + /** + * This class generates a method body which calls the lambda implementation + * method, converting arguments, as needed. + */ + private class ForwardingMethodGenerator extends TypeConvertingMethodAdapter { + + ForwardingMethodGenerator(MethodVisitor mv) { + super(mv); + } + + void generate(Method m) throws InternalError { + visitCode(); + + if (implKind == MethodHandleInfo.REF_newInvokeSpecial) { + visitTypeInsn(NEW, implMethodClassName); + dup(); + } + for (int i = 0; i < argTypes.length; i++) { + visitVarInsn(ALOAD, 0); + getfield(lambdaClassName, argNames[i], argTypes[i].getDescriptor()); + } + + convertArgumentTypes(Type.getArgumentTypes(m)); + + // Invoke the method we want to forward to + visitMethodInsn(invocationOpcode(), implMethodClassName, implMethodName, implMethodDesc); + + // Convert the return value (if any) and return it + // Note: if adapting from non-void to void, the 'return' instruction will pop the unneeded result + Type samReturnType = Type.getReturnType(m); + convertType(implMethodReturnType, samReturnType, samReturnType); + areturn(samReturnType); + + visitMaxs(-1, -1); // Maxs computed by ClassWriter.COMPUTE_MAXS, these arguments ignored + visitEnd(); + } + + private void convertArgumentTypes(Type[] samArgumentTypes) { + int lvIndex = 0; + boolean samIncludesReceiver = implIsInstanceMethod && argTypes.length == 0; + int samReceiverLength = samIncludesReceiver ? 1 : 0; + if (samIncludesReceiver) { + // push receiver + Type rcvrType = samArgumentTypes[0]; + Type instantiatedRcvrType = instantiatedArgumentTypes[0]; + + load(lvIndex + 1, rcvrType); + lvIndex += rcvrType.getSize(); + convertType(rcvrType, Type.getType(implDefiningClass), instantiatedRcvrType); + } + int argOffset = implMethodArgumentTypes.length - samArgumentTypes.length; + for (int i = samReceiverLength; i < samArgumentTypes.length; i++) { + Type argType = samArgumentTypes[i]; + Type targetType = implMethodArgumentTypes[argOffset + i]; + Type instantiatedArgType = instantiatedArgumentTypes[i]; + + load(lvIndex + 1, argType); + lvIndex += argType.getSize(); + convertType(argType, targetType, instantiatedArgType); + } + } + + private void convertType(Type argType, Type targetType, Type functionalType) { + convertType(argType.getDescriptor(), targetType.getDescriptor(), functionalType.getDescriptor()); + } + + private int invocationOpcode() throws InternalError { + switch (implKind) { + case MethodHandleInfo.REF_invokeStatic: + return INVOKESTATIC; + case MethodHandleInfo.REF_newInvokeSpecial: + return INVOKESPECIAL; + case MethodHandleInfo.REF_invokeVirtual: + return INVOKEVIRTUAL; + case MethodHandleInfo.REF_invokeInterface: + return INVOKEINTERFACE; + case MethodHandleInfo.REF_invokeSpecial: + return INVOKESPECIAL; + default: + throw new InternalError("Unexpected invocation kind: " + implKind); + } + } + + /** + * The following methods are copied from + * org.objectweb.asm.commons.InstructionAdapter. Part of ASM: a very + * small and fast Java bytecode manipulation framework. Copyright (c) + * 2000-2005 INRIA, France Telecom All rights reserved. + * + * Subclass with that (removing these methods) if that package/class is + * ever added to the JDK. + */ + private void iconst(final int cst) { + if (cst >= -1 && cst <= 5) { + mv.visitInsn(Opcodes.ICONST_0 + cst); + } else if (cst >= Byte.MIN_VALUE && cst <= Byte.MAX_VALUE) { + mv.visitIntInsn(Opcodes.BIPUSH, cst); + } else if (cst >= Short.MIN_VALUE && cst <= Short.MAX_VALUE) { + mv.visitIntInsn(Opcodes.SIPUSH, cst); + } else { + mv.visitLdcInsn(cst); + } + } + + private void load(final int var, final Type type) { + mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), var); + } + + private void dup() { + mv.visitInsn(Opcodes.DUP); + } + + private void areturn(final Type t) { + mv.visitInsn(t.getOpcode(Opcodes.IRETURN)); + } + + private void getfield( + final String owner, + final String name, + final String desc) { + mv.visitFieldInsn(Opcodes.GETFIELD, owner, name, desc); + } + } +} diff --git a/jdk/src/share/classes/java/lang/invoke/LambdaConversionException.java b/jdk/src/share/classes/java/lang/invoke/LambdaConversionException.java new file mode 100644 index 00000000000..11ffb580ea9 --- /dev/null +++ b/jdk/src/share/classes/java/lang/invoke/LambdaConversionException.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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.lang.invoke; + +/** + * LambdaConversionException + */ +public class LambdaConversionException extends Exception { + public LambdaConversionException() { + } + + public LambdaConversionException(String message) { + super(message); + } + + public LambdaConversionException(String message, Throwable cause) { + super(message, cause); + } + + public LambdaConversionException(Throwable cause) { + super(cause); + } + + public LambdaConversionException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/jdk/src/share/classes/java/lang/invoke/LambdaMetafactory.java b/jdk/src/share/classes/java/lang/invoke/LambdaMetafactory.java new file mode 100644 index 00000000000..378494b48d3 --- /dev/null +++ b/jdk/src/share/classes/java/lang/invoke/LambdaMetafactory.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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.lang.invoke; + +/** + *

Bootstrap methods for converting lambda expressions and method references to functional interface objects.

+ * + *

For every lambda expressions or method reference in the source code, there is a target type which is a + * functional interface. Evaluating a lambda expression produces an object of its target type. The mechanism for + * evaluating lambda expressions is to invoke an invokedynamic call site, which takes arguments describing the sole + * method of the functional interface and the implementation method, and returns an object (the lambda object) that + * implements the target type. Methods of the lambda object invoke the implementation method. For method + * references, the implementation method is simply the referenced method; for lambda expressions, the + * implementation method is produced by the compiler based on the body of the lambda expression. The methods in + * this file are the bootstrap methods for those invokedynamic call sites, called lambda factories, and the + * bootstrap methods responsible for linking the lambda factories are called lambda meta-factories. + * + *

The bootstrap methods in this class take the information about the functional interface, the implementation + * method, and the static types of the captured lambda arguments, and link a call site which, when invoked, + * produces the lambda object. + * + *

Two pieces of information are needed about the functional interface: the SAM method and the type of the SAM + * method in the functional interface. The type can be different when parameterized types are used. For example, + * consider + * interface I<T> { int m(T x); } if this SAM type is used in a lambda + * I<Byte> v = ..., we need both the actual SAM method which has the signature + * (Object)int and the functional interface type of the method, which has signature + * (Byte)int. The latter is the instantiated erased functional interface method type, or + * simply instantiated method type. + * + *

While functional interfaces only have a single abstract method from the language perspective (concrete + * methods in Object are and default methods may be present), at the bytecode level they may actually have multiple + * methods because of the need for bridge methods. Invoking any of these methods on the lambda object will result + * in invoking the implementation method. + * + *

The argument list of the implementation method and the argument list of the functional interface method(s) + * may differ in several ways. The implementation methods may have additional arguments to accommodate arguments + * captured by the lambda expression; there may also be differences resulting from permitted adaptations of + * arguments, such as casting, boxing, unboxing, and primitive widening. They may also differ because of var-args, + * but this is expected to be handled by the compiler. + * + *

Invokedynamic call sites have two argument lists: a static argument list and a dynamic argument list. The + * static argument list lives in the constant pool; the dynamic argument list lives on the operand stack at + * invocation time. The bootstrap method has access to the entire static argument list (which in this case, + * contains method handles describing the implementation method and the canonical functional interface method), + * as well as a method signature describing the number and static types (but not the values) of the dynamic + * arguments, and the static return type of the invokedynamic site. + * + *

The implementation method is described with a method handle. In theory, any method handle could be used. + * Currently supported are method handles representing invocation of virtual, interface, constructor and static + * methods. + * + *

Assume: + *

    + *
  • the functional interface method has N arguments, of types (U1, U2, ... Un) and return type Ru
  • + *
  • then the instantiated method type also has N arguments, of types (T1, T2, ... Tn) and return type Rt
  • + *
  • the implementation method has M arguments, of types (A1..Am) and return type Ra,
  • + *
  • the dynamic argument list has K arguments of types (D1..Dk), and the invokedynamic return site has + * type Rd
  • + *
  • the functional interface type is F
  • + *
+ * + *

The following signature invariants must hold: + *

    + *
  • Rd is a subtype of F
  • + *
  • For i=1..N, Ti is a subtype of Ui
  • + *
  • Either Rt and Ru are primitive and are the same type, or both are reference types and + * Rt is a subtype of Ru
  • + *
  • If the implementation method is a static method: + *
      + *
    • K + N = M
    • + *
    • For i=1..K, Di = Ai
    • + *
    • For i=1..N, Ti is adaptable to Aj, where j=i+k
    • + *
  • + *
  • If the implementation method is an instance method: + *
      + *
    • K + N = M + 1
    • + *
    • D1 must be a subtype of the enclosing class for the implementation method
    • + *
    • For i=2..K, Di = Aj, where j=i-1
    • + *
    • For i=1..N, Ti is adaptable to Aj, where j=i+k-1
    • + *
  • + *
  • The return type Rt is void, or the return type Ra is not void and is adaptable to Rt
  • + *
+ * + *

Note that the potentially parameterized implementation return type provides the value for the SAM. Whereas + * the completely known instantiated return type is adapted to the implementation arguments. Because the + * instantiated type of the implementation method is not available, the adaptability of return types cannot be + * checked as precisely at link-time as the arguments can be checked. Thus a loose version of link-time checking is + * done on return type, while a strict version is applied to arguments. + * + *

A type Q is considered adaptable to S as follows: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
QSLink-time checksCapture-time checks
PrimitivePrimitiveQ can be converted to S via a primitive widening conversionNone
PrimitiveReferenceS is a supertype of the Wrapper(Q)Cast from Wrapper(Q) to S
ReferencePrimitivestrict: Q is a primitive wrapper and Primitive(Q) can be widened to S + *
loose: If Q is a primitive wrapper, check that Primitive(Q) can be widened to S
If Q is not a primitive wrapper, cast Q to the base Wrapper(S); for example Number for numeric types
ReferenceReferencestrict: S is a supertype of Q + *
loose: none
Cast from Q to S
+ * + * + */ +public class LambdaMetafactory { + + /** + * Standard meta-factory for conversion of lambda expressions or method references to functional interfaces. + * + * @param caller Stacked automatically by VM; represents a lookup context with the accessibility privileges + * of the caller. + * @param invokedName Stacked automatically by VM; the name of the invoked method as it appears at the call site. + * Currently unused. + * @param invokedType Stacked automatically by VM; the signature of the invoked method, which includes the + * expected static type of the returned lambda object, and the static types of the captured + * arguments for the lambda. In the event that the implementation method is an instance method, + * the first argument in the invocation signature will correspond to the receiver. + * @param samMethod The primary method in the functional interface to which the lambda or method reference is + * being converted, represented as a method handle. + * @param implMethod The implementation method which should be called (with suitable adaptation of argument + * types, return types, and adjustment for captured arguments) when methods of the resulting + * functional interface instance are invoked. + * @param instantiatedMethodType The signature of the SAM method from the functional interface's perspective + * @return a CallSite, which, when invoked, will return an instance of the functional interface + * @throws ReflectiveOperationException + * @throws LambdaConversionException If any of the meta-factory protocol invariants are violated + */ + public static CallSite metaFactory(MethodHandles.Lookup caller, + String invokedName, + MethodType invokedType, + MethodHandle samMethod, + MethodHandle implMethod, + MethodType instantiatedMethodType) + throws ReflectiveOperationException, LambdaConversionException { + AbstractValidatingLambdaMetafactory mf; + mf = new InnerClassLambdaMetafactory(caller, invokedType, samMethod, implMethod, instantiatedMethodType); + mf.validateMetafactoryArgs(); + return mf.buildCallSite(); + } +} diff --git a/jdk/src/share/classes/java/lang/invoke/MagicLambdaImpl.java b/jdk/src/share/classes/java/lang/invoke/MagicLambdaImpl.java new file mode 100644 index 00000000000..b78588bf8fa --- /dev/null +++ b/jdk/src/share/classes/java/lang/invoke/MagicLambdaImpl.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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.lang.invoke; + +/**

MagicLambdaImpl (named for similarity to MagicAccessorImpl and + others, not because it actually implements an interface) is a + marker class in the hierarchy. All subclasses of this class are + "magically" granted access by the VM to otherwise inaccessible + fields and methods of other classes. It is distinct from MagicAccessorImpl + because, while we want to bypass accessibility checks, we do not want to + bypass verification.

+ +

Do not change the name of this class without also changing the + VM's code.

*/ + +class MagicLambdaImpl { +} diff --git a/jdk/src/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java b/jdk/src/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java new file mode 100644 index 00000000000..7384bee464c --- /dev/null +++ b/jdk/src/share/classes/java/lang/invoke/TypeConvertingMethodAdapter.java @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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.lang.invoke; + +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import sun.invoke.util.Wrapper; +import static sun.invoke.util.Wrapper.*; + +class TypeConvertingMethodAdapter extends MethodVisitor { + + TypeConvertingMethodAdapter(MethodVisitor mv) { + super(Opcodes.ASM4, mv); + } + + private static final int NUM_WRAPPERS = Wrapper.values().length; + + private static final String NAME_OBJECT = "java/lang/Object"; + private static final String WRAPPER_PREFIX = "Ljava/lang/"; + + // Same for all primitives; name of the boxing method + private static final String NAME_BOX_METHOD = "valueOf"; + + // Table of opcodes for widening primitive conversions; NOP = no conversion + private static final int[][] wideningOpcodes = new int[NUM_WRAPPERS][NUM_WRAPPERS]; + + private static final Wrapper[] FROM_WRAPPER_NAME = new Wrapper[16]; + + static { + for (Wrapper w : Wrapper.values()) { + if (w.basicTypeChar() != 'L') { + int wi = hashWrapperName(w.wrapperSimpleName()); + assert (FROM_WRAPPER_NAME[wi] == null); + FROM_WRAPPER_NAME[wi] = w; + } + } + + for (int i = 0; i < NUM_WRAPPERS; i++) { + for (int j = 0; j < NUM_WRAPPERS; j++) { + wideningOpcodes[i][j] = Opcodes.NOP; + } + } + + initWidening(LONG, Opcodes.I2L, BYTE, SHORT, INT, CHAR); + initWidening(LONG, Opcodes.F2L, FLOAT); + initWidening(FLOAT, Opcodes.I2F, BYTE, SHORT, INT, CHAR); + initWidening(FLOAT, Opcodes.L2F, LONG); + initWidening(DOUBLE, Opcodes.I2D, BYTE, SHORT, INT, CHAR); + initWidening(DOUBLE, Opcodes.F2D, FLOAT); + initWidening(DOUBLE, Opcodes.L2D, LONG); + } + + private static void initWidening(Wrapper to, int opcode, Wrapper... from) { + for (Wrapper f : from) { + wideningOpcodes[f.ordinal()][to.ordinal()] = opcode; + } + } + + /** + * Class name to Wrapper hash, derived from Wrapper.hashWrap() + * @param xn + * @return The hash code 0-15 + */ + private static int hashWrapperName(String xn) { + if (xn.length() < 3) { + return 0; + } + return (3 * xn.charAt(1) + xn.charAt(2)) % 16; + } + + private Wrapper wrapperOrNullFromDescriptor(String desc) { + if (!desc.startsWith(WRAPPER_PREFIX)) { + // Not a class type (array or method), so not a boxed type + // or not in the right package + return null; + } + // Pare it down to the simple class name + String cname = desc.substring(WRAPPER_PREFIX.length(), desc.length() - 1); + // Hash to a Wrapper + Wrapper w = FROM_WRAPPER_NAME[hashWrapperName(cname)]; + if (w == null || w.wrapperSimpleName().equals(cname)) { + return w; + } else { + return null; + } + } + + private static String wrapperName(Wrapper w) { + return "java/lang/" + w.wrapperSimpleName(); + } + + private static String unboxMethod(Wrapper w) { + return w.primitiveSimpleName() + "Value"; + } + + private static String boxingDescriptor(Wrapper w) { + return String.format("(%s)L%s;", w.basicTypeChar(), wrapperName(w)); + } + + private static String unboxingDescriptor(Wrapper w) { + return "()" + w.basicTypeChar(); + } + + void boxIfPrimitive(Wrapper w) { + if (w.zero() != null) { + box(w); + } + } + + void widen(Wrapper ws, Wrapper wt) { + if (ws != wt) { + int opcode = wideningOpcodes[ws.ordinal()][wt.ordinal()]; + if (opcode != Opcodes.NOP) { + visitInsn(opcode); + } + } + } + + void box(Wrapper w) { + visitMethodInsn(Opcodes.INVOKESTATIC, + wrapperName(w), + NAME_BOX_METHOD, + boxingDescriptor(w)); + } + + /** + * Convert types by unboxing. The source type is known to be a primitive wrapper. + * @param ws A primitive wrapper corresponding to wrapped reference source type + * @param wt A primitive wrapper being converted to + */ + void unbox(String sname, Wrapper wt) { + visitMethodInsn(Opcodes.INVOKEVIRTUAL, + sname, + unboxMethod(wt), + unboxingDescriptor(wt)); + } + + private String descriptorToName(String desc) { + int last = desc.length() - 1; + if (desc.charAt(0) == 'L' && desc.charAt(last) == ';') { + // In descriptor form + return desc.substring(1, last); + } else { + // Already in internal name form + return desc; + } + } + + void cast(String ds, String dt) { + String ns = descriptorToName(ds); + String nt = descriptorToName(dt); + if (!nt.equals(ns) && !nt.equals(NAME_OBJECT)) { + visitTypeInsn(Opcodes.CHECKCAST, nt); + } + } + + private boolean isPrimitive(Wrapper w) { + return w != OBJECT; + } + + private Wrapper toWrapper(String desc) { + char first = desc.charAt(0); + if (first == '[' || first == '(') { + first = 'L'; + } + return Wrapper.forBasicType(first); + } + + /** + * Convert an argument of type 'argType' to be passed to 'targetType' assuring that it is 'functionalType'. + * Insert the needed conversion instructions in the method code. + * @param argType + * @param targetType + * @param functionalType + */ + void convertType(String dArg, String dTarget, String dFunctional) { + if (dArg.equals(dTarget)) { + return; + } + Wrapper wArg = toWrapper(dArg); + Wrapper wTarget = toWrapper(dTarget); + if (wArg == VOID || wTarget == VOID) { + return; + } + if (isPrimitive(wArg)) { + if (isPrimitive(wTarget)) { + // Both primitives: widening + widen(wArg, wTarget); + } else { + // Primitive argument to reference target + Wrapper wPrimTarget = wrapperOrNullFromDescriptor(dTarget); + if (wPrimTarget != null) { + // The target is a boxed primitive type, widen to get there before boxing + widen(wArg, wPrimTarget); + box(wPrimTarget); + } else { + // Otherwise, box and cast + box(wArg); + cast(wrapperName(wArg), dTarget); + } + } + } else { + String dSrc; + Wrapper wFunctional = toWrapper(dFunctional); + if (isPrimitive(wFunctional)) { + dSrc = dArg; + } else { + // Cast to convert to possibly more specific type, and generate CCE for invalid arg + dSrc = dFunctional; + cast(dArg, dFunctional); + } + if (isPrimitive(wTarget)) { + // Reference argument to primitive target + Wrapper wps = wrapperOrNullFromDescriptor(dSrc); + if (wps != null) { + if (wps.isSigned() || wps.isFloating()) { + // Boxed number to primitive + unbox(wrapperName(wps), wTarget); + } else { + // Character or Boolean + unbox(wrapperName(wps), wps); + widen(wps, wTarget); + } + } else { + // Source type is reference type, but not boxed type, + // assume it is super type of target type + String intermediate; + if (wTarget.isSigned() || wTarget.isFloating()) { + // Boxed number to primitive + intermediate = "java/lang/Number"; + } else { + // Character or Boolean + intermediate = wrapperName(wTarget); + } + cast(dSrc, intermediate); + unbox(intermediate, wTarget); + } + } else { + // Both reference types: just case to target type + cast(dSrc, dTarget); + } + } + } +} From ed483ab38b3e0b1e8169d6f17c6b3b6e40e79354 Mon Sep 17 00:00:00 2001 From: Dan Xu Date: Fri, 26 Oct 2012 11:21:02 +0100 Subject: [PATCH 15/59] 4239752: FileSystem should be a platform-specific class to avoid native code Reviewed-by: alanb, dholmes, erikj, jgish --- jdk/make/java/java/Exportedfiles.gmk | 4 +++- jdk/make/java/java/FILES_c.gmk | 3 +-- jdk/make/java/java/FILES_java.gmk | 3 ++- jdk/make/java/java/mapfile-vers | 3 +-- jdk/makefiles/CompileJavaClasses.gmk | 3 ++- jdk/makefiles/mapfiles/libjava/mapfile-vers | 3 +-- jdk/src/share/classes/java/io/File.java | 2 +- jdk/src/share/classes/java/io/FileSystem.java | 9 +------- .../java/io/DefaultFileSystem.java} | 21 +++++++++++------- .../java/io/DefaultFileSystem.java} | 22 ++++++++++++------- 10 files changed, 39 insertions(+), 34 deletions(-) rename jdk/src/solaris/{native/java/io/FileSystem_md.c => classes/java/io/DefaultFileSystem.java} (79%) rename jdk/src/windows/{native/java/io/FileSystem_md.c => classes/java/io/DefaultFileSystem.java} (78%) diff --git a/jdk/make/java/java/Exportedfiles.gmk b/jdk/make/java/java/Exportedfiles.gmk index 3a7c8b3ff10..f6d3c3ae1de 100644 --- a/jdk/make/java/java/Exportedfiles.gmk +++ b/jdk/make/java/java/Exportedfiles.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -66,6 +66,7 @@ FILES_export = \ java/util/prefs/FileSystemPreferences.java \ java/io/Console.java \ java/io/FileDescriptor.java \ + java/io/DefaultFileSystem.java \ java/io/InputStream.java \ java/io/FileInputStream.java \ java/io/FileOutputStream.java \ @@ -142,6 +143,7 @@ FILES_export = \ java/io/Console.java \ java/io/FileSystem.java \ java/io/FileDescriptor.java \ + java/io/DefaultFileSystem.java \ java/io/InputStream.java \ java/io/FileInputStream.java \ java/io/FileOutputStream.java \ diff --git a/jdk/make/java/java/FILES_c.gmk b/jdk/make/java/java/FILES_c.gmk index be698cd70b0..aa48464771b 100644 --- a/jdk/make/java/java/FILES_c.gmk +++ b/jdk/make/java/java/FILES_c.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. # 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,7 +32,6 @@ FILES_c = \ Compiler.c \ Console_md.c \ Double.c \ - FileSystem_md.c \ FileDescriptor_md.c \ FileInputStream.c \ FileInputStream_md.c \ diff --git a/jdk/make/java/java/FILES_java.gmk b/jdk/make/java/java/FILES_java.gmk index efbf73b744d..246acf3e3aa 100644 --- a/jdk/make/java/java/FILES_java.gmk +++ b/jdk/make/java/java/FILES_java.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -438,6 +438,7 @@ JAVA_JAVA_java = \ java/io/File.java \ java/io/FileSystem.java \ java/io/FileDescriptor.java \ + java/io/DefaultFileSystem.java \ java/io/FilenameFilter.java \ java/io/FileFilter.java \ java/io/FilePermission.java \ diff --git a/jdk/make/java/java/mapfile-vers b/jdk/make/java/java/mapfile-vers index 42ec3ca7277..97938361c99 100644 --- a/jdk/make/java/java/mapfile-vers +++ b/jdk/make/java/java/mapfile-vers @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -87,7 +87,6 @@ SUNWprivate_1.1 { Java_java_io_FileOutputStream_open; Java_java_io_FileOutputStream_write; Java_java_io_FileOutputStream_writeBytes; - Java_java_io_FileSystem_getFileSystem; Java_java_io_ObjectInputStream_bytesToDoubles; Java_java_io_ObjectInputStream_bytesToFloats; Java_java_io_ObjectOutputStream_doublesToBytes; diff --git a/jdk/makefiles/CompileJavaClasses.gmk b/jdk/makefiles/CompileJavaClasses.gmk index 879ffadfed1..c3a5eab9237 100644 --- a/jdk/makefiles/CompileJavaClasses.gmk +++ b/jdk/makefiles/CompileJavaClasses.gmk @@ -312,7 +312,8 @@ $(eval $(call SetupJavaCompilation,BUILD_JDK,\ JDK_BASE_HEADER_CLASSES:=java.lang.Integer \ java.lang.Long \ java.net.SocketOptions \ - sun.nio.ch.IOStatus + sun.nio.ch.IOStatus \ + java.io.FileSystem JDK_BASE_HEADER_JAVA_FILES:=$(patsubst %,$(JDK_TOPDIR)/src/share/classes/%.java,\ $(subst .,/,$(JDK_BASE_HEADER_CLASSES))) diff --git a/jdk/makefiles/mapfiles/libjava/mapfile-vers b/jdk/makefiles/mapfiles/libjava/mapfile-vers index 42ec3ca7277..97938361c99 100644 --- a/jdk/makefiles/mapfiles/libjava/mapfile-vers +++ b/jdk/makefiles/mapfiles/libjava/mapfile-vers @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -87,7 +87,6 @@ SUNWprivate_1.1 { Java_java_io_FileOutputStream_open; Java_java_io_FileOutputStream_write; Java_java_io_FileOutputStream_writeBytes; - Java_java_io_FileSystem_getFileSystem; Java_java_io_ObjectInputStream_bytesToDoubles; Java_java_io_ObjectInputStream_bytesToFloats; Java_java_io_ObjectOutputStream_doublesToBytes; diff --git a/jdk/src/share/classes/java/io/File.java b/jdk/src/share/classes/java/io/File.java index 3c0fafca5c1..dd313dd97d0 100644 --- a/jdk/src/share/classes/java/io/File.java +++ b/jdk/src/share/classes/java/io/File.java @@ -153,7 +153,7 @@ public class File /** * The FileSystem object representing the platform's local file system. */ - private static final FileSystem fs = FileSystem.getFileSystem(); + private static final FileSystem fs = DefaultFileSystem.getFileSystem(); /** * This abstract pathname's normalized pathname string. A normalized diff --git a/jdk/src/share/classes/java/io/FileSystem.java b/jdk/src/share/classes/java/io/FileSystem.java index 0afed180da8..9baaa3cc187 100644 --- a/jdk/src/share/classes/java/io/FileSystem.java +++ b/jdk/src/share/classes/java/io/FileSystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. * 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,13 +32,6 @@ package java.io; abstract class FileSystem { - /** - * Return the FileSystem object representing this platform's local - * filesystem. - */ - public static native FileSystem getFileSystem(); - - /* -- Normalization and construction -- */ /** diff --git a/jdk/src/solaris/native/java/io/FileSystem_md.c b/jdk/src/solaris/classes/java/io/DefaultFileSystem.java similarity index 79% rename from jdk/src/solaris/native/java/io/FileSystem_md.c rename to jdk/src/solaris/classes/java/io/DefaultFileSystem.java index af4aaba6428..8e8cf081f01 100644 --- a/jdk/src/solaris/native/java/io/FileSystem_md.c +++ b/jdk/src/solaris/classes/java/io/DefaultFileSystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. * 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,13 +23,18 @@ * questions. */ -#include "jni.h" -#include "jni_util.h" -#include "java_io_FileSystem.h" +package java.io; +/** + * + * @since 1.8 + */ +class DefaultFileSystem { -JNIEXPORT jobject JNICALL -Java_java_io_FileSystem_getFileSystem(JNIEnv *env, jclass ignored) -{ - return JNU_NewObjectByName(env, "java/io/UnixFileSystem", "()V"); + /** + * Return the FileSystem object for Unix-based platform. + */ + public static FileSystem getFileSystem() { + return new UnixFileSystem(); + } } diff --git a/jdk/src/windows/native/java/io/FileSystem_md.c b/jdk/src/windows/classes/java/io/DefaultFileSystem.java similarity index 78% rename from jdk/src/windows/native/java/io/FileSystem_md.c rename to jdk/src/windows/classes/java/io/DefaultFileSystem.java index bd813e7dbf0..9256dca151d 100644 --- a/jdk/src/windows/native/java/io/FileSystem_md.c +++ b/jdk/src/windows/classes/java/io/DefaultFileSystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. * 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,18 @@ * questions. */ -#include -#include "jni.h" -#include "jni_util.h" +package java.io; -JNIEXPORT jobject JNICALL -Java_java_io_FileSystem_getFileSystem(JNIEnv *env, jclass ignored) -{ - return JNU_NewObjectByName(env, "java/io/WinNTFileSystem", "()V"); +/** + * + * @since 1.8 + */ +class DefaultFileSystem { + + /** + * Return the FileSystem object for Windows platform. + */ + public static FileSystem getFileSystem() { + return new WinNTFileSystem(); + } } From 6f31fa54ac050d781656d6e8ed18a40b55ef5c0d Mon Sep 17 00:00:00 2001 From: Doug Lea Date: Fri, 26 Oct 2012 21:34:24 +0100 Subject: [PATCH 16/59] 8001575: Minor/sync/cleanup j.u.c with Dougs CVS - Oct 2012 Reviewed-by: chegar, dholmes --- .../concurrent/AbstractExecutorService.java | 24 ++-- .../java/util/concurrent/BlockingQueue.java | 5 +- .../concurrent/BrokenBarrierException.java | 1 - .../util/concurrent/CompletionService.java | 2 - .../concurrent/ConcurrentLinkedDeque.java | 11 +- .../concurrent/ConcurrentLinkedQueue.java | 11 +- .../java/util/concurrent/ConcurrentMap.java | 46 ++++--- .../concurrent/ConcurrentNavigableMap.java | 1 - .../concurrent/ConcurrentSkipListMap.java | 10 +- .../concurrent/ConcurrentSkipListSet.java | 2 +- .../util/concurrent/CopyOnWriteArrayList.java | 41 +++---- .../util/concurrent/CopyOnWriteArraySet.java | 7 +- .../java/util/concurrent/CountDownLatch.java | 15 +-- .../java/util/concurrent/CyclicBarrier.java | 49 ++++---- .../classes/java/util/concurrent/Delayed.java | 2 - .../util/concurrent/ExecutionException.java | 8 +- .../java/util/concurrent/Executor.java | 20 +-- .../java/util/concurrent/ExecutorService.java | 14 +-- .../java/util/concurrent/Executors.java | 6 +- .../classes/java/util/concurrent/Future.java | 12 +- .../util/concurrent/LinkedBlockingDeque.java | 14 +-- .../util/concurrent/LinkedBlockingQueue.java | 20 +-- .../util/concurrent/LinkedTransferQueue.java | 15 +-- .../java/util/concurrent/RecursiveAction.java | 36 ++++-- .../RejectedExecutionException.java | 4 +- .../concurrent/ScheduledExecutorService.java | 2 - .../ScheduledThreadPoolExecutor.java | 38 +++--- .../java/util/concurrent/Semaphore.java | 16 +-- .../util/concurrent/SynchronousQueue.java | 41 +++---- .../java/util/concurrent/ThreadFactory.java | 5 +- .../java/util/concurrent/TimeUnit.java | 14 +-- .../util/concurrent/atomic/AtomicInteger.java | 1 - .../atomic/AtomicIntegerFieldUpdater.java | 8 +- .../util/concurrent/atomic/AtomicLong.java | 1 - .../atomic/AtomicLongFieldUpdater.java | 8 +- .../concurrent/atomic/AtomicReference.java | 2 +- .../atomic/AtomicReferenceArray.java | 7 +- .../atomic/AtomicReferenceFieldUpdater.java | 30 ++--- .../util/concurrent/atomic/package-info.java | 35 ++++-- .../locks/AbstractQueuedLongSynchronizer.java | 85 ++++++------- .../locks/AbstractQueuedSynchronizer.java | 96 ++++++--------- .../java/util/concurrent/locks/Condition.java | 9 +- .../java/util/concurrent/locks/Lock.java | 45 +++---- .../util/concurrent/locks/LockSupport.java | 10 +- .../util/concurrent/locks/ReentrantLock.java | 38 +++--- .../locks/ReentrantReadWriteLock.java | 115 +++++++++--------- .../java/util/concurrent/package-info.java | 7 +- 47 files changed, 456 insertions(+), 533 deletions(-) diff --git a/jdk/src/share/classes/java/util/concurrent/AbstractExecutorService.java b/jdk/src/share/classes/java/util/concurrent/AbstractExecutorService.java index bac93ab3b90..fdf8b437524 100644 --- a/jdk/src/share/classes/java/util/concurrent/AbstractExecutorService.java +++ b/jdk/src/share/classes/java/util/concurrent/AbstractExecutorService.java @@ -137,7 +137,7 @@ public abstract class AbstractExecutorService implements ExecutorService { * the main mechanics of invokeAny. */ private T doInvokeAny(Collection> tasks, - boolean timed, long nanos) + boolean timed, long nanos) throws InterruptedException, ExecutionException, TimeoutException { if (tasks == null) throw new NullPointerException(); @@ -158,7 +158,7 @@ public abstract class AbstractExecutorService implements ExecutorService { // Record exceptions so that if we fail to obtain any // result, we can throw the last exception we got. ExecutionException ee = null; - long lastTime = timed ? System.nanoTime() : 0; + final long deadline = timed ? System.nanoTime() + nanos : 0L; Iterator> it = tasks.iterator(); // Start one task for sure; the rest incrementally @@ -180,9 +180,7 @@ public abstract class AbstractExecutorService implements ExecutorService { f = ecs.poll(nanos, TimeUnit.NANOSECONDS); if (f == null) throw new TimeoutException(); - long now = System.nanoTime(); - nanos -= now - lastTime; - lastTime = now; + nanos = deadline - System.nanoTime(); } else f = ecs.take(); @@ -258,7 +256,7 @@ public abstract class AbstractExecutorService implements ExecutorService { public List> invokeAll(Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException { - if (tasks == null || unit == null) + if (tasks == null) throw new NullPointerException(); long nanos = unit.toNanos(timeout); List> futures = new ArrayList>(tasks.size()); @@ -267,23 +265,21 @@ public abstract class AbstractExecutorService implements ExecutorService { for (Callable t : tasks) futures.add(newTaskFor(t)); - long lastTime = System.nanoTime(); + final long deadline = System.nanoTime() + nanos; // Interleave time checks and calls to execute in case // executor doesn't have any/much parallelism. Iterator> it = futures.iterator(); while (it.hasNext()) { execute((Runnable)(it.next())); - long now = System.nanoTime(); - nanos -= now - lastTime; - lastTime = now; - if (nanos <= 0) + nanos = deadline - System.nanoTime(); + if (nanos <= 0L) return futures; } for (Future f : futures) { if (!f.isDone()) { - if (nanos <= 0) + if (nanos <= 0L) return futures; try { f.get(nanos, TimeUnit.NANOSECONDS); @@ -292,9 +288,7 @@ public abstract class AbstractExecutorService implements ExecutorService { } catch (TimeoutException toe) { return futures; } - long now = System.nanoTime(); - nanos -= now - lastTime; - lastTime = now; + nanos = deadline - System.nanoTime(); } } done = true; diff --git a/jdk/src/share/classes/java/util/concurrent/BlockingQueue.java b/jdk/src/share/classes/java/util/concurrent/BlockingQueue.java index 4511d27efd7..bb5eb603324 100644 --- a/jdk/src/share/classes/java/util/concurrent/BlockingQueue.java +++ b/jdk/src/share/classes/java/util/concurrent/BlockingQueue.java @@ -127,7 +127,7 @@ import java.util.Queue; * Usage example, based on a typical producer-consumer scenario. * Note that a BlockingQueue can safely be used with multiple * producers and multiple consumers. - *
+ *  
 {@code
  * class Producer implements Runnable {
  *   private final BlockingQueue queue;
  *   Producer(BlockingQueue q) { queue = q; }
@@ -160,8 +160,7 @@ import java.util.Queue;
  *     new Thread(c1).start();
  *     new Thread(c2).start();
  *   }
- * }
- * 
+ * }}
* *

Memory consistency effects: As with other concurrent * collections, actions in a thread prior to placing an object into a diff --git a/jdk/src/share/classes/java/util/concurrent/BrokenBarrierException.java b/jdk/src/share/classes/java/util/concurrent/BrokenBarrierException.java index 9d2a9f4b4f6..2c8f7e3396d 100644 --- a/jdk/src/share/classes/java/util/concurrent/BrokenBarrierException.java +++ b/jdk/src/share/classes/java/util/concurrent/BrokenBarrierException.java @@ -44,7 +44,6 @@ package java.util.concurrent; * * @since 1.5 * @author Doug Lea - * */ public class BrokenBarrierException extends Exception { private static final long serialVersionUID = 7117394618823254244L; diff --git a/jdk/src/share/classes/java/util/concurrent/CompletionService.java b/jdk/src/share/classes/java/util/concurrent/CompletionService.java index 5a807c5effe..78d09f302b6 100644 --- a/jdk/src/share/classes/java/util/concurrent/CompletionService.java +++ b/jdk/src/share/classes/java/util/concurrent/CompletionService.java @@ -57,7 +57,6 @@ package java.util.concurrent; * happen-before * actions taken by that task, which in turn happen-before * actions following a successful return from the corresponding {@code take()}. - * */ public interface CompletionService { /** @@ -98,7 +97,6 @@ public interface CompletionService { */ Future take() throws InterruptedException; - /** * Retrieves and removes the Future representing the next * completed task or null if none are present. diff --git a/jdk/src/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java b/jdk/src/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java index c26e371f9d1..146934af475 100644 --- a/jdk/src/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java +++ b/jdk/src/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java @@ -90,7 +90,6 @@ import java.util.Queue; * @author Martin Buchholz * @param the type of elements held in this collection */ - public class ConcurrentLinkedDeque extends AbstractCollection implements Deque, java.io.Serializable { @@ -1250,8 +1249,7 @@ public class ConcurrentLinkedDeque * The following code can be used to dump the deque into a newly * allocated array of {@code String}: * - *

-     *     String[] y = x.toArray(new String[0]);
+ *
 {@code String[] y = x.toArray(new String[0]);}
* * Note that {@code toArray(new Object[0])} is identical in function to * {@code toArray()}. @@ -1388,11 +1386,10 @@ public class ConcurrentLinkedDeque } /** - * Saves the state to a stream (that is, serializes it). + * Saves this deque to a stream (that is, serializes it). * * @serialData All of the elements (each an {@code E}) in * the proper order, followed by a null - * @param s the stream */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { @@ -1412,8 +1409,7 @@ public class ConcurrentLinkedDeque } /** - * Reconstitutes the instance from a stream (that is, deserializes it). - * @param s the stream + * Reconstitutes this deque from a stream (that is, deserializes it). */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { @@ -1436,7 +1432,6 @@ public class ConcurrentLinkedDeque initHeadTail(h, t); } - private boolean casHead(Node cmp, Node val) { return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val); } diff --git a/jdk/src/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java b/jdk/src/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java index dfac05c6d40..abf12c59760 100644 --- a/jdk/src/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java +++ b/jdk/src/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java @@ -98,7 +98,6 @@ import java.util.Queue; * @since 1.5 * @author Doug Lea * @param the type of elements held in this collection - * */ public class ConcurrentLinkedQueue extends AbstractQueue implements Queue, java.io.Serializable { @@ -247,7 +246,6 @@ public class ConcurrentLinkedQueue extends AbstractQueue */ private transient volatile Node tail; - /** * Creates a {@code ConcurrentLinkedQueue} that is initially empty. */ @@ -609,8 +607,7 @@ public class ConcurrentLinkedQueue extends AbstractQueue * The following code can be used to dump the queue into a newly * allocated array of {@code String}: * - *
-     *     String[] y = x.toArray(new String[0]);
+ *
 {@code String[] y = x.toArray(new String[0]);}
* * Note that {@code toArray(new Object[0])} is identical in function to * {@code toArray()}. @@ -747,11 +744,10 @@ public class ConcurrentLinkedQueue extends AbstractQueue } /** - * Saves the state to a stream (that is, serializes it). + * Saves this queue to a stream (that is, serializes it). * * @serialData All of the elements (each an {@code E}) in * the proper order, followed by a null - * @param s the stream */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { @@ -771,8 +767,7 @@ public class ConcurrentLinkedQueue extends AbstractQueue } /** - * Reconstitutes the instance from a stream (that is, deserializes it). - * @param s the stream + * Reconstitutes this queue from a stream (that is, deserializes it). */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { diff --git a/jdk/src/share/classes/java/util/concurrent/ConcurrentMap.java b/jdk/src/share/classes/java/util/concurrent/ConcurrentMap.java index 4434c0563b4..a725db6e674 100644 --- a/jdk/src/share/classes/java/util/concurrent/ConcurrentMap.java +++ b/jdk/src/share/classes/java/util/concurrent/ConcurrentMap.java @@ -61,11 +61,12 @@ public interface ConcurrentMap extends Map { * If the specified key is not already associated * with a value, associate it with the given value. * This is equivalent to - *
-     *   if (!map.containsKey(key))
-     *       return map.put(key, value);
-     *   else
-     *       return map.get(key);
+ *
 {@code
+     * if (!map.containsKey(key))
+     *   return map.put(key, value);
+     * else
+     *   return map.get(key);}
+ * * except that the action is performed atomically. * * @param key key with which the specified value is to be associated @@ -83,18 +84,19 @@ public interface ConcurrentMap extends Map { * and this map does not permit null keys or values * @throws IllegalArgumentException if some property of the specified key * or value prevents it from being stored in this map - * */ V putIfAbsent(K key, V value); /** * Removes the entry for a key only if currently mapped to a given value. * This is equivalent to - *
-     *   if (map.containsKey(key) && map.get(key).equals(value)) {
-     *       map.remove(key);
-     *       return true;
-     *   } else return false;
+ *
 {@code
+     * if (map.containsKey(key) && map.get(key).equals(value)) {
+     *   map.remove(key);
+     *   return true;
+     * } else
+     *   return false;}
+ * * except that the action is performed atomically. * * @param key key with which the specified value is associated @@ -114,11 +116,13 @@ public interface ConcurrentMap extends Map { /** * Replaces the entry for a key only if currently mapped to a given value. * This is equivalent to - *
-     *   if (map.containsKey(key) && map.get(key).equals(oldValue)) {
-     *       map.put(key, newValue);
-     *       return true;
-     *   } else return false;
+ *
 {@code
+     * if (map.containsKey(key) && map.get(key).equals(oldValue)) {
+     *   map.put(key, newValue);
+     *   return true;
+     * } else
+     *   return false;}
+ * * except that the action is performed atomically. * * @param key key with which the specified value is associated @@ -139,10 +143,12 @@ public interface ConcurrentMap extends Map { /** * Replaces the entry for a key only if currently mapped to some value. * This is equivalent to - *
-     *   if (map.containsKey(key)) {
-     *       return map.put(key, value);
-     *   } else return null;
+ *
 {@code
+     * if (map.containsKey(key)) {
+     *   return map.put(key, value);
+     * } else
+     *   return null;}
+ * * except that the action is performed atomically. * * @param key key with which the specified value is associated diff --git a/jdk/src/share/classes/java/util/concurrent/ConcurrentNavigableMap.java b/jdk/src/share/classes/java/util/concurrent/ConcurrentNavigableMap.java index df5bb31d1b1..1d096f0c52d 100644 --- a/jdk/src/share/classes/java/util/concurrent/ConcurrentNavigableMap.java +++ b/jdk/src/share/classes/java/util/concurrent/ConcurrentNavigableMap.java @@ -67,7 +67,6 @@ public interface ConcurrentNavigableMap */ ConcurrentNavigableMap headMap(K toKey, boolean inclusive); - /** * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} diff --git a/jdk/src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java b/jdk/src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java index fdf83d1cc81..cd93e211890 100644 --- a/jdk/src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java +++ b/jdk/src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java @@ -1507,7 +1507,7 @@ public class ConcurrentSkipListMap extends AbstractMap /* ---------------- Serialization -------------- */ /** - * Saves the state of this map to a stream (that is, serializes it). + * Saves this map to a stream (that is, serializes it). * * @serialData The key (Object) and value (Object) for each * key-value mapping represented by the map, followed by @@ -1532,9 +1532,7 @@ public class ConcurrentSkipListMap extends AbstractMap } /** - * Reconstitutes the map from a stream (that is, deserializes it). - * - * @param s the stream + * Reconstitutes this map from a stream (that is, deserializes it). */ private void readObject(final java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { @@ -2342,7 +2340,7 @@ public class ConcurrentSkipListMap extends AbstractMap Collection c = (Collection) o; try { return containsAll(c) && c.containsAll(this); - } catch (ClassCastException unused) { + } catch (ClassCastException unused) { return false; } catch (NullPointerException unused) { return false; @@ -2451,7 +2449,7 @@ public class ConcurrentSkipListMap extends AbstractMap Collection c = (Collection) o; try { return containsAll(c) && c.containsAll(this); - } catch (ClassCastException unused) { + } catch (ClassCastException unused) { return false; } catch (NullPointerException unused) { return false; diff --git a/jdk/src/share/classes/java/util/concurrent/ConcurrentSkipListSet.java b/jdk/src/share/classes/java/util/concurrent/ConcurrentSkipListSet.java index b250c1a5108..8214b37c4fd 100644 --- a/jdk/src/share/classes/java/util/concurrent/ConcurrentSkipListSet.java +++ b/jdk/src/share/classes/java/util/concurrent/ConcurrentSkipListSet.java @@ -298,7 +298,7 @@ public class ConcurrentSkipListSet Collection c = (Collection) o; try { return containsAll(c) && c.containsAll(this); - } catch (ClassCastException unused) { + } catch (ClassCastException unused) { return false; } catch (NullPointerException unused) { return false; diff --git a/jdk/src/share/classes/java/util/concurrent/CopyOnWriteArrayList.java b/jdk/src/share/classes/java/util/concurrent/CopyOnWriteArrayList.java index e61dd7921fd..5621c907cd5 100644 --- a/jdk/src/share/classes/java/util/concurrent/CopyOnWriteArrayList.java +++ b/jdk/src/share/classes/java/util/concurrent/CopyOnWriteArrayList.java @@ -35,7 +35,7 @@ package java.util.concurrent; import java.util.*; -import java.util.concurrent.locks.*; +import java.util.concurrent.locks.ReentrantLock; /** * A thread-safe variant of {@link java.util.ArrayList} in which all mutative @@ -152,7 +152,7 @@ public class CopyOnWriteArrayList } /** - * Test for equality, coping with nulls. + * Tests for equality, coping with nulls. */ private static boolean eq(Object o1, Object o2) { return (o1 == null ? o2 == null : o1.equals(o2)); @@ -333,8 +333,7 @@ public class CopyOnWriteArrayList * The following code can be used to dump the list into a newly * allocated array of String: * - *
-     *     String[] y = x.toArray(new String[0]);
+ *
 {@code String[] y = x.toArray(new String[0]);}
* * Note that toArray(new Object[0]) is identical in function to * toArray(). @@ -548,9 +547,9 @@ public class CopyOnWriteArrayList * @param fromIndex index of first element to be removed * @param toIndex index after last element to be removed * @throws IndexOutOfBoundsException if fromIndex or toIndex out of range - * ({@code{fromIndex < 0 || toIndex > size() || toIndex < fromIndex}) + * ({@code fromIndex < 0 || toIndex > size() || toIndex < fromIndex}) */ - private void removeRange(int fromIndex, int toIndex) { + void removeRange(int fromIndex, int toIndex) { final ReentrantLock lock = this.lock; lock.lock(); try { @@ -576,7 +575,7 @@ public class CopyOnWriteArrayList } /** - * Append the element if not present. + * Appends the element, if not present. * * @param e element to be added to this list, if absent * @return true if the element was added @@ -641,6 +640,7 @@ public class CopyOnWriteArrayList * @see #remove(Object) */ public boolean removeAll(Collection c) { + if (c == null) throw new NullPointerException(); final ReentrantLock lock = this.lock; lock.lock(); try { @@ -683,6 +683,7 @@ public class CopyOnWriteArrayList * @see #remove(Object) */ public boolean retainAll(Collection c) { + if (c == null) throw new NullPointerException(); final ReentrantLock lock = this.lock; lock.lock(); try { @@ -837,15 +838,14 @@ public class CopyOnWriteArrayList } /** - * Saves the state of the list to a stream (that is, serializes it). + * Saves this list to a stream (that is, serializes it). * * @serialData The length of the array backing the list is emitted * (int), followed by all of its elements (each an Object) * in the proper order. - * @param s the stream */ private void writeObject(java.io.ObjectOutputStream s) - throws java.io.IOException{ + throws java.io.IOException { s.defaultWriteObject(); @@ -859,9 +859,7 @@ public class CopyOnWriteArrayList } /** - * Reconstitutes the list from a stream (that is, deserializes it). - * - * @param s the stream + * Reconstitutes this list from a stream (that is, deserializes it). */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { @@ -1266,17 +1264,14 @@ public class CopyOnWriteArrayList private static class COWSubListIterator implements ListIterator { - private final ListIterator i; - private final int index; + private final ListIterator it; private final int offset; private final int size; - COWSubListIterator(List l, int index, int offset, - int size) { - this.index = index; + COWSubListIterator(List l, int index, int offset, int size) { this.offset = offset; this.size = size; - i = l.listIterator(index+offset); + it = l.listIterator(index+offset); } public boolean hasNext() { @@ -1285,7 +1280,7 @@ public class CopyOnWriteArrayList public E next() { if (hasNext()) - return i.next(); + return it.next(); else throw new NoSuchElementException(); } @@ -1296,17 +1291,17 @@ public class CopyOnWriteArrayList public E previous() { if (hasPrevious()) - return i.previous(); + return it.previous(); else throw new NoSuchElementException(); } public int nextIndex() { - return i.nextIndex() - offset; + return it.nextIndex() - offset; } public int previousIndex() { - return i.previousIndex() - offset; + return it.previousIndex() - offset; } public void remove() { diff --git a/jdk/src/share/classes/java/util/concurrent/CopyOnWriteArraySet.java b/jdk/src/share/classes/java/util/concurrent/CopyOnWriteArraySet.java index d518048227d..da3c9856332 100644 --- a/jdk/src/share/classes/java/util/concurrent/CopyOnWriteArraySet.java +++ b/jdk/src/share/classes/java/util/concurrent/CopyOnWriteArraySet.java @@ -189,8 +189,7 @@ public class CopyOnWriteArraySet extends AbstractSet * The following code can be used to dump the set into a newly allocated * array of String: * - *
-     *     String[] y = x.toArray(new String[0]);
+ *
 {@code String[] y = x.toArray(new String[0]);}
* * Note that toArray(new Object[0]) is identical in function to * toArray(). @@ -384,9 +383,9 @@ public class CopyOnWriteArraySet extends AbstractSet } /** - * Test for equality, coping with nulls. + * Tests for equality, coping with nulls. */ private static boolean eq(Object o1, Object o2) { - return (o1 == null ? o2 == null : o1.equals(o2)); + return (o1 == null) ? o2 == null : o1.equals(o2); } } diff --git a/jdk/src/share/classes/java/util/concurrent/CountDownLatch.java b/jdk/src/share/classes/java/util/concurrent/CountDownLatch.java index 187b1f2355f..055eb113727 100644 --- a/jdk/src/share/classes/java/util/concurrent/CountDownLatch.java +++ b/jdk/src/share/classes/java/util/concurrent/CountDownLatch.java @@ -34,8 +34,7 @@ */ package java.util.concurrent; -import java.util.concurrent.locks.*; -import java.util.concurrent.atomic.*; +import java.util.concurrent.locks.AbstractQueuedSynchronizer; /** * A synchronization aid that allows one or more threads to wait until @@ -73,7 +72,7 @@ import java.util.concurrent.atomic.*; * until all workers have completed. * * - *
+ *  
 {@code
  * class Driver { // ...
  *   void main() throws InterruptedException {
  *     CountDownLatch startSignal = new CountDownLatch(1);
@@ -105,9 +104,7 @@ import java.util.concurrent.atomic.*;
  *   }
  *
  *   void doWork() { ... }
- * }
- *
- * 
+ * }}
* *

Another typical usage would be to divide a problem into N parts, * describe each part with a Runnable that executes that portion and @@ -116,7 +113,7 @@ import java.util.concurrent.atomic.*; * will be able to pass through await. (When threads must repeatedly * count down in this way, instead use a {@link CyclicBarrier}.) * - *

+ *  
 {@code
  * class Driver2 { // ...
  *   void main() throws InterruptedException {
  *     CountDownLatch doneSignal = new CountDownLatch(N);
@@ -144,9 +141,7 @@ import java.util.concurrent.atomic.*;
  *   }
  *
  *   void doWork() { ... }
- * }
- *
- * 
+ * }}
* *

Memory consistency effects: Until the count reaches * zero, actions in a thread prior to calling diff --git a/jdk/src/share/classes/java/util/concurrent/CyclicBarrier.java b/jdk/src/share/classes/java/util/concurrent/CyclicBarrier.java index 01d64b116b7..eb25879dbcf 100644 --- a/jdk/src/share/classes/java/util/concurrent/CyclicBarrier.java +++ b/jdk/src/share/classes/java/util/concurrent/CyclicBarrier.java @@ -34,7 +34,8 @@ */ package java.util.concurrent; -import java.util.concurrent.locks.*; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; /** * A synchronization aid that allows a set of threads to all wait for @@ -52,7 +53,8 @@ import java.util.concurrent.locks.*; * *

Sample usage: Here is an example of * using a barrier in a parallel decomposition design: - *

+ *
+ *  
 {@code
  * class Solver {
  *   final int N;
  *   final float[][] data;
@@ -90,8 +92,8 @@ import java.util.concurrent.locks.*;
  *
  *     waitUntilDone();
  *   }
- * }
- * 
+ * }}
+ * * Here, each worker thread processes a row of the matrix then waits at the * barrier until all rows have been processed. When all rows are processed * the supplied {@link Runnable} barrier action is executed and merges the @@ -105,9 +107,10 @@ import java.util.concurrent.locks.*; * {@link #await} returns the arrival index of that thread at the barrier. * You can then choose which thread should execute the barrier action, for * example: - *
  if (barrier.await() == 0) {
- *     // log the completion of this iteration
- *   }
+ *
 {@code
+ * if (barrier.await() == 0) {
+ *   // log the completion of this iteration
+ * }}
* *

The CyclicBarrier uses an all-or-none breakage model * for failed synchronization attempts: If a thread leaves a barrier @@ -204,21 +207,21 @@ public class CyclicBarrier { throw new InterruptedException(); } - int index = --count; - if (index == 0) { // tripped - boolean ranAction = false; - try { - final Runnable command = barrierCommand; - if (command != null) - command.run(); - ranAction = true; - nextGeneration(); - return 0; - } finally { - if (!ranAction) - breakBarrier(); - } - } + int index = --count; + if (index == 0) { // tripped + boolean ranAction = false; + try { + final Runnable command = barrierCommand; + if (command != null) + command.run(); + ranAction = true; + nextGeneration(); + return 0; + } finally { + if (!ranAction) + breakBarrier(); + } + } // loop until tripped, broken, interrupted, or timed out for (;;) { @@ -354,7 +357,7 @@ public class CyclicBarrier { try { return dowait(false, 0L); } catch (TimeoutException toe) { - throw new Error(toe); // cannot happen; + throw new Error(toe); // cannot happen } } diff --git a/jdk/src/share/classes/java/util/concurrent/Delayed.java b/jdk/src/share/classes/java/util/concurrent/Delayed.java index d7756412130..8b185e1d79c 100644 --- a/jdk/src/share/classes/java/util/concurrent/Delayed.java +++ b/jdk/src/share/classes/java/util/concurrent/Delayed.java @@ -35,8 +35,6 @@ package java.util.concurrent; -import java.util.*; - /** * A mix-in style interface for marking objects that should be * acted upon after a given delay. diff --git a/jdk/src/share/classes/java/util/concurrent/ExecutionException.java b/jdk/src/share/classes/java/util/concurrent/ExecutionException.java index fc2b1e899ec..f5bfa7f309a 100644 --- a/jdk/src/share/classes/java/util/concurrent/ExecutionException.java +++ b/jdk/src/share/classes/java/util/concurrent/ExecutionException.java @@ -79,11 +79,9 @@ public class ExecutionException extends Exception { /** * Constructs an ExecutionException with the specified cause. - * The detail message is set to: - *

-     *  (cause == null ? null : cause.toString())
- * (which typically contains the class and detail message of - * cause). + * The detail message is set to {@code (cause == null ? null : + * cause.toString())} (which typically contains the class and + * detail message of {@code cause}). * * @param cause the cause (which is saved for later retrieval by the * {@link #getCause()} method) diff --git a/jdk/src/share/classes/java/util/concurrent/Executor.java b/jdk/src/share/classes/java/util/concurrent/Executor.java index 6b4574a63c7..09b9ac367e3 100644 --- a/jdk/src/share/classes/java/util/concurrent/Executor.java +++ b/jdk/src/share/classes/java/util/concurrent/Executor.java @@ -56,23 +56,23 @@ package java.util.concurrent; * executor can run the submitted task immediately in the caller's * thread: * - *
+ *  
 {@code
  * class DirectExecutor implements Executor {
- *     public void execute(Runnable r) {
- *         r.run();
- *     }
- * }
+ * public void execute(Runnable r) { + * r.run(); + * } + * }}
* * More typically, tasks are executed in some thread other * than the caller's thread. The executor below spawns a new thread * for each task. * - *
+ *  
 {@code
  * class ThreadPerTaskExecutor implements Executor {
- *     public void execute(Runnable r) {
- *         new Thread(r).start();
- *     }
- * }
+ * public void execute(Runnable r) { + * new Thread(r).start(); + * } + * }}
* * Many Executor implementations impose some sort of * limitation on how and when tasks are scheduled. The executor below diff --git a/jdk/src/share/classes/java/util/concurrent/ExecutorService.java b/jdk/src/share/classes/java/util/concurrent/ExecutorService.java index f1ab3275ef5..2340d2a0be8 100644 --- a/jdk/src/share/classes/java/util/concurrent/ExecutorService.java +++ b/jdk/src/share/classes/java/util/concurrent/ExecutorService.java @@ -36,8 +36,6 @@ package java.util.concurrent; import java.util.List; import java.util.Collection; -import java.security.PrivilegedAction; -import java.security.PrivilegedExceptionAction; /** * An {@link Executor} that provides methods to manage termination and @@ -73,7 +71,7 @@ import java.security.PrivilegedExceptionAction; * pool service incoming requests. It uses the preconfigured {@link * Executors#newFixedThreadPool} factory method: * - *
+ *  
 {@code
  * class NetworkService implements Runnable {
  *   private final ServerSocket serverSocket;
  *   private final ExecutorService pool;
@@ -101,14 +99,13 @@ import java.security.PrivilegedExceptionAction;
  *   public void run() {
  *     // read and service request on socket
  *   }
- * }
- * 
+ * }}
* * The following method shuts down an ExecutorService in two phases, * first by calling shutdown to reject incoming tasks, and then * calling shutdownNow, if necessary, to cancel any lingering tasks: * - *
+ *  
 {@code
  * void shutdownAndAwaitTermination(ExecutorService pool) {
  *   pool.shutdown(); // Disable new tasks from being submitted
  *   try {
@@ -125,8 +122,7 @@ import java.security.PrivilegedExceptionAction;
  *     // Preserve interrupt status
  *     Thread.currentThread().interrupt();
  *   }
- * }
- * 
+ * }}
* *

Memory consistency effects: Actions in a thread prior to the * submission of a {@code Runnable} or {@code Callable} task to an @@ -214,7 +210,6 @@ public interface ExecutorService extends Executor { boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException; - /** * Submits a value-returning task for execution and returns a * Future representing the pending results of the task. The @@ -286,7 +281,6 @@ public interface ExecutorService extends Executor { * @throws RejectedExecutionException if any task cannot be * scheduled for execution */ - List> invokeAll(Collection> tasks) throws InterruptedException; diff --git a/jdk/src/share/classes/java/util/concurrent/Executors.java b/jdk/src/share/classes/java/util/concurrent/Executors.java index 4ff71418422..723dc320980 100644 --- a/jdk/src/share/classes/java/util/concurrent/Executors.java +++ b/jdk/src/share/classes/java/util/concurrent/Executors.java @@ -686,16 +686,16 @@ public class Executors { super(executor); e = executor; } - public ScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) { + public ScheduledFuture schedule(Runnable command, long delay, TimeUnit unit) { return e.schedule(command, delay, unit); } public ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit) { return e.schedule(callable, delay, unit); } - public ScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { + public ScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { return e.scheduleAtFixedRate(command, initialDelay, period, unit); } - public ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { + public ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { return e.scheduleWithFixedDelay(command, initialDelay, delay, unit); } } diff --git a/jdk/src/share/classes/java/util/concurrent/Future.java b/jdk/src/share/classes/java/util/concurrent/Future.java index 2aab18ed346..74ded1836c3 100644 --- a/jdk/src/share/classes/java/util/concurrent/Future.java +++ b/jdk/src/share/classes/java/util/concurrent/Future.java @@ -76,12 +76,12 @@ package java.util.concurrent; * implements Runnable, and so may be executed by an Executor. * For example, the above construction with submit could be replaced by: *

 {@code
- *     FutureTask future =
- *       new FutureTask(new Callable() {
- *         public String call() {
- *           return searcher.search(target);
- *       }});
- *     executor.execute(future);}
+ * FutureTask future = + * new FutureTask(new Callable() { + * public String call() { + * return searcher.search(target); + * }}); + * executor.execute(future);} * *

Memory consistency effects: Actions taken by the asynchronous computation * happen-before diff --git a/jdk/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java b/jdk/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java index 60a18d0dba3..b79bc9444e3 100644 --- a/jdk/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java +++ b/jdk/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java @@ -73,7 +73,7 @@ import java.util.concurrent.locks.ReentrantLock; */ public class LinkedBlockingDeque extends AbstractQueue - implements BlockingDeque, java.io.Serializable { + implements BlockingDeque, java.io.Serializable { /* * Implemented as a simple doubly-linked list protected by a @@ -922,8 +922,7 @@ public class LinkedBlockingDeque * The following code can be used to dump the deque into a newly * allocated array of {@code String}: * - *

-     *     String[] y = x.toArray(new String[0]);
+ *
 {@code String[] y = x.toArray(new String[0]);}
* * Note that {@code toArray(new Object[0])} is identical in function to * {@code toArray()}. @@ -1045,7 +1044,7 @@ public class LinkedBlockingDeque /** * The next node to return in next() */ - Node next; + Node next; /** * nextItem holds on to item fields because once we claim that @@ -1153,11 +1152,10 @@ public class LinkedBlockingDeque } /** - * Save the state of this deque to a stream (that is, serialize it). + * Saves this deque to a stream (that is, serializes it). * * @serialData The capacity (int), followed by elements (each an * {@code Object}) in the proper order, followed by a null - * @param s the stream */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { @@ -1177,9 +1175,7 @@ public class LinkedBlockingDeque } /** - * Reconstitute this deque from a stream (that is, - * deserialize it). - * @param s the stream + * Reconstitutes this deque from a stream (that is, deserializes it). */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { diff --git a/jdk/src/share/classes/java/util/concurrent/LinkedBlockingQueue.java b/jdk/src/share/classes/java/util/concurrent/LinkedBlockingQueue.java index d1a6d5a0b58..e95e0a32af8 100644 --- a/jdk/src/share/classes/java/util/concurrent/LinkedBlockingQueue.java +++ b/jdk/src/share/classes/java/util/concurrent/LinkedBlockingQueue.java @@ -73,7 +73,6 @@ import java.util.NoSuchElementException; * @since 1.5 * @author Doug Lea * @param the type of elements held in this collection - * */ public class LinkedBlockingQueue extends AbstractQueue implements BlockingQueue, java.io.Serializable { @@ -135,13 +134,13 @@ public class LinkedBlockingQueue extends AbstractQueue private final int capacity; /** Current number of elements */ - private final AtomicInteger count = new AtomicInteger(0); + private final AtomicInteger count = new AtomicInteger(); /** * Head of linked list. * Invariant: head.item == null */ - private transient Node head; + transient Node head; /** * Tail of linked list. @@ -291,7 +290,6 @@ public class LinkedBlockingQueue extends AbstractQueue } } - // this doc comment is overridden to remove the reference to collections // greater in size than Integer.MAX_VALUE /** @@ -430,7 +428,6 @@ public class LinkedBlockingQueue extends AbstractQueue return c >= 0; } - public E take() throws InterruptedException { E x; int c = -1; @@ -630,8 +627,7 @@ public class LinkedBlockingQueue extends AbstractQueue * The following code can be used to dump the queue into a newly * allocated array of {@code String}: * - *
-     *     String[] y = x.toArray(new String[0]);
+ *
 {@code String[] y = x.toArray(new String[0]);}
* * Note that {@code toArray(new Object[0])} is identical in function to * {@code toArray()}. @@ -777,7 +773,7 @@ public class LinkedBlockingQueue extends AbstractQueue * @return an iterator over the elements in this queue in proper sequence */ public Iterator iterator() { - return new Itr(); + return new Itr(); } private class Itr implements Iterator { @@ -860,12 +856,11 @@ public class LinkedBlockingQueue extends AbstractQueue } /** - * Save the state to a stream (that is, serialize it). + * Saves this queue to a stream (that is, serializes it). * * @serialData The capacity is emitted (int), followed by all of * its elements (each an {@code Object}) in the proper order, * followed by a null - * @param s the stream */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { @@ -887,10 +882,7 @@ public class LinkedBlockingQueue extends AbstractQueue } /** - * Reconstitute this queue instance from a stream (that is, - * deserialize it). - * - * @param s the stream + * Reconstitutes this queue from a stream (that is, deserializes it). */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { diff --git a/jdk/src/share/classes/java/util/concurrent/LinkedTransferQueue.java b/jdk/src/share/classes/java/util/concurrent/LinkedTransferQueue.java index 171523f1643..6b6e46a9264 100644 --- a/jdk/src/share/classes/java/util/concurrent/LinkedTransferQueue.java +++ b/jdk/src/share/classes/java/util/concurrent/LinkedTransferQueue.java @@ -695,7 +695,7 @@ public class LinkedTransferQueue extends AbstractQueue * @return matched item, or e if unmatched on interrupt or timeout */ private E awaitMatch(Node s, Node pred, E e, boolean timed, long nanos) { - long lastTime = timed ? System.nanoTime() : 0L; + final long deadline = timed ? System.nanoTime() + nanos : 0L; Thread w = Thread.currentThread(); int spins = -1; // initialized after first item and cancel checks ThreadLocalRandom randomYields = null; // bound if needed @@ -726,10 +726,9 @@ public class LinkedTransferQueue extends AbstractQueue s.waiter = w; // request unpark then recheck } else if (timed) { - long now = System.nanoTime(); - if ((nanos -= now - lastTime) > 0) + nanos = deadline - System.nanoTime(); + if (nanos > 0L) LockSupport.parkNanos(this, nanos); - lastTime = now; } else { LockSupport.park(this); @@ -1294,11 +1293,10 @@ public class LinkedTransferQueue extends AbstractQueue } /** - * Saves the state to a stream (that is, serializes it). + * Saves this queue to a stream (that is, serializes it). * * @serialData All of the elements (each an {@code E}) in * the proper order, followed by a null - * @param s the stream */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { @@ -1310,10 +1308,7 @@ public class LinkedTransferQueue extends AbstractQueue } /** - * Reconstitutes the Queue instance from a stream (that is, - * deserializes it). - * - * @param s the stream + * Reconstitutes this queue from a stream (that is, deserializes it). */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { diff --git a/jdk/src/share/classes/java/util/concurrent/RecursiveAction.java b/jdk/src/share/classes/java/util/concurrent/RecursiveAction.java index add4a54a44f..6796789dd6e 100644 --- a/jdk/src/share/classes/java/util/concurrent/RecursiveAction.java +++ b/jdk/src/share/classes/java/util/concurrent/RecursiveAction.java @@ -39,37 +39,49 @@ package java.util.concurrent; * A recursive resultless {@link ForkJoinTask}. This class * establishes conventions to parameterize resultless actions as * {@code Void} {@code ForkJoinTask}s. Because {@code null} is the - * only valid value of type {@code Void}, methods such as join always - * return {@code null} upon completion. + * only valid value of type {@code Void}, methods such as {@code join} + * always return {@code null} upon completion. * - *

Sample Usages. Here is a sketch of a ForkJoin sort that - * sorts a given {@code long[]} array: + *

Sample Usages. Here is a simple but complete ForkJoin + * sort that sorts a given {@code long[]} array: * *

 {@code
- * class SortTask extends RecursiveAction {
- *   final long[] array; final int lo; final int hi;
+ * static class SortTask extends RecursiveAction {
+ *   final long[] array; final int lo, hi;
  *   SortTask(long[] array, int lo, int hi) {
  *     this.array = array; this.lo = lo; this.hi = hi;
  *   }
+ *   SortTask(long[] array) { this(array, 0, array.length); }
  *   protected void compute() {
  *     if (hi - lo < THRESHOLD)
- *       sequentiallySort(array, lo, hi);
+ *       sortSequentially(lo, hi);
  *     else {
  *       int mid = (lo + hi) >>> 1;
  *       invokeAll(new SortTask(array, lo, mid),
  *                 new SortTask(array, mid, hi));
- *       merge(array, lo, hi);
+ *       merge(lo, mid, hi);
  *     }
  *   }
+ *   // implementation details follow:
+ *   final static int THRESHOLD = 1000;
+ *   void sortSequentially(int lo, int hi) {
+ *     Arrays.sort(array, lo, hi);
+ *   }
+ *   void merge(int lo, int mid, int hi) {
+ *     long[] buf = Arrays.copyOfRange(array, lo, mid);
+ *     for (int i = 0, j = lo, k = mid; i < buf.length; j++)
+ *       array[j] = (k == hi || buf[i] < array[k]) ?
+ *         buf[i++] : array[k++];
+ *   }
  * }}
* * You could then sort {@code anArray} by creating {@code new - * SortTask(anArray, 0, anArray.length-1) } and invoking it in a - * ForkJoinPool. As a more concrete simple example, the following - * task increments each element of an array: + * SortTask(anArray)} and invoking it in a ForkJoinPool. As a more + * concrete simple example, the following task increments each element + * of an array: *
 {@code
  * class IncrementTask extends RecursiveAction {
- *   final long[] array; final int lo; final int hi;
+ *   final long[] array; final int lo, hi;
  *   IncrementTask(long[] array, int lo, int hi) {
  *     this.array = array; this.lo = lo; this.hi = hi;
  *   }
diff --git a/jdk/src/share/classes/java/util/concurrent/RejectedExecutionException.java b/jdk/src/share/classes/java/util/concurrent/RejectedExecutionException.java
index 9e599453996..abc8fbed3da 100644
--- a/jdk/src/share/classes/java/util/concurrent/RejectedExecutionException.java
+++ b/jdk/src/share/classes/java/util/concurrent/RejectedExecutionException.java
@@ -78,8 +78,8 @@ public class RejectedExecutionException extends RuntimeException {
 
     /**
      * Constructs a RejectedExecutionException with the
-     * specified cause.  The detail message is set to: 
 (cause ==
-     * null ? null : cause.toString())
(which typically contains + * specified cause. The detail message is set to {@code (cause == + * null ? null : cause.toString())} (which typically contains * the class and detail message of cause). * * @param cause the cause (which is saved for later retrieval by the diff --git a/jdk/src/share/classes/java/util/concurrent/ScheduledExecutorService.java b/jdk/src/share/classes/java/util/concurrent/ScheduledExecutorService.java index 187d6a193d1..e60786a2910 100644 --- a/jdk/src/share/classes/java/util/concurrent/ScheduledExecutorService.java +++ b/jdk/src/share/classes/java/util/concurrent/ScheduledExecutorService.java @@ -34,8 +34,6 @@ */ package java.util.concurrent; -import java.util.concurrent.atomic.*; -import java.util.*; /** * An {@link ExecutorService} that can schedule commands to run after a given diff --git a/jdk/src/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java b/jdk/src/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java index 49195b87c69..f4085960357 100644 --- a/jdk/src/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java +++ b/jdk/src/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java @@ -223,7 +223,7 @@ public class ScheduledThreadPoolExecutor } /** - * Creates a one-shot action with given nanoTime-based trigger. + * Creates a one-shot action with given nanoTime-based trigger time. */ ScheduledFutureTask(Callable callable, long ns) { super(callable); @@ -237,7 +237,7 @@ public class ScheduledThreadPoolExecutor } public int compareTo(Delayed other) { - if (other == this) // compare zero ONLY if same object + if (other == this) // compare zero if same object return 0; if (other instanceof ScheduledFutureTask) { ScheduledFutureTask x = (ScheduledFutureTask)other; @@ -251,9 +251,8 @@ public class ScheduledThreadPoolExecutor else return 1; } - long d = (getDelay(NANOSECONDS) - - other.getDelay(NANOSECONDS)); - return (d == 0) ? 0 : ((d < 0) ? -1 : 1); + long diff = getDelay(NANOSECONDS) - other.getDelay(NANOSECONDS); + return (diff < 0) ? -1 : (diff > 0) ? 1 : 0; } /** @@ -862,7 +861,7 @@ public class ScheduledThreadPoolExecutor private final Condition available = lock.newCondition(); /** - * Set f's heapIndex if it is a ScheduledFutureTask. + * Sets f's heapIndex if it is a ScheduledFutureTask. */ private void setIndex(RunnableScheduledFuture f, int idx) { if (f instanceof ScheduledFutureTask) @@ -870,7 +869,7 @@ public class ScheduledThreadPoolExecutor } /** - * Sift element added at bottom up to its heap-ordered spot. + * Sifts element added at bottom up to its heap-ordered spot. * Call only when holding lock. */ private void siftUp(int k, RunnableScheduledFuture key) { @@ -888,7 +887,7 @@ public class ScheduledThreadPoolExecutor } /** - * Sift element added at top down to its heap-ordered spot. + * Sifts element added at top down to its heap-ordered spot. * Call only when holding lock. */ private void siftDown(int k, RunnableScheduledFuture key) { @@ -910,7 +909,7 @@ public class ScheduledThreadPoolExecutor } /** - * Resize the heap array. Call only when holding lock. + * Resizes the heap array. Call only when holding lock. */ private void grow() { int oldCapacity = queue.length; @@ -921,7 +920,7 @@ public class ScheduledThreadPoolExecutor } /** - * Find index of given object, or -1 if absent + * Finds index of given object, or -1 if absent. */ private int indexOf(Object x) { if (x != null) { @@ -1162,15 +1161,14 @@ public class ScheduledThreadPoolExecutor } /** - * Return and remove first element only if it is expired. + * Returns first element only if it is expired. * Used only by drainTo. Call only when holding lock. */ - private RunnableScheduledFuture pollExpired() { + private RunnableScheduledFuture peekExpired() { // assert lock.isHeldByCurrentThread(); RunnableScheduledFuture first = queue[0]; - if (first == null || first.getDelay(NANOSECONDS) > 0) - return null; - return finishPoll(first); + return (first == null || first.getDelay(NANOSECONDS) > 0) ? + null : first; } public int drainTo(Collection c) { @@ -1183,8 +1181,9 @@ public class ScheduledThreadPoolExecutor try { RunnableScheduledFuture first; int n = 0; - while ((first = pollExpired()) != null) { - c.add(first); + while ((first = peekExpired()) != null) { + c.add(first); // In this order, in case add() throws. + finishPoll(first); ++n; } return n; @@ -1205,8 +1204,9 @@ public class ScheduledThreadPoolExecutor try { RunnableScheduledFuture first; int n = 0; - while (n < maxElements && (first = pollExpired()) != null) { - c.add(first); + while (n < maxElements && (first = peekExpired()) != null) { + c.add(first); // In this order, in case add() throws. + finishPoll(first); ++n; } return n; diff --git a/jdk/src/share/classes/java/util/concurrent/Semaphore.java b/jdk/src/share/classes/java/util/concurrent/Semaphore.java index c144b492dbf..4ce1151780f 100644 --- a/jdk/src/share/classes/java/util/concurrent/Semaphore.java +++ b/jdk/src/share/classes/java/util/concurrent/Semaphore.java @@ -34,9 +34,8 @@ */ package java.util.concurrent; -import java.util.*; -import java.util.concurrent.locks.*; -import java.util.concurrent.atomic.*; +import java.util.Collection; +import java.util.concurrent.locks.AbstractQueuedSynchronizer; /** * A counting semaphore. Conceptually, a semaphore maintains a set of @@ -49,7 +48,7 @@ import java.util.concurrent.atomic.*; *

Semaphores are often used to restrict the number of threads than can * access some (physical or logical) resource. For example, here is * a class that uses a semaphore to control access to a pool of items: - *

+ *  
 {@code
  * class Pool {
  *   private static final int MAX_AVAILABLE = 100;
  *   private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
@@ -91,9 +90,7 @@ import java.util.concurrent.atomic.*;
  *     }
  *     return false;
  *   }
- *
- * }
- * 
+ * }}
* *

Before obtaining an item each thread must acquire a permit from * the semaphore, guaranteeing that an item is available for use. When @@ -111,7 +108,7 @@ import java.util.concurrent.atomic.*; * exclusion lock. This is more commonly known as a binary * semaphore, because it only has two states: one permit * available, or zero permits available. When used in this way, the - * binary semaphore has the property (unlike many {@link Lock} + * binary semaphore has the property (unlike many {@link java.util.concurrent.locks.Lock} * implementations), that the "lock" can be released by a * thread other than the owner (as semaphores have no notion of * ownership). This can be useful in some specialized contexts, such @@ -155,9 +152,7 @@ import java.util.concurrent.atomic.*; * * @since 1.5 * @author Doug Lea - * */ - public class Semaphore implements java.io.Serializable { private static final long serialVersionUID = -3222578661600680210L; /** All mechanics via AbstractQueuedSynchronizer subclass */ @@ -493,7 +488,6 @@ public class Semaphore implements java.io.Serializable { * * @param permits the number of permits to acquire * @throws IllegalArgumentException if {@code permits} is negative - * */ public void acquireUninterruptibly(int permits) { if (permits < 0) throw new IllegalArgumentException(); diff --git a/jdk/src/share/classes/java/util/concurrent/SynchronousQueue.java b/jdk/src/share/classes/java/util/concurrent/SynchronousQueue.java index 9d0d830c265..ee9b1218854 100644 --- a/jdk/src/share/classes/java/util/concurrent/SynchronousQueue.java +++ b/jdk/src/share/classes/java/util/concurrent/SynchronousQueue.java @@ -35,7 +35,8 @@ */ package java.util.concurrent; -import java.util.concurrent.locks.*; +import java.util.concurrent.locks.LockSupport; +import java.util.concurrent.locks.ReentrantLock; import java.util.*; /** @@ -222,7 +223,7 @@ public class SynchronousQueue extends AbstractQueue /** Node is fulfilling another unfulfilled DATA or REQUEST */ static final int FULFILLING = 2; - /** Return true if m has fulfilling bit set */ + /** Returns true if m has fulfilling bit set. */ static boolean isFulfilling(int m) { return (m & FULFILLING) != 0; } /** Node class for TransferStacks. */ @@ -430,9 +431,8 @@ public class SynchronousQueue extends AbstractQueue * and don't wait at all, so are trapped in transfer * method rather than calling awaitFulfill. */ - long lastTime = timed ? System.nanoTime() : 0; + final long deadline = timed ? System.nanoTime() + nanos : 0L; Thread w = Thread.currentThread(); - SNode h = head; int spins = (shouldSpin(s) ? (timed ? maxTimedSpins : maxUntimedSpins) : 0); for (;;) { @@ -442,10 +442,8 @@ public class SynchronousQueue extends AbstractQueue if (m != null) return m; if (timed) { - long now = System.nanoTime(); - nanos -= now - lastTime; - lastTime = now; - if (nanos <= 0) { + nanos = deadline - System.nanoTime(); + if (nanos <= 0L) { s.tryCancel(); continue; } @@ -737,7 +735,7 @@ public class SynchronousQueue extends AbstractQueue */ Object awaitFulfill(QNode s, E e, boolean timed, long nanos) { /* Same idea as TransferStack.awaitFulfill */ - long lastTime = timed ? System.nanoTime() : 0; + final long deadline = timed ? System.nanoTime() + nanos : 0L; Thread w = Thread.currentThread(); int spins = ((head.next == s) ? (timed ? maxTimedSpins : maxUntimedSpins) : 0); @@ -748,10 +746,8 @@ public class SynchronousQueue extends AbstractQueue if (x != e) return x; if (timed) { - long now = System.nanoTime(); - nanos -= now - lastTime; - lastTime = now; - if (nanos <= 0) { + nanos = deadline - System.nanoTime(); + if (nanos <= 0L) { s.tryCancel(e); continue; } @@ -874,9 +870,9 @@ public class SynchronousQueue extends AbstractQueue * @throws InterruptedException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ - public void put(E o) throws InterruptedException { - if (o == null) throw new NullPointerException(); - if (transferer.transfer(o, false, 0) == null) { + public void put(E e) throws InterruptedException { + if (e == null) throw new NullPointerException(); + if (transferer.transfer(e, false, 0) == null) { Thread.interrupted(); throw new InterruptedException(); } @@ -891,10 +887,10 @@ public class SynchronousQueue extends AbstractQueue * @throws InterruptedException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ - public boolean offer(E o, long timeout, TimeUnit unit) + public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException { - if (o == null) throw new NullPointerException(); - if (transferer.transfer(o, true, unit.toNanos(timeout)) != null) + if (e == null) throw new NullPointerException(); + if (transferer.transfer(e, true, unit.toNanos(timeout)) != null) return true; if (!Thread.interrupted()) return false; @@ -1162,9 +1158,7 @@ public class SynchronousQueue extends AbstractQueue private WaitQueue waitingConsumers; /** - * Saves the state to a stream (that is, serializes it). - * - * @param s the stream + * Saves this queue to a stream (that is, serializes it). */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { @@ -1182,6 +1176,9 @@ public class SynchronousQueue extends AbstractQueue s.defaultWriteObject(); } + /** + * Reconstitutes this queue from a stream (that is, deserializes it). + */ private void readObject(final java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); diff --git a/jdk/src/share/classes/java/util/concurrent/ThreadFactory.java b/jdk/src/share/classes/java/util/concurrent/ThreadFactory.java index 9274abc5f8d..a0e21e2113e 100644 --- a/jdk/src/share/classes/java/util/concurrent/ThreadFactory.java +++ b/jdk/src/share/classes/java/util/concurrent/ThreadFactory.java @@ -42,13 +42,12 @@ package java.util.concurrent; * *

* The simplest implementation of this interface is just: - *

+ *  
 {@code
  * class SimpleThreadFactory implements ThreadFactory {
  *   public Thread newThread(Runnable r) {
  *     return new Thread(r);
  *   }
- * }
- * 
+ * }}
* * The {@link Executors#defaultThreadFactory} method provides a more * useful simple implementation, that sets the created thread context diff --git a/jdk/src/share/classes/java/util/concurrent/TimeUnit.java b/jdk/src/share/classes/java/util/concurrent/TimeUnit.java index f756759e8fd..ab3aa854f35 100644 --- a/jdk/src/share/classes/java/util/concurrent/TimeUnit.java +++ b/jdk/src/share/classes/java/util/concurrent/TimeUnit.java @@ -52,14 +52,14 @@ package java.util.concurrent; * the following code will timeout in 50 milliseconds if the {@link * java.util.concurrent.locks.Lock lock} is not available: * - *
  Lock lock = ...;
- *  if (lock.tryLock(50L, TimeUnit.MILLISECONDS)) ...
- * 
+ *
 {@code
+ * Lock lock = ...;
+ * if (lock.tryLock(50L, TimeUnit.MILLISECONDS)) ...}
+ * * while this code will timeout in 50 seconds: - *
- *  Lock lock = ...;
- *  if (lock.tryLock(50L, TimeUnit.SECONDS)) ...
- * 
+ *
 {@code
+ * Lock lock = ...;
+ * if (lock.tryLock(50L, TimeUnit.SECONDS)) ...}
* * Note however, that there is no guarantee that a particular timeout * implementation will be able to notice the passage of time at the diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicInteger.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicInteger.java index 1bc7fa2aa44..0d509cda035 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicInteger.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicInteger.java @@ -245,7 +245,6 @@ public class AtomicInteger extends Number implements java.io.Serializable { return Integer.toString(get()); } - /** * Returns the value of this {@code AtomicInteger} as an {@code int}. */ diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java index dc26f4c0ba7..a692479ad9c 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java @@ -59,7 +59,7 @@ import java.security.PrivilegedActionException; * @author Doug Lea * @param The type of the object holding the updatable field */ -public abstract class AtomicIntegerFieldUpdater { +public abstract class AtomicIntegerFieldUpdater { /** * Creates and returns an updater for objects with the given field. * The Class argument is needed to check that reflective types and @@ -274,9 +274,9 @@ public abstract class AtomicIntegerFieldUpdater { private final Class cclass; AtomicIntegerFieldUpdaterImpl(final Class tclass, final String fieldName) { - Field field = null; - Class caller = null; - int modifiers = 0; + final Field field; + final Class caller; + final int modifiers; try { field = AccessController.doPrivileged( new PrivilegedExceptionAction() { diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLong.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLong.java index f503d577d1b..7813aad04f4 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLong.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLong.java @@ -259,7 +259,6 @@ public class AtomicLong extends Number implements java.io.Serializable { return Long.toString(get()); } - /** * Returns the value of this {@code AtomicLong} as an {@code int} * after a narrowing primitive conversion. diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java index 3311aecdbfb..8b80684d848 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java @@ -59,7 +59,7 @@ import java.security.PrivilegedActionException; * @author Doug Lea * @param The type of the object holding the updatable field */ -public abstract class AtomicLongFieldUpdater { +public abstract class AtomicLongFieldUpdater { /** * Creates and returns an updater for objects with the given field. * The Class argument is needed to check that reflective types and @@ -274,9 +274,9 @@ public abstract class AtomicLongFieldUpdater { private final Class cclass; CASUpdater(final Class tclass, final String fieldName) { - Field field = null; - Class caller = null; - int modifiers = 0; + final Field field; + final Class caller; + final int modifiers; try { field = AccessController.doPrivileged( new PrivilegedExceptionAction() { diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReference.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReference.java index 978664e2d83..8bbc25c696e 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReference.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReference.java @@ -44,7 +44,7 @@ import sun.misc.Unsafe; * @author Doug Lea * @param The type of object referred to by this reference */ -public class AtomicReference implements java.io.Serializable { +public class AtomicReference implements java.io.Serializable { private static final long serialVersionUID = -1848883965231344442L; private static final Unsafe unsafe = Unsafe.getUnsafe(); diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java index 8459e7c4f80..015523ff393 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java @@ -35,8 +35,8 @@ package java.util.concurrent.atomic; -import java.lang.reflect.Array; import java.util.Arrays; +import java.lang.reflect.Array; import sun.misc.Unsafe; /** @@ -151,7 +151,6 @@ public class AtomicReferenceArray implements java.io.Serializable { unsafe.putOrderedObject(array, checkedByteOffset(i), newValue); } - /** * Atomically sets the element at position {@code i} to the given * value and returns the old value. @@ -225,10 +224,10 @@ public class AtomicReferenceArray implements java.io.Serializable { /** * Reconstitutes the instance from a stream (that is, deserializes it). - * @param s the stream */ private void readObject(java.io.ObjectInputStream s) - throws java.io.IOException, ClassNotFoundException { + throws java.io.IOException, ClassNotFoundException, + java.io.InvalidObjectException { // Note: This must be changed if any additional fields are defined Object a = s.readFields().get("array", null); if (a == null || !a.getClass().isArray()) diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java index bba703e67ec..2bb1fae40d7 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java @@ -206,10 +206,10 @@ public abstract class AtomicReferenceFieldUpdater { AtomicReferenceFieldUpdaterImpl(final Class tclass, Class vclass, final String fieldName) { - Field field = null; - Class fieldClass = null; - Class caller = null; - int modifiers = 0; + final Field field; + final Class fieldClass; + final Class caller; + final int modifiers; try { field = AccessController.doPrivileged( new PrivilegedExceptionAction() { @@ -220,12 +220,12 @@ public abstract class AtomicReferenceFieldUpdater { caller = sun.reflect.Reflection.getCallerClass(3); modifiers = field.getModifiers(); sun.reflect.misc.ReflectUtil.ensureMemberAccess( - caller, tclass, null, modifiers); + caller, tclass, null, modifiers); ClassLoader cl = tclass.getClassLoader(); ClassLoader ccl = caller.getClassLoader(); if ((ccl != null) && (ccl != cl) && ((cl == null) || !isAncestor(cl, ccl))) { - sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); + sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); } fieldClass = field.getType(); } catch (PrivilegedActionException pae) { @@ -315,7 +315,7 @@ public abstract class AtomicReferenceFieldUpdater { } @SuppressWarnings("unchecked") - public V get(T obj) { + public V get(T obj) { if (obj == null || obj.getClass() != tclass || cclass != null) targetCheck(obj); return (V)unsafe.getObjectVolatile(obj, offset); @@ -326,14 +326,14 @@ public abstract class AtomicReferenceFieldUpdater { return; } throw new RuntimeException( - new IllegalAccessException("Class " + - cclass.getName() + - " can not access a protected member of class " + - tclass.getName() + - " using an instance of " + - obj.getClass().getName() - ) - ); + new IllegalAccessException("Class " + + cclass.getName() + + " can not access a protected member of class " + + tclass.getName() + + " using an instance of " + + obj.getClass().getName() + ) + ); } } } diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/package-info.java b/jdk/src/share/classes/java/util/concurrent/atomic/package-info.java index 7c0ba5e8618..5cc25956255 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/package-info.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/package-info.java @@ -40,9 +40,7 @@ * array elements to those that also provide an atomic conditional update * operation of the form: * - *
- *   boolean compareAndSet(expectedValue, updateValue);
- * 
+ *
 {@code boolean compareAndSet(expectedValue, updateValue);}
* *

This method (which varies in argument types across different * classes) atomically sets a variable to the {@code updateValue} if it @@ -69,19 +67,36 @@ * {@code AtomicInteger} provide atomic increment methods. One * application is to generate sequence numbers, as in: * - *

+ *  
 {@code
  * class Sequencer {
  *   private final AtomicLong sequenceNumber
  *     = new AtomicLong(0);
  *   public long next() {
  *     return sequenceNumber.getAndIncrement();
  *   }
- * }
- * 
+ * }}
+ * + *

It is straightforward to define new utility functions that, like + * {@code getAndIncrement}, apply a function to a value atomically. + * For example, given some transformation + *

 {@code long transform(long input)}
+ * + * write your utility method as follows: + *
 {@code
+ * long getAndTransform(AtomicLong var) {
+ *   while (true) {
+ *     long current = var.get();
+ *     long next = transform(current);
+ *     if (var.compareAndSet(current, next))
+ *         return current;
+ *         // return next; for transformAndGet
+ *   }
+ * }}
* *

The memory effects for accesses and updates of atomics generally - * follow the rules for volatiles, as stated in section 17.4 of - * The Java™ Language Specification. + * follow the rules for volatiles, as stated in + * + * The Java Language Specification, Third Edition (17.4 Memory Model): * *

    * @@ -189,9 +204,9 @@ * {@code byte} values, and cast appropriately. * * You can also hold floats using - * {@link java.lang.Float#floatToIntBits} and + * {@link java.lang.Float#floatToRawIntBits} and * {@link java.lang.Float#intBitsToFloat} conversions, and doubles using - * {@link java.lang.Double#doubleToLongBits} and + * {@link java.lang.Double#doubleToRawLongBits} and * {@link java.lang.Double#longBitsToDouble} conversions. * * @since 1.5 diff --git a/jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java b/jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java index 15490bd36af..46ad577cf10 100644 --- a/jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java +++ b/jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java @@ -34,9 +34,10 @@ */ package java.util.concurrent.locks; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.atomic.*; +import java.util.concurrent.TimeUnit; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; import sun.misc.Unsafe; /** @@ -598,7 +599,7 @@ public abstract class AbstractQueuedLongSynchronizer /** * Convenience method to interrupt current thread. */ - private static void selfInterrupt() { + static void selfInterrupt() { Thread.currentThread().interrupt(); } @@ -686,8 +687,10 @@ public abstract class AbstractQueuedLongSynchronizer * @return {@code true} if acquired */ private boolean doAcquireNanos(long arg, long nanosTimeout) - throws InterruptedException { - long lastTime = System.nanoTime(); + throws InterruptedException { + if (nanosTimeout <= 0L) + return false; + final long deadline = System.nanoTime() + nanosTimeout; final Node node = addWaiter(Node.EXCLUSIVE); boolean failed = true; try { @@ -699,14 +702,12 @@ public abstract class AbstractQueuedLongSynchronizer failed = false; return true; } - if (nanosTimeout <= 0) + nanosTimeout = deadline - System.nanoTime(); + if (nanosTimeout <= 0L) return false; if (shouldParkAfterFailedAcquire(p, node) && nanosTimeout > spinForTimeoutThreshold) LockSupport.parkNanos(this, nanosTimeout); - long now = System.nanoTime(); - nanosTimeout -= now - lastTime; - lastTime = now; if (Thread.interrupted()) throw new InterruptedException(); } @@ -786,9 +787,10 @@ public abstract class AbstractQueuedLongSynchronizer * @return {@code true} if acquired */ private boolean doAcquireSharedNanos(long arg, long nanosTimeout) - throws InterruptedException { - - long lastTime = System.nanoTime(); + throws InterruptedException { + if (nanosTimeout <= 0L) + return false; + final long deadline = System.nanoTime() + nanosTimeout; final Node node = addWaiter(Node.SHARED); boolean failed = true; try { @@ -803,14 +805,12 @@ public abstract class AbstractQueuedLongSynchronizer return true; } } - if (nanosTimeout <= 0) + nanosTimeout = deadline - System.nanoTime(); + if (nanosTimeout <= 0L) return false; if (shouldParkAfterFailedAcquire(p, node) && nanosTimeout > spinForTimeoutThreshold) LockSupport.parkNanos(this, nanosTimeout); - long now = System.nanoTime(); - nanosTimeout -= now - lastTime; - lastTime = now; if (Thread.interrupted()) throw new InterruptedException(); } @@ -1260,7 +1260,7 @@ public abstract class AbstractQueuedLongSynchronizer * due to the queue being empty. * *

    This method is designed to be used by a fair synchronizer to - * avoid barging. + * avoid barging. * Such a synchronizer's {@link #tryAcquire} method should return * {@code false}, and its {@link #tryAcquireShared} method should * return a negative value, if this method returns {@code true} @@ -1520,8 +1520,6 @@ public abstract class AbstractQueuedLongSynchronizer * @throws NullPointerException if the condition is null */ public final boolean owns(ConditionObject condition) { - if (condition == null) - throw new NullPointerException(); return condition.isOwnedBy(this); } @@ -1742,9 +1740,8 @@ public abstract class AbstractQueuedLongSynchronizer * Implements uninterruptible condition wait. *

      *
    1. Save lock state returned by {@link #getState}. - *
    2. Invoke {@link #release} with - * saved state as argument, throwing - * IllegalMonitorStateException if it fails. + *
    3. Invoke {@link #release} with saved state as argument, + * throwing IllegalMonitorStateException if it fails. *
    4. Block until signalled. *
    5. Reacquire by invoking specialized version of * {@link #acquire} with saved state as argument. @@ -1803,9 +1800,8 @@ public abstract class AbstractQueuedLongSynchronizer *
        *
      1. If current thread is interrupted, throw InterruptedException. *
      2. Save lock state returned by {@link #getState}. - *
      3. Invoke {@link #release} with - * saved state as argument, throwing - * IllegalMonitorStateException if it fails. + *
      4. Invoke {@link #release} with saved state as argument, + * throwing IllegalMonitorStateException if it fails. *
      5. Block until signalled or interrupted. *
      6. Reacquire by invoking specialized version of * {@link #acquire} with saved state as argument. @@ -1836,9 +1832,8 @@ public abstract class AbstractQueuedLongSynchronizer *
          *
        1. If current thread is interrupted, throw InterruptedException. *
        2. Save lock state returned by {@link #getState}. - *
        3. Invoke {@link #release} with - * saved state as argument, throwing - * IllegalMonitorStateException if it fails. + *
        4. Invoke {@link #release} with saved state as argument, + * throwing IllegalMonitorStateException if it fails. *
        5. Block until signalled, interrupted, or timed out. *
        6. Reacquire by invoking specialized version of * {@link #acquire} with saved state as argument. @@ -1851,20 +1846,18 @@ public abstract class AbstractQueuedLongSynchronizer throw new InterruptedException(); Node node = addConditionWaiter(); long savedState = fullyRelease(node); - long lastTime = System.nanoTime(); + final long deadline = System.nanoTime() + nanosTimeout; int interruptMode = 0; while (!isOnSyncQueue(node)) { if (nanosTimeout <= 0L) { transferAfterCancelledWait(node); break; } - LockSupport.parkNanos(this, nanosTimeout); + if (nanosTimeout >= spinForTimeoutThreshold) + LockSupport.parkNanos(this, nanosTimeout); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; - - long now = System.nanoTime(); - nanosTimeout -= now - lastTime; - lastTime = now; + nanosTimeout = deadline - System.nanoTime(); } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; @@ -1872,7 +1865,7 @@ public abstract class AbstractQueuedLongSynchronizer unlinkCancelledWaiters(); if (interruptMode != 0) reportInterruptAfterWait(interruptMode); - return nanosTimeout - (System.nanoTime() - lastTime); + return deadline - System.nanoTime(); } /** @@ -1880,9 +1873,8 @@ public abstract class AbstractQueuedLongSynchronizer *
            *
          1. If current thread is interrupted, throw InterruptedException. *
          2. Save lock state returned by {@link #getState}. - *
          3. Invoke {@link #release} with - * saved state as argument, throwing - * IllegalMonitorStateException if it fails. + *
          4. Invoke {@link #release} with saved state as argument, + * throwing IllegalMonitorStateException if it fails. *
          5. Block until signalled, interrupted, or timed out. *
          6. Reacquire by invoking specialized version of * {@link #acquire} with saved state as argument. @@ -1892,8 +1884,6 @@ public abstract class AbstractQueuedLongSynchronizer */ public final boolean awaitUntil(Date deadline) throws InterruptedException { - if (deadline == null) - throw new NullPointerException(); long abstime = deadline.getTime(); if (Thread.interrupted()) throw new InterruptedException(); @@ -1924,9 +1914,8 @@ public abstract class AbstractQueuedLongSynchronizer *
              *
            1. If current thread is interrupted, throw InterruptedException. *
            2. Save lock state returned by {@link #getState}. - *
            3. Invoke {@link #release} with - * saved state as argument, throwing - * IllegalMonitorStateException if it fails. + *
            4. Invoke {@link #release} with saved state as argument, + * throwing IllegalMonitorStateException if it fails. *
            5. Block until signalled, interrupted, or timed out. *
            6. Reacquire by invoking specialized version of * {@link #acquire} with saved state as argument. @@ -1936,14 +1925,12 @@ public abstract class AbstractQueuedLongSynchronizer */ public final boolean await(long time, TimeUnit unit) throws InterruptedException { - if (unit == null) - throw new NullPointerException(); long nanosTimeout = unit.toNanos(time); if (Thread.interrupted()) throw new InterruptedException(); Node node = addConditionWaiter(); long savedState = fullyRelease(node); - long lastTime = System.nanoTime(); + final long deadline = System.nanoTime() + nanosTimeout; boolean timedout = false; int interruptMode = 0; while (!isOnSyncQueue(node)) { @@ -1955,9 +1942,7 @@ public abstract class AbstractQueuedLongSynchronizer LockSupport.parkNanos(this, nanosTimeout); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; - long now = System.nanoTime(); - nanosTimeout -= now - lastTime; - lastTime = now; + nanosTimeout = deadline - System.nanoTime(); } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; diff --git a/jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java b/jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java index 0da0eaeca70..6f39256c0d6 100644 --- a/jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java +++ b/jdk/src/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java @@ -34,9 +34,10 @@ */ package java.util.concurrent.locks; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.atomic.*; +import java.util.concurrent.TimeUnit; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; import sun.misc.Unsafe; /** @@ -194,7 +195,7 @@ import sun.misc.Unsafe; * It also supports conditions and exposes * one of the instrumentation methods: * - *
              + *  
               {@code
                * class Mutex implements Lock, java.io.Serializable {
                *
                *   // Our internal helper class
              @@ -250,15 +251,15 @@ import sun.misc.Unsafe;
                *       throws InterruptedException {
                *     return sync.tryAcquireNanos(1, unit.toNanos(timeout));
                *   }
              - * }
              - * 
              + * }}
              * - *

              Here is a latch class that is like a {@link CountDownLatch} + *

              Here is a latch class that is like a + * {@link java.util.concurrent.CountDownLatch CountDownLatch} * except that it only requires a single signal to * fire. Because a latch is non-exclusive, it uses the shared * acquire and release methods. * - *

              + *  
               {@code
                * class BooleanLatch {
                *
                *   private static class Sync extends AbstractQueuedSynchronizer {
              @@ -280,8 +281,7 @@ import sun.misc.Unsafe;
                *   public void await() throws InterruptedException {
                *     sync.acquireSharedInterruptibly(1);
                *   }
              - * }
              - * 
              + * }}
              * * @since 1.5 * @author Doug Lea @@ -821,7 +821,7 @@ public abstract class AbstractQueuedSynchronizer /** * Convenience method to interrupt current thread. */ - private static void selfInterrupt() { + static void selfInterrupt() { Thread.currentThread().interrupt(); } @@ -909,8 +909,10 @@ public abstract class AbstractQueuedSynchronizer * @return {@code true} if acquired */ private boolean doAcquireNanos(int arg, long nanosTimeout) - throws InterruptedException { - long lastTime = System.nanoTime(); + throws InterruptedException { + if (nanosTimeout <= 0L) + return false; + final long deadline = System.nanoTime() + nanosTimeout; final Node node = addWaiter(Node.EXCLUSIVE); boolean failed = true; try { @@ -922,14 +924,12 @@ public abstract class AbstractQueuedSynchronizer failed = false; return true; } - if (nanosTimeout <= 0) + nanosTimeout = deadline - System.nanoTime(); + if (nanosTimeout <= 0L) return false; if (shouldParkAfterFailedAcquire(p, node) && nanosTimeout > spinForTimeoutThreshold) LockSupport.parkNanos(this, nanosTimeout); - long now = System.nanoTime(); - nanosTimeout -= now - lastTime; - lastTime = now; if (Thread.interrupted()) throw new InterruptedException(); } @@ -1009,9 +1009,10 @@ public abstract class AbstractQueuedSynchronizer * @return {@code true} if acquired */ private boolean doAcquireSharedNanos(int arg, long nanosTimeout) - throws InterruptedException { - - long lastTime = System.nanoTime(); + throws InterruptedException { + if (nanosTimeout <= 0L) + return false; + final long deadline = System.nanoTime() + nanosTimeout; final Node node = addWaiter(Node.SHARED); boolean failed = true; try { @@ -1026,14 +1027,12 @@ public abstract class AbstractQueuedSynchronizer return true; } } - if (nanosTimeout <= 0) + nanosTimeout = deadline - System.nanoTime(); + if (nanosTimeout <= 0L) return false; if (shouldParkAfterFailedAcquire(p, node) && nanosTimeout > spinForTimeoutThreshold) LockSupport.parkNanos(this, nanosTimeout); - long now = System.nanoTime(); - nanosTimeout -= now - lastTime; - lastTime = now; if (Thread.interrupted()) throw new InterruptedException(); } @@ -1743,8 +1742,6 @@ public abstract class AbstractQueuedSynchronizer * @throws NullPointerException if the condition is null */ public final boolean owns(ConditionObject condition) { - if (condition == null) - throw new NullPointerException(); return condition.isOwnedBy(this); } @@ -1963,9 +1960,8 @@ public abstract class AbstractQueuedSynchronizer * Implements uninterruptible condition wait. *
                *
              1. Save lock state returned by {@link #getState}. - *
              2. Invoke {@link #release} with - * saved state as argument, throwing - * IllegalMonitorStateException if it fails. + *
              3. Invoke {@link #release} with saved state as argument, + * throwing IllegalMonitorStateException if it fails. *
              4. Block until signalled. *
              5. Reacquire by invoking specialized version of * {@link #acquire} with saved state as argument. @@ -2024,9 +2020,8 @@ public abstract class AbstractQueuedSynchronizer *
                  *
                1. If current thread is interrupted, throw InterruptedException. *
                2. Save lock state returned by {@link #getState}. - *
                3. Invoke {@link #release} with - * saved state as argument, throwing - * IllegalMonitorStateException if it fails. + *
                4. Invoke {@link #release} with saved state as argument, + * throwing IllegalMonitorStateException if it fails. *
                5. Block until signalled or interrupted. *
                6. Reacquire by invoking specialized version of * {@link #acquire} with saved state as argument. @@ -2057,9 +2052,8 @@ public abstract class AbstractQueuedSynchronizer *
                    *
                  1. If current thread is interrupted, throw InterruptedException. *
                  2. Save lock state returned by {@link #getState}. - *
                  3. Invoke {@link #release} with - * saved state as argument, throwing - * IllegalMonitorStateException if it fails. + *
                  4. Invoke {@link #release} with saved state as argument, + * throwing IllegalMonitorStateException if it fails. *
                  5. Block until signalled, interrupted, or timed out. *
                  6. Reacquire by invoking specialized version of * {@link #acquire} with saved state as argument. @@ -2072,20 +2066,18 @@ public abstract class AbstractQueuedSynchronizer throw new InterruptedException(); Node node = addConditionWaiter(); int savedState = fullyRelease(node); - long lastTime = System.nanoTime(); + final long deadline = System.nanoTime() + nanosTimeout; int interruptMode = 0; while (!isOnSyncQueue(node)) { if (nanosTimeout <= 0L) { transferAfterCancelledWait(node); break; } - LockSupport.parkNanos(this, nanosTimeout); + if (nanosTimeout >= spinForTimeoutThreshold) + LockSupport.parkNanos(this, nanosTimeout); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; - - long now = System.nanoTime(); - nanosTimeout -= now - lastTime; - lastTime = now; + nanosTimeout = deadline - System.nanoTime(); } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; @@ -2093,7 +2085,7 @@ public abstract class AbstractQueuedSynchronizer unlinkCancelledWaiters(); if (interruptMode != 0) reportInterruptAfterWait(interruptMode); - return nanosTimeout - (System.nanoTime() - lastTime); + return deadline - System.nanoTime(); } /** @@ -2101,9 +2093,8 @@ public abstract class AbstractQueuedSynchronizer *
                      *
                    1. If current thread is interrupted, throw InterruptedException. *
                    2. Save lock state returned by {@link #getState}. - *
                    3. Invoke {@link #release} with - * saved state as argument, throwing - * IllegalMonitorStateException if it fails. + *
                    4. Invoke {@link #release} with saved state as argument, + * throwing IllegalMonitorStateException if it fails. *
                    5. Block until signalled, interrupted, or timed out. *
                    6. Reacquire by invoking specialized version of * {@link #acquire} with saved state as argument. @@ -2113,8 +2104,6 @@ public abstract class AbstractQueuedSynchronizer */ public final boolean awaitUntil(Date deadline) throws InterruptedException { - if (deadline == null) - throw new NullPointerException(); long abstime = deadline.getTime(); if (Thread.interrupted()) throw new InterruptedException(); @@ -2145,9 +2134,8 @@ public abstract class AbstractQueuedSynchronizer *
                        *
                      1. If current thread is interrupted, throw InterruptedException. *
                      2. Save lock state returned by {@link #getState}. - *
                      3. Invoke {@link #release} with - * saved state as argument, throwing - * IllegalMonitorStateException if it fails. + *
                      4. Invoke {@link #release} with saved state as argument, + * throwing IllegalMonitorStateException if it fails. *
                      5. Block until signalled, interrupted, or timed out. *
                      6. Reacquire by invoking specialized version of * {@link #acquire} with saved state as argument. @@ -2157,14 +2145,12 @@ public abstract class AbstractQueuedSynchronizer */ public final boolean await(long time, TimeUnit unit) throws InterruptedException { - if (unit == null) - throw new NullPointerException(); long nanosTimeout = unit.toNanos(time); if (Thread.interrupted()) throw new InterruptedException(); Node node = addConditionWaiter(); int savedState = fullyRelease(node); - long lastTime = System.nanoTime(); + final long deadline = System.nanoTime() + nanosTimeout; boolean timedout = false; int interruptMode = 0; while (!isOnSyncQueue(node)) { @@ -2176,9 +2162,7 @@ public abstract class AbstractQueuedSynchronizer LockSupport.parkNanos(this, nanosTimeout); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; - long now = System.nanoTime(); - nanosTimeout -= now - lastTime; - lastTime = now; + nanosTimeout = deadline - System.nanoTime(); } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; diff --git a/jdk/src/share/classes/java/util/concurrent/locks/Condition.java b/jdk/src/share/classes/java/util/concurrent/locks/Condition.java index 8bdbedea398..02cbee904bc 100644 --- a/jdk/src/share/classes/java/util/concurrent/locks/Condition.java +++ b/jdk/src/share/classes/java/util/concurrent/locks/Condition.java @@ -34,7 +34,7 @@ */ package java.util.concurrent.locks; -import java.util.concurrent.*; +import java.util.concurrent.TimeUnit; import java.util.Date; /** @@ -360,10 +360,9 @@ public interface Condition { /** * Causes the current thread to wait until it is signalled or interrupted, * or the specified waiting time elapses. This method is behaviorally - * equivalent to:
                        - *
                        -     *   awaitNanos(unit.toNanos(time)) > 0
                        -     * 
                        + * equivalent to: + *
                         {@code awaitNanos(unit.toNanos(time)) > 0}
                        + * * @param time the maximum time to wait * @param unit the time unit of the {@code time} argument * @return {@code false} if the waiting time detectably elapsed diff --git a/jdk/src/share/classes/java/util/concurrent/locks/Lock.java b/jdk/src/share/classes/java/util/concurrent/locks/Lock.java index 8ed346c2914..d9ae1bcc4ed 100644 --- a/jdk/src/share/classes/java/util/concurrent/locks/Lock.java +++ b/jdk/src/share/classes/java/util/concurrent/locks/Lock.java @@ -77,14 +77,14 @@ import java.util.concurrent.TimeUnit; * methods and statements. In most cases, the following idiom * should be used: * - *
                             Lock l = ...;
                        - *     l.lock();
                        - *     try {
                        - *         // access the resource protected by this lock
                        - *     } finally {
                        - *         l.unlock();
                        - *     }
                        - * 
                        + *
                         {@code
                        + * Lock l = ...;
                        + * l.lock();
                        + * try {
                        + *   // access the resource protected by this lock
                        + * } finally {
                        + *   l.unlock();
                        + * }}
                        * * When locking and unlocking occur in different scopes, care must be * taken to ensure that all code that is executed while the lock is @@ -120,8 +120,9 @@ import java.util.concurrent.TimeUnit; * *

                        All {@code Lock} implementations must enforce the same * memory synchronization semantics as provided by the built-in monitor - * lock, as described in section 17.4 of - * The Java™ Language Specification: + * lock, as described in + * + * The Java Language Specification, Third Edition (17.4 Memory Model): *

                          *
                        • A successful {@code lock} operation has the same memory * synchronization effects as a successful Lock action. @@ -239,18 +240,18 @@ public interface Lock { * immediately with the value {@code false}. * *

                          A typical usage idiom for this method would be: - *

                          -     *      Lock lock = ...;
                          -     *      if (lock.tryLock()) {
                          -     *          try {
                          -     *              // manipulate protected state
                          -     *          } finally {
                          -     *              lock.unlock();
                          -     *          }
                          -     *      } else {
                          -     *          // perform alternative actions
                          -     *      }
                          -     * 
                          + *
                           {@code
                          +     * Lock lock = ...;
                          +     * if (lock.tryLock()) {
                          +     *   try {
                          +     *     // manipulate protected state
                          +     *   } finally {
                          +     *     lock.unlock();
                          +     *   }
                          +     * } else {
                          +     *   // perform alternative actions
                          +     * }}
                          + * * This usage ensures that the lock is unlocked if it was acquired, and * doesn't try to unlock if the lock was not acquired. * diff --git a/jdk/src/share/classes/java/util/concurrent/locks/LockSupport.java b/jdk/src/share/classes/java/util/concurrent/locks/LockSupport.java index 7b829f63a06..08bd8878a81 100644 --- a/jdk/src/share/classes/java/util/concurrent/locks/LockSupport.java +++ b/jdk/src/share/classes/java/util/concurrent/locks/LockSupport.java @@ -34,10 +34,8 @@ */ package java.util.concurrent.locks; -import java.util.concurrent.*; import sun.misc.Unsafe; - /** * Basic thread blocking primitives for creating locks and other * synchronization classes. @@ -78,7 +76,10 @@ import sun.misc.Unsafe; * higher-level synchronization utilities, and are not in themselves * useful for most concurrency control applications. The {@code park} * method is designed for use only in constructions of the form: - *
                          while (!canProceed()) { ... LockSupport.park(this); }
                          + * + *
                           {@code
                          + * while (!canProceed()) { ... LockSupport.park(this); }}
                          + * * where neither {@code canProceed} nor any other actions prior to the * call to {@code park} entail locking or blocking. Because only one * permit is associated with each thread, any intermediary uses of @@ -86,7 +87,7 @@ import sun.misc.Unsafe; * *

                          Sample Usage. Here is a sketch of a first-in-first-out * non-reentrant lock class: - *

                          {@code
                          + *  
                           {@code
                            * class FIFOMutex {
                            *   private final AtomicBoolean locked = new AtomicBoolean(false);
                            *   private final Queue waiters
                          @@ -116,7 +117,6 @@ import sun.misc.Unsafe;
                            *   }
                            * }}
                          */ - public class LockSupport { private LockSupport() {} // Cannot be instantiated. diff --git a/jdk/src/share/classes/java/util/concurrent/locks/ReentrantLock.java b/jdk/src/share/classes/java/util/concurrent/locks/ReentrantLock.java index 9952c8c93b8..5ca1335aaf6 100644 --- a/jdk/src/share/classes/java/util/concurrent/locks/ReentrantLock.java +++ b/jdk/src/share/classes/java/util/concurrent/locks/ReentrantLock.java @@ -34,9 +34,8 @@ */ package java.util.concurrent.locks; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.atomic.*; +import java.util.concurrent.TimeUnit; +import java.util.Collection; /** * A reentrant mutual exclusion {@link Lock} with the same basic @@ -73,7 +72,7 @@ import java.util.concurrent.atomic.*; * follow a call to {@code lock} with a {@code try} block, most * typically in a before/after construction such as: * - *
                          + *  
                           {@code
                            * class X {
                            *   private final ReentrantLock lock = new ReentrantLock();
                            *   // ...
                          @@ -86,8 +85,7 @@ import java.util.concurrent.atomic.*;
                            *       lock.unlock()
                            *     }
                            *   }
                          - * }
                          - * 
                          + * }}
                          * *

                          In addition to implementing the {@link Lock} interface, this * class defines methods {@code isLocked} and @@ -187,8 +185,7 @@ public class ReentrantLock implements Lock, java.io.Serializable { } /** - * Reconstitutes this lock instance from a stream. - * @param s the stream + * Reconstitutes the instance from a stream (that is, deserializes it). */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { @@ -383,8 +380,11 @@ public class ReentrantLock implements Lock, java.io.Serializable { * method. If you want a timed {@code tryLock} that does permit barging on * a fair lock then combine the timed and un-timed forms together: * - *

                          if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... }
                          -     * 
                          + *
                           {@code
                          +     * if (lock.tryLock() ||
                          +     *     lock.tryLock(timeout, unit)) {
                          +     *   ...
                          +     * }}
                          * *

                          If the current thread * already holds this lock then the hold count is incremented by one and @@ -438,7 +438,6 @@ public class ReentrantLock implements Lock, java.io.Serializable { * the lock could be acquired * @throws InterruptedException if the current thread is interrupted * @throws NullPointerException if the time unit is null - * */ public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { @@ -514,7 +513,7 @@ public class ReentrantLock implements Lock, java.io.Serializable { * not be entered with the lock already held then we can assert that * fact: * - *

                          +     *  
                           {@code
                                * class X {
                                *   ReentrantLock lock = new ReentrantLock();
                                *   // ...
                          @@ -527,8 +526,7 @@ public class ReentrantLock implements Lock, java.io.Serializable {
                                *       lock.unlock();
                                *     }
                                *   }
                          -     * }
                          -     * 
                          + * }}
                          * * @return the number of holds on this lock by the current thread, * or zero if this lock is not held by the current thread @@ -545,7 +543,7 @@ public class ReentrantLock implements Lock, java.io.Serializable { * testing. For example, a method that should only be called while * a lock is held can assert that this is the case: * - *
                          +     *  
                           {@code
                                * class X {
                                *   ReentrantLock lock = new ReentrantLock();
                                *   // ...
                          @@ -554,13 +552,12 @@ public class ReentrantLock implements Lock, java.io.Serializable {
                                *       assert lock.isHeldByCurrentThread();
                                *       // ... method body
                                *   }
                          -     * }
                          -     * 
                          + * }}
                          * *

                          It can also be used to ensure that a reentrant lock is used * in a non-reentrant manner, for example: * - *

                          +     *  
                           {@code
                                * class X {
                                *   ReentrantLock lock = new ReentrantLock();
                                *   // ...
                          @@ -574,8 +571,7 @@ public class ReentrantLock implements Lock, java.io.Serializable {
                                *           lock.unlock();
                                *       }
                                *   }
                          -     * }
                          -     * 
                          + * }}
                          * * @return {@code true} if current thread holds this lock and * {@code false} otherwise @@ -636,7 +632,6 @@ public class ReentrantLock implements Lock, java.io.Serializable { return sync.hasQueuedThreads(); } - /** * Queries whether the given thread is waiting to acquire this * lock. Note that because cancellations may occur at any time, a @@ -652,7 +647,6 @@ public class ReentrantLock implements Lock, java.io.Serializable { return sync.isQueued(thread); } - /** * Returns an estimate of the number of threads waiting to * acquire this lock. The value is only an estimate because the number of diff --git a/jdk/src/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java b/jdk/src/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java index fbafd3c5fdf..3698bab27bb 100644 --- a/jdk/src/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java +++ b/jdk/src/share/classes/java/util/concurrent/locks/ReentrantReadWriteLock.java @@ -34,9 +34,8 @@ */ package java.util.concurrent.locks; -import java.util.concurrent.*; -import java.util.concurrent.atomic.*; -import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.Collection; /** * An implementation of {@link ReadWriteLock} supporting similar @@ -62,7 +61,7 @@ import java.util.*; *
                          Fair mode *
                          When constructed as fair, threads contend for entry using an * approximately arrival-order policy. When the currently held lock - * is released either the longest-waiting single writer thread will + * is released, either the longest-waiting single writer thread will * be assigned the write lock, or if there is a group of reader threads * waiting longer than all waiting writer threads, that group will be * assigned the read lock. @@ -80,8 +79,8 @@ import java.util.*; * will block unless both the read lock and write lock are free (which * implies there are no waiting threads). (Note that the non-blocking * {@link ReadLock#tryLock()} and {@link WriteLock#tryLock()} methods - * do not honor this fair setting and will acquire the lock if it is - * possible, regardless of waiting threads.) + * do not honor this fair setting and will immediately acquire the lock + * if it is possible, regardless of waiting threads.) *

                          * * @@ -143,21 +142,21 @@ import java.util.*; * void processCachedData() { * rwl.readLock().lock(); * if (!cacheValid) { - * // Must release read lock before acquiring write lock - * rwl.readLock().unlock(); - * rwl.writeLock().lock(); - * try { - * // Recheck state because another thread might have - * // acquired write lock and changed state before we did. - * if (!cacheValid) { - * data = ... - * cacheValid = true; - * } - * // Downgrade by acquiring read lock before releasing write lock - * rwl.readLock().lock(); - * } finally { - * rwl.writeLock().unlock(); // Unlock write, still hold read - * } + * // Must release read lock before acquiring write lock + * rwl.readLock().unlock(); + * rwl.writeLock().lock(); + * try { + * // Recheck state because another thread might have + * // acquired write lock and changed state before we did. + * if (!cacheValid) { + * data = ... + * cacheValid = true; + * } + * // Downgrade by acquiring read lock before releasing write lock + * rwl.readLock().lock(); + * } finally { + * rwl.writeLock().unlock(); // Unlock write, still hold read + * } * } * * try { @@ -176,33 +175,33 @@ import java.util.*; * is a class using a TreeMap that is expected to be large and * concurrently accessed. * - *

                          {@code
                          + *  
                           {@code
                            * class RWDictionary {
                          - *    private final Map m = new TreeMap();
                          - *    private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
                          - *    private final Lock r = rwl.readLock();
                          - *    private final Lock w = rwl.writeLock();
                          + *   private final Map m = new TreeMap();
                          + *   private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
                          + *   private final Lock r = rwl.readLock();
                          + *   private final Lock w = rwl.writeLock();
                            *
                          - *    public Data get(String key) {
                          - *        r.lock();
                          - *        try { return m.get(key); }
                          - *        finally { r.unlock(); }
                          - *    }
                          - *    public String[] allKeys() {
                          - *        r.lock();
                          - *        try { return m.keySet().toArray(); }
                          - *        finally { r.unlock(); }
                          - *    }
                          - *    public Data put(String key, Data value) {
                          - *        w.lock();
                          - *        try { return m.put(key, value); }
                          - *        finally { w.unlock(); }
                          - *    }
                          - *    public void clear() {
                          - *        w.lock();
                          - *        try { m.clear(); }
                          - *        finally { w.unlock(); }
                          - *    }
                          + *   public Data get(String key) {
                          + *     r.lock();
                          + *     try { return m.get(key); }
                          + *     finally { r.unlock(); }
                          + *   }
                          + *   public String[] allKeys() {
                          + *     r.lock();
                          + *     try { return m.keySet().toArray(); }
                          + *     finally { r.unlock(); }
                          + *   }
                          + *   public Data put(String key, Data value) {
                          + *     w.lock();
                          + *     try { return m.put(key, value); }
                          + *     finally { w.unlock(); }
                          + *   }
                          + *   public void clear() {
                          + *     w.lock();
                          + *     try { m.clear(); }
                          + *     finally { w.unlock(); }
                          + *   }
                            * }}
                          * *

                          Implementation Notes

                          @@ -213,7 +212,6 @@ import java.util.*; * * @since 1.5 * @author Doug Lea - * */ public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable { @@ -654,8 +652,7 @@ public class ReentrantReadWriteLock } /** - * Reconstitute this lock instance from a stream - * @param s the stream + * Reconstitutes the instance from a stream (that is, deserializes it). */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { @@ -799,7 +796,7 @@ public class ReentrantReadWriteLock * * @return {@code true} if the read lock was acquired */ - public boolean tryLock() { + public boolean tryLock() { return sync.tryReadLock(); } @@ -819,8 +816,11 @@ public class ReentrantReadWriteLock * permit barging on a fair lock then combine the timed and * un-timed forms together: * - *
                          if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... }
                          -         * 
                          + *
                           {@code
                          +         * if (lock.tryLock() ||
                          +         *     lock.tryLock(timeout, unit)) {
                          +         *   ...
                          +         * }}
                          * *

                          If the write lock is held by another thread then the * current thread becomes disabled for thread scheduling @@ -866,7 +866,6 @@ public class ReentrantReadWriteLock * @return {@code true} if the read lock was acquired * @throws InterruptedException if the current thread is interrupted * @throws NullPointerException if the time unit is null - * */ public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { @@ -879,7 +878,7 @@ public class ReentrantReadWriteLock *

                          If the number of readers is now zero then the lock * is made available for write lock attempts. */ - public void unlock() { + public void unlock() { sync.releaseShared(1); } @@ -1049,8 +1048,11 @@ public class ReentrantReadWriteLock * that does permit barging on a fair lock then combine the * timed and un-timed forms together: * - *

                          if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... }
                          -         * 
                          + *
                           {@code
                          +         * if (lock.tryLock() ||
                          +         *     lock.tryLock(timeout, unit)) {
                          +         *   ...
                          +         * }}
                          * *

                          If the current thread already holds this lock then the * hold count is incremented by one and the method returns @@ -1108,7 +1110,6 @@ public class ReentrantReadWriteLock * * @throws InterruptedException if the current thread is interrupted * @throws NullPointerException if the time unit is null - * */ public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { diff --git a/jdk/src/share/classes/java/util/concurrent/package-info.java b/jdk/src/share/classes/java/util/concurrent/package-info.java index 8116e82cffa..4c56e0390df 100644 --- a/jdk/src/share/classes/java/util/concurrent/package-info.java +++ b/jdk/src/share/classes/java/util/concurrent/package-info.java @@ -188,7 +188,7 @@ * A {@code CopyOnWriteArrayList} is preferable to a synchronized * {@code ArrayList} when the expected number of reads and traversals * greatly outnumber the number of updates to a list. - + * *

                          The "Concurrent" prefix used with some classes in this package * is a shorthand indicating several differences from similar * "synchronized" classes. For example {@code java.util.Hashtable} and @@ -218,9 +218,8 @@ * *

                          Memory Consistency Properties

                          * - * Chapter 17 of - * The Java™ Language Specification - * defines the + * + * Chapter 17 of the Java Language Specification defines the * happens-before relation on memory operations such as reads and * writes of shared variables. The results of a write by one thread are * guaranteed to be visible to a read by another thread only if the write From f0534ca47014226e75d064c00f803f89d2e18f27 Mon Sep 17 00:00:00 2001 From: Alejandro Murillo Date: Fri, 26 Oct 2012 14:18:57 -0700 Subject: [PATCH 17/59] 8001663: new hotspot build - hs25-b08 Reviewed-by: jcoomes --- hotspot/make/hotspot_version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/make/hotspot_version b/hotspot/make/hotspot_version index 1f72e227aae..59320dbec54 100644 --- a/hotspot/make/hotspot_version +++ b/hotspot/make/hotspot_version @@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2012 HS_MAJOR_VER=25 HS_MINOR_VER=0 -HS_BUILD_NUMBER=07 +HS_BUILD_NUMBER=08 JDK_MAJOR_VER=1 JDK_MINOR_VER=8 From b9f46f00011bf3161108175484bd79e21cb1d5db Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Sat, 27 Oct 2012 09:18:29 +0100 Subject: [PATCH 18/59] 7176225: Remove JDBC-ODBC Bridge Reviewed-by: lancea, ohair, tbell --- jdk/make/common/Sanity.gmk | 1 - jdk/make/common/shared/Defs-solaris.gmk | 5 +- jdk/make/common/shared/Sanity.gmk | 1 - jdk/make/sun/Makefile | 8 +- jdk/make/sun/jdbc/Makefile | 142 ----------------------- jdk/makefiles/CompileNativeLibraries.gmk | 90 -------------- jdk/makefiles/CopyIntoClasses.gmk | 6 - jdk/makefiles/CreateJars.gmk | 1 - jdk/makefiles/GensrcMisc.gmk | 26 ----- 9 files changed, 3 insertions(+), 277 deletions(-) delete mode 100644 jdk/make/sun/jdbc/Makefile diff --git a/jdk/make/common/Sanity.gmk b/jdk/make/common/Sanity.gmk index 27fe5bdfa16..ab6b29c0a71 100644 --- a/jdk/make/common/Sanity.gmk +++ b/jdk/make/common/Sanity.gmk @@ -64,7 +64,6 @@ sanity-base: pre-sanity \ sane-math_iso \ sane-libCrun \ sane-unixccs_path \ - sane-odbcdir \ sane-msdevtools_path \ sane-dxsdk \ sane-compiler \ diff --git a/jdk/make/common/shared/Defs-solaris.gmk b/jdk/make/common/shared/Defs-solaris.gmk index ec1dd148f13..3caf73d1fdc 100644 --- a/jdk/make/common/shared/Defs-solaris.gmk +++ b/jdk/make/common/shared/Defs-solaris.gmk @@ -206,13 +206,12 @@ MAPFILE_WARNING=$(MAPFILE_WARNING-$(VARIANT)) # libjdgaSUNWffb.so # libjdgaSUNWm64.so # libxinerama.so -# The library libJdbcOdbc.so has also been given an exception. # The JNI/JVMTI demo libraries are also missing mapfiles, no exceptions yet. ifeq ($(ARCH_FAMILY),sparc) MAPFILE_EXCEPTIONS = \ - (libJdbcOdbc|libjdgaSUNWafb|libjdgaSUNWcg6|libjdgaSUNWffb|libjdgaSUNWm64|libxinerama) + (libjdgaSUNWafb|libjdgaSUNWcg6|libjdgaSUNWffb|libjdgaSUNWm64|libxinerama) else - MAPFILE_EXCEPTIONS = (libJdbcOdbc) + MAPFILE_EXCEPTIONS = () endif # Macro to check it's input file for banned dependencies and verify the diff --git a/jdk/make/common/shared/Sanity.gmk b/jdk/make/common/shared/Sanity.gmk index b6c340cfe91..3e50e9089d5 100644 --- a/jdk/make/common/shared/Sanity.gmk +++ b/jdk/make/common/shared/Sanity.gmk @@ -208,7 +208,6 @@ include $(JDK_MAKE_SHARED_DIR)/Sanity-Settings.gmk sane-docs_import \ sane-math_iso \ sane-libCrun \ - sane-odbcdir \ sane-msdevtools_path \ sane-hotspot_binaries \ sane-hotspot_import \ diff --git a/jdk/make/sun/Makefile b/jdk/make/sun/Makefile index 56b484fc19f..2b8f017bbcb 100644 --- a/jdk/make/sun/Makefile +++ b/jdk/make/sun/Makefile @@ -63,12 +63,6 @@ ifeq ($(PLATFORM), macosx) LWAWT_SUBDIR = lwawt endif -ifndef OPENJDK -ifneq ($(PLATFORM), macosx) - JDBC_SUBDIR = jdbc -endif -endif - ifdef OPENJDK RENDER_SUBDIR = pisces else @@ -89,7 +83,7 @@ SUBDIRS_desktop = audio $(RENDER_SUBDIR) image \ $(LWAWT_PRE_SUBDIR) $(DISPLAY_LIBS) $(DGA_SUBDIR) $(LWAWT_SUBDIR) \ jawt font jpeg cmm $(DISPLAY_TOOLS) SUBDIRS_management = management -SUBDIRS_misc = $(ORG_SUBDIR) rmi $(JDBC_SUBDIR) tracing +SUBDIRS_misc = $(ORG_SUBDIR) rmi tracing SUBDIRS_tools = native2ascii serialver tools jconsole ifndef OPENJDK diff --git a/jdk/make/sun/jdbc/Makefile b/jdk/make/sun/jdbc/Makefile deleted file mode 100644 index b5751d104c5..00000000000 --- a/jdk/make/sun/jdbc/Makefile +++ /dev/null @@ -1,142 +0,0 @@ -# -# Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute 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. -# - -# -# Makefile for JDBC-ODBC Bridge Driver -# -# Note - the native library for the bridge may be linked with the -# shared library for the ODBC driver manager. Or dummy libraries -# may be used to just create libJdbcOdbc.so with a dependency on -# libodbc.so and libodbcinst.so. -# - -BUILDDIR = ../.. -PACKAGE = sun.jdbc.odbc -LIBRARY = JdbcOdbc -PRODUCT = sun -include $(BUILDDIR)/common/Defs.gmk - -# -# Files -# - -AUTO_FILES_JAVA_DIRS = sun/jdbc/odbc - -FILES_c = \ - JdbcOdbc.c - -FILES_export = \ - sun/jdbc/odbc/JdbcOdbc.java - -# Use fake libraries on Solaris and Linux just so the library we create has -# a dependency on these two library names. (which are not part of the jdk) -ifneq ($(PLATFORM), windows) - # In jdk5 and jdk6, and on Solaris 32bit, we would have required that - # these two libraries exist at: $(ALT_ODBCDIR)/ISLIodbc/2.11/lib - # In jdk7, we just fake them out like we did on Linux in jdk5 and jdk6. - # - # If you wanted to use the real odbc libraries, change the value of - # ODBC_LIBRARY_LOCATION, and delete the variable assignments below. - # - # Tell linker to ignore missing externals when building this shared library. - LDFLAGS_DEFS_OPTION = -Xlinker -z -Xlinker nodefs - # Define a place to create the fake libraries and their names. - ODBC_LIBRARY_LOCATION = $(TEMPDIR) - ODBC_FAKE_LIBRARIES = $(ODBC_LIBRARY_LOCATION)/libodbcinst.so $(ODBC_LIBRARY_LOCATION)/libodbc.so - # Make sure they get created early. - INIT += $(ODBC_FAKE_LIBRARIES) -endif - -# -# Rules -# -include $(BUILDDIR)/common/Library.gmk - -# -# The UNIX define specifies conditional compilation for UNIX -# -ifeq ($(PLATFORM), windows) - LDLIBS += odbc32.lib odbccp32.lib -else - CFLAGS += -DUNIX - LDFLAGS += -L$(ODBC_LIBRARY_LOCATION) -lodbcinst -lodbc -endif - -# -# The native code for the bridge uses conditional compilation to -# support Solaris, Win95 and Mac PPC. This is the path to the shared C files -# (which unfortunately are in the same directory as shared Java files). -# -vpath %.c $(CLOSED_SHARE_SRC)/classes/sun/jdbc/odbc - -# -# Rules to generate fake libraries -# - -ifdef ODBC_FAKE_LIBRARIES -$(TEMPDIR)/dummyodbc.c: - @$(prep-target) - $(ECHO) "void dummyOdbc(void){}" >> $@ -$(TEMPDIR)/dummyodbc.o: $(TEMPDIR)/dummyodbc.c - @$(prep-target) - $(COMPILE.c) $(CC_OBJECT_OUTPUT_FLAG)$@ $(CFLAGS_GPROF) $< -$(ODBC_FAKE_LIBRARIES): $(TEMPDIR)/dummyodbc.o - @$(prep-target) - $(CC) $(SHARED_LIBRARY_FLAG) $(LDFLAGS_COMMON) -o $@ $< $(EXTRA_LIBS) -clean:: - $(RM) -f $(ODBC_FAKE_LIBRARIES) - $(RM) -f $(TEMPDIR)/dummyodbc.c - $(RM) -f $(TEMPDIR)/dummyodbc.o -endif - -# -# Files that need to be copied -# -SERVICEDIR = $(CLASSBINDIR)/META-INF/services - -FILES_copy = \ - $(SERVICEDIR)/java.sql.Driver - - -FILES_mkdirs = \ - $(CLASSBINDIR)/META-INF \ - $(CLASSBINDIR)/META-INF/services - -FILES_copydirs = \ - $(CLASSBINDIR) \ - $(FILES_mkdirs) - -build: copy-files - -copy-files: $(FILES_copy) - -$(SERVICEDIR)/%: $(CLOSED_SHARE_SRC)/classes/sun/jdbc/odbc/META-INF/services/% - $(install-file) - -clean clobber:: - $(RM) $(FILES_copy) - -.PHONY: copy-files - diff --git a/jdk/makefiles/CompileNativeLibraries.gmk b/jdk/makefiles/CompileNativeLibraries.gmk index 4962b40a2f1..eb8db8dc469 100644 --- a/jdk/makefiles/CompileNativeLibraries.gmk +++ b/jdk/makefiles/CompileNativeLibraries.gmk @@ -1540,96 +1540,6 @@ BUILD_LIBRARIES += $(BUILD_LIBJAWT) ########################################################################################## -ifndef OPENJDK -ifneq ($(OPENJDK_TARGET_OS), macosx) - -LIBJDBCODBC_DIR :=$(JDK_OUTPUTDIR)/objs/libjdbcodbc -LIBJDBCODBC_NAME :=$(LIBRARY_PREFIX)JdbcOdbc$(SHARED_LIBRARY_SUFFIX) -LIBJDBCODBC_CFLAGS:= -LIBJDBCODBC_LIBS := -LIBJDBCODBC_LDFLAGS:= - -ifeq ($(OPENJDK_TARGET_OS), windows) - LIBJDBCODBC_LDFLAGS:=$(LDFLAGS_JDKLIB) - LIBJDBCODBC_LIBS += odbc32.lib odbccp32.lib $(WIN_JAVA_LIB) advapi32.lib -else - LIBJDBCODBC_CFLAGS:=-DUNIX - -# -# This mimics "current" build system exactly. Link against fake -lodbcinst -lodbc -# but...those are linked with the -soname, causing the dependency to be dropped on linux (gnu ld) -# but kept with other linker (solaris) -# -# IMO very weird behaviour...very weird -# - LIBJDBCODBC_LDFLAGS:=$(patsubst defs,nodefs,$(LDFLAGS_JDKLIB)) \ - -Xlinker -z -Xlinker nodefs - LIBJDBCODBC_LIBS += -L$(LIBJDBCODBC_DIR) -lodbcinst -lodbc - LIBJDBCODBC_SONAME:=$(call SET_SHARED_LIBRARY_NAME,$(LIBJDBCODBC_NAME)) -endif - -$(eval $(call SetupNativeCompilation,BUILD_LIBJDBCODBC,\ - LIBRARY:=JdbcOdbc,\ - OUTPUT_DIR:=$(INSTALL_LIBRARIES_HERE),\ - SRC:=$(JDK_TOPDIR)/src/closed/share/classes/sun/jdbc/odbc,\ - EXCLUDE_FILES:=dummyodbc.c,\ - LANG:=C,\ - OPTIMIZATION:=LOW, \ - CFLAGS:=$(LIBJDBCODBC_CFLAGS) $(CFLAGS_JDKLIB) \ - $(SHARED_LIBRARY_FLAGS),\ - LDFLAGS:=$(LIBJDBCODBC_LDFLAGS) \ - $(call SET_SHARED_LIBRARY_ORIGIN) $(LIBJDBCODBC_LIBS),\ - LDFLAGS_SUFFIX:=$(LDFLAGS_JDKLIB_SUFFIX) $(LIBJDBCODBC_SONAME),\ - VERSIONINFO_RESOURCE:=$(JDK_TOPDIR)/src/windows/resource/version.rc,\ - RC_FLAGS:=$(RC_FLAGS)\ - /D "JDK_FNAME=JdbcOdbc.dll" \ - /D "JDK_INTERNAL_NAME=JdbcOdbc" \ - /D "JDK_FTYPE=0x2L",\ - OBJECT_DIR:=$(LIBJDBCODBC_DIR),\ - DEBUG_SYMBOLS:=$(WINDOWS_ONLY))) - -$(BUILD_LIBJDBCODBC) : $(BUILD_LIBJAVA) - -BUILD_LIBRARIES += $(BUILD_LIBJDBCODBC) - -ifneq ($(OPENJDK_TARGET_OS), windows) - -$(eval $(call SetupNativeCompilation,BUILD_FAKEODBCINST,\ - LIBRARY:=odbcinst,\ - OUTPUT_DIR:=$(LIBJDBCODBC_DIR),\ - SRC:=$(JDK_OUTPUTDIR)/gensrc_c/libjdbcodbc,\ - INCLUDE_FILES:=dummyodbc1.c,\ - LANG:=C,\ - OPTIMIZATION:=LOW, \ - CFLAGS:=$(CFLAGS_JDKLIB),\ - LDFLAGS:=$(LDFLAGS_JDKLIB) $(call SET_SHARED_LIBRARY_ORIGIN) $(LIBJDBCODBC_LDFLAGS),\ - LDFLAGS_SUFFIX:=$(LDFLAGS_JDKLIB_SUFFIX) $(LIBJDBCODBC_SONAME),\ - OBJECT_DIR:=$(LIBJDBCODBC_DIR))) - -$(eval $(call SetupNativeCompilation,BUILD_FAKEODBC,\ - LIBRARY:=odbc,\ - OUTPUT_DIR:=$(LIBJDBCODBC_DIR),\ - SRC:=$(JDK_OUTPUTDIR)/gensrc_c/libjdbcodbc,\ - INCLUDE_FILES:=dummyodbc2.c,\ - LANG:=C,\ - OPTIMIZATION:=LOW, \ - CFLAGS:=$(LIBJDBCODBC_CFLAGS) $(CFLAGS_JDKLIB),\ - LDFLAGS:=$(LDFLAGS_JDKLIB) $(call SET_SHARED_LIBRARY_ORIGIN) $(LIBJDBCODBC_LDFLAGS),\ - LDFLAGS_SUFFIX:=$(LDFLAGS_JDKLIB_SUFFIX) $(LIBJDBCODBC_SONAME),\ - OBJECT_DIR:=$(LIBJDBCODBC_DIR))) - -$(BUILD_FAKEODBCINST) $(BUILD_FAKEODBC) : \ - $(BUILD_LIBJAVA) - -$(BUILD_LIBJDBCODBC) : $(BUILD_FAKEODBCINST) $(BUILD_FAKEODBC) - -endif - -endif -endif - -########################################################################################## - LIBINSTRUMENT_SRC :=$(JDK_TOPDIR)/src/share/instrument \ $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/java/io \ $(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/instrument diff --git a/jdk/makefiles/CopyIntoClasses.gmk b/jdk/makefiles/CopyIntoClasses.gmk index 5519f29c48d..06490141a4c 100644 --- a/jdk/makefiles/CopyIntoClasses.gmk +++ b/jdk/makefiles/CopyIntoClasses.gmk @@ -188,12 +188,6 @@ ifdef OPENJDK ALL_META-INF_DIRS:=$(filter-out %com/sun/script/javascript/META-INF,$(ALL_META-INF_DIRS)) endif -ifndef OPENJDK -ifneq ($(OPENJDK_TARGET_OS), macosx) - ALL_META-INF_DIRS += $(JDK_TOPDIR)/src/closed/share/classes/sun/jdbc/odbc/META-INF -endif -endif - ifndef OPENJDK ALL_META-INF_DIRS += $(JDK_TOPDIR)/src/closed/share/classes/sun/java2d/cmm/kcms/META-INF endif diff --git a/jdk/makefiles/CreateJars.gmk b/jdk/makefiles/CreateJars.gmk index ebd34b3a236..d060ff2ba23 100644 --- a/jdk/makefiles/CreateJars.gmk +++ b/jdk/makefiles/CreateJars.gmk @@ -249,7 +249,6 @@ endif ifeq ($(OPENJDK_TARGET_OS), macosx) RT_JAR_EXCLUDES += com/sun/nio/sctp \ sun/nio/ch/sctp \ - sun/jdbc \ sun/nio/ch/DevPollArrayWrapper\$$$$Updator.class \ sun/nio/ch/DevPollArrayWrapper.class \ sun/nio/ch/DevPollSelectorImpl.class \ diff --git a/jdk/makefiles/GensrcMisc.gmk b/jdk/makefiles/GensrcMisc.gmk index f3734621716..9f14e666614 100644 --- a/jdk/makefiles/GensrcMisc.gmk +++ b/jdk/makefiles/GensrcMisc.gmk @@ -77,32 +77,6 @@ endif ########################################################################################## -ifndef OPENJDK -ifneq ($(OPENJDK_TARGET_OS), windows) -ifneq ($(OPENJDK_TARGET_OS), macosx) - # These file(s) are needed for building fake .so libs on !windows for jdbcodbc - - $(JDK_OUTPUTDIR)/gensrc_c/libjdbcodbc/dummyodbc1.c : - $(MKDIR) -p $(@D) - $(RM) $@ - $(ECHO) Creating $@ - $(PRINTF) "void dummyOdbc(void){}\n" > $@ - $(ECHO) Created $@ - - $(JDK_OUTPUTDIR)/gensrc_c/libjdbcodbc/dummyodbc2.c : - $(MKDIR) -p $(@D) - $(RM) $@ - $(ECHO) Creating $@ - $(PRINTF) "void dummyOdbc(void){}\n" > $@ - $(ECHO) Created $@ - - GENSRC_MISC += $(JDK_OUTPUTDIR)/gensrc_c/libjdbcodbc/dummyodbc1.c $(JDK_OUTPUTDIR)/gensrc_c/libjdbcodbc/dummyodbc2.c -endif -endif -endif - -########################################################################################## - GENSRC_MISC += $(JDK_OUTPUTDIR)/gensrc_misc/sun/nio/ch/SocketOptionRegistry.java GENSRC_SOR_SRC := $(JDK_TOPDIR)/src/share/native/sun/nio/ch From 620f0e5006fb88967199b05cd54db6c22f41fc51 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Mon, 29 Oct 2012 14:14:06 +0800 Subject: [PATCH 19/59] 7184246: Simplify Config.get() of krb5 Reviewed-by: xuelei --- .../classes/sun/security/krb5/Checksum.java | 12 +- .../classes/sun/security/krb5/Config.java | 727 +++++++----------- .../classes/sun/security/krb5/KdcComm.java | 8 +- .../sun/security/krb5/PrincipalName.java | 6 +- .../classes/sun/security/krb5/Realm.java | 4 +- .../security/krb5/SCDynamicStoreConfig.java | 68 +- .../security/krb5/internal/KDCOptions.java | 16 +- .../security/krb5/internal/KerberosTime.java | 6 +- .../krb5/internal/crypto/CksumType.java | 8 +- .../security/krb5/internal/crypto/EType.java | 12 +- .../security/krb5/internal/ktab/KeyTab.java | 4 +- jdk/test/sun/security/krb5/ConfPlusProp.java | 9 +- jdk/test/sun/security/krb5/DnsFallback.java | 37 +- jdk/test/sun/security/krb5/ParseConfig.java | 3 +- .../sun/security/krb5/auto/BasicKrb5Test.java | 3 +- .../sun/security/krb5/auto/MaxRetries.java | 2 +- .../sun/security/krb5/config/Duplicates.java | 72 ++ .../krb5/config/SCDynamicConfigTest.java | 102 +++ jdk/test/sun/security/krb5/config/k1.conf | 40 + 19 files changed, 602 insertions(+), 537 deletions(-) create mode 100644 jdk/test/sun/security/krb5/config/Duplicates.java create mode 100644 jdk/test/sun/security/krb5/config/SCDynamicConfigTest.java create mode 100644 jdk/test/sun/security/krb5/config/k1.conf diff --git a/jdk/src/share/classes/sun/security/krb5/Checksum.java b/jdk/src/share/classes/sun/security/krb5/Checksum.java index 4cc58204963..54155a39b88 100644 --- a/jdk/src/share/classes/sun/security/krb5/Checksum.java +++ b/jdk/src/share/classes/sun/security/krb5/Checksum.java @@ -74,14 +74,18 @@ public class Checksum { private static boolean DEBUG = Krb5.DEBUG; static { + initStatic(); + } + + public static void initStatic() { String temp = null; Config cfg = null; try { cfg = Config.getInstance(); - temp = cfg.getDefault("default_checksum", "libdefaults"); + temp = cfg.get("libdefaults", "default_checksum"); if (temp != null) { - CKSUMTYPE_DEFAULT = cfg.getType(temp); + CKSUMTYPE_DEFAULT = Config.getType(temp); } else { /* * If the default checksum is not @@ -103,10 +107,10 @@ public class Checksum { try { - temp = cfg.getDefault("safe_checksum_type", "libdefaults"); + temp = cfg.get("libdefaults", "safe_checksum_type"); if (temp != null) { - SAFECKSUMTYPE_DEFAULT = cfg.getType(temp); + SAFECKSUMTYPE_DEFAULT = Config.getType(temp); } else { SAFECKSUMTYPE_DEFAULT = CKSUMTYPE_RSA_MD5_DES; } diff --git a/jdk/src/share/classes/sun/security/krb5/Config.java b/jdk/src/share/classes/sun/security/krb5/Config.java index 596fa80a0f2..486f59f2ef2 100644 --- a/jdk/src/share/classes/sun/security/krb5/Config.java +++ b/jdk/src/share/classes/sun/security/krb5/Config.java @@ -38,11 +38,14 @@ import java.util.ArrayList; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; -import java.util.Enumeration; import java.util.StringTokenizer; import java.net.InetAddress; import java.net.UnknownHostException; +import java.security.AccessController; +import java.security.PrivilegedExceptionAction; +import java.util.Arrays; import java.util.List; +import java.util.Locale; import sun.net.dns.ResolverConfiguration; import sun.security.krb5.internal.crypto.EType; import sun.security.krb5.internal.Krb5; @@ -62,7 +65,7 @@ public class Config { /* * Hashtable used to store configuration infomation. */ - private Hashtable stanzaTable; + private Hashtable stanzaTable = new Hashtable<>(); private static boolean DEBUG = sun.security.krb5.internal.Krb5.DEBUG; @@ -100,7 +103,9 @@ public class Config { /** * Refresh and reload the Configuration. This could involve, * for example reading the Configuration file again or getting - * the java.security.krb5.* system properties again. + * the java.security.krb5.* system properties again. This method + * also tries its best to update static fields in other classes + * that depend on the configuration. * * @exception KrbException if error occurs when constructing a Config * instance. Possible causes would be either of java.security.krb5.realm or @@ -110,6 +115,8 @@ public class Config { public static synchronized void refresh() throws KrbException { singleton = new Config(); KdcComm.initStatic(); + EType.initStatic(); + Checksum.initStatic(); } @@ -163,7 +170,7 @@ public class Config { // Always read the Kerberos configuration file try { - Vector configFile; + List configFile; String fileName = getJavaFileName(); if (fileName != null) { configFile = loadConfigFile(fileName); @@ -194,216 +201,111 @@ public class Config { } } } catch (IOException ioe) { - // No krb5.conf, no problem. We'll use DNS or system property etc. + // I/O error, mostly like krb5.conf missing. + // No problem. We'll use DNS or system property etc. } } /** - * Gets the default int value for the specified name. - * @param name the name. - * @return the default Integer, null is returned if no such name and - * value are found in configuration file, or error occurs when parsing - * string to integer. + * Gets the last-defined string value for the specified keys. + * @param keys the keys, as an array from section name, sub-section names + * (if any), to value name. + * @return the value. When there are multiple values for the same key, + * returns the last one. {@code null} is returned if not all the keys are + * defined. For example, {@code get("libdefaults", "forwardable")} will + * return null if "forwardable" is not defined in [libdefaults], and + * {@code get("realms", "R", "kdc")} will return null if "R" is not + * defined in [realms] or "kdc" is not defined for "R". + * @throws IllegalArgumentException if any of the keys is illegal, either + * because a key not the last one is not a (sub)section name or the last + * key is still a section name. For example, {@code get("libdefaults")} + * throws this exception because [libdefaults] is a section name instead of + * a value name, and {@code get("libdefaults", "forwardable", "tail")} + * also throws this exception because "forwardable" is already a value name + * and has no sub-key at all (given "forwardable" is defined, otherwise, + * this method has no knowledge if it's a value name or a section name), */ - public int getDefaultIntValue(String name) { - String result = null; - int value = Integer.MIN_VALUE; - result = getDefault(name); - if (result != null) { - try { - value = parseIntValue(result); - } catch (NumberFormatException e) { - if (DEBUG) { - System.out.println("Exception in getting value of " + - name + " " + - e.getMessage()); - System.out.println("Setting " + name + - " to minimum value"); - } - value = Integer.MIN_VALUE; - } - } - return value; - } - - /** - * Gets the default int value for the specified name in the specified - * section.
                          This method is quicker by using section name as the - * search key. - * @param name the name. - * @param sectio the name string of the section. - * @return the default Integer, null is returned if no such name and - * value are found in configuration file, or error occurs when parsing - * string to integer. - */ - public int getDefaultIntValue(String name, String section) { - String result = null; - int value = Integer.MIN_VALUE; - result = getDefault(name, section); - if (result != null) { - try { - value = parseIntValue(result); - } catch (NumberFormatException e) { - if (DEBUG) { - System.out.println("Exception in getting value of " + - name +" in section " + - section + " " + e.getMessage()); - System.out.println("Setting " + name + - " to minimum value"); - } - value = Integer.MIN_VALUE; - } - } - return value; - } - - /** - * Gets the default string value for the specified name. - * @param name the name. - * @return the default value, null is returned if it cannot be found. - */ - public String getDefault(String name) { - if (stanzaTable == null) { - return null; - } else { - return getDefault(name, stanzaTable); - } - } - - /** - * This method does the real job to recursively search through the - * stanzaTable. - * @param k the key string. - * @param t stanzaTable or sub hashtable within it. - * @return the value found in config file, returns null if no value - * matched with the key is found. - */ - private String getDefault(String k, Hashtable t) { - String result = null; - String key; - if (stanzaTable != null) { - for (Enumeration e = t.keys(); e.hasMoreElements(); ) { - key = e.nextElement(); - Object ob = t.get(key); - if (ob instanceof Hashtable) { - @SuppressWarnings("unchecked") // Checked with an instanceof check - Hashtable table = - (Hashtable)ob; - result = getDefault(k, table); - if (result != null) { - return result; - } - } else if (key.equalsIgnoreCase(k)) { - if (ob instanceof String) { - return (String)(t.get(key)); - } else if (ob instanceof Vector) { - result = ""; - int length = ((Vector)ob).size(); - for (int i = 0; i < length; i++) { - if (i == length -1) { - result += - (String)(((Vector)ob).elementAt(i)); - } else { - result += - (String)(((Vector)ob).elementAt(i)) + " "; - } - } - return result; - } - } - } - } - return result; - } - - /** - * Gets the default string value for the specified name in the - * specified section. - *
                          This method is quicker by using the section name as the search key. - * @param name the name. - * @param section the name of the section. - * @return the default value, null is returned if it cannot be found. - */ - // stanzaTable leads to a lot of unchecked casts since its value type is - // STANZATABLE = String | Hashtable @SuppressWarnings("unchecked") - public String getDefault(String name, String section) { - String stanzaName; - String result = null; - Hashtable subTable; + public String get(String... keys) { + Vector v = get0(keys); + if (v == null) return null; + return v.lastElement(); + } - if (stanzaTable != null) { - for (Enumeration e = stanzaTable.keys(); - e.hasMoreElements(); ) { - stanzaName = e.nextElement(); - subTable = (Hashtable) - stanzaTable.get(stanzaName); - if (stanzaName.equalsIgnoreCase(section)) { - if (subTable.containsKey(name)) { - return (String)(subTable.get(name)); - } - } else if (subTable.containsKey(section)) { - Object ob = subTable.get(section); - if (ob instanceof Hashtable) { - Hashtable temp = - (Hashtable)ob; - if (temp.containsKey(name)) { - Object object = temp.get(name); - if (object instanceof Vector) { - result = ""; - int length = ((Vector)object).size(); - for (int i = 0; i < length; i++) { - if (i == length - 1) { - result += - (String)(((Vector)object).elementAt(i)); - } else { - result += - (String)(((Vector)object).elementAt(i)) - + " "; - } - } - } else { - result = (String)object; - } - } - } - } + /** + * Gets all values for the specified keys. + * @see #get(java.lang.String[]) + */ + public String getAll(String... keys) { + Vector v = get0(keys); + if (v == null) return null; + StringBuilder sb = new StringBuilder(); + boolean first = true; + for (String s: v) { + if (first) { + sb.append(s); + first = false; + } else { + sb.append(' ').append(s); } } - return result; + return sb.toString(); } - /** - * Gets the default boolean value for the specified name. - * @param name the name. - * @return the default boolean value, false is returned if it cannot be - * found. - */ - public boolean getDefaultBooleanValue(String name) { - String val = null; - if (stanzaTable == null) { - val = null; - } else { - val = getDefault(name, stanzaTable); - } - if (val != null && val.equalsIgnoreCase("true")) { - return true; - } else { - return false; + // Internal method. Returns the vector of strings for keys. + // The only method (except for toString) that reads stanzaTable directly. + @SuppressWarnings("unchecked") + private Vector get0(String... keys) { + Object current = stanzaTable; + try { + for (String key: keys) { + current = ((Hashtable)current).get(key); + if (current == null) return null; + } + return (Vector)current; + } catch (ClassCastException cce) { + throw new IllegalArgumentException(cce); } } /** - * Gets the default boolean value for the specified name in the - * specified section. - *
                          This method is quicker by using the section name as the search key. - * @param name the name. - * @param section the name of the section. - * @return the default boolean value, false is returned if it cannot be - * found. + * Gets the int value for the specified keys. + * @param keys the keys + * @return the int value, Integer.MIN_VALUE is returned if it cannot be + * found or the value is not a legal integer. + * @throw IllegalArgumentException if any of the keys is illegal + * @see #get(java.lang.String[]) */ - public boolean getDefaultBooleanValue(String name, String section) { - String val = getDefault(name, section); + public int getIntValue(String... keys) { + String result = get(keys); + int value = Integer.MIN_VALUE; + if (result != null) { + try { + value = parseIntValue(result); + } catch (NumberFormatException e) { + if (DEBUG) { + System.out.println("Exception in getting value of " + + Arrays.toString(keys) + " " + + e.getMessage()); + System.out.println("Setting " + Arrays.toString(keys) + + " to minimum value"); + } + value = Integer.MIN_VALUE; + } + } + return value; + } + + /** + * Gets the boolean value for the specified keys. + * @param keys the keys + * @return the boolean value, false is returned if it cannot be + * found or the value is not "true" (case insensitive). + * @throw IllegalArgumentException if any of the keys is illegal + * @see #get(java.lang.String[]) + */ + public boolean getBooleanValue(String... keys) { + String val = get(keys); if (val != null && val.equalsIgnoreCase("true")) { return true; } else { @@ -528,29 +430,14 @@ public class Config { } /** - * Finds the matching value in the hashtable. - */ - private String find(String key1, String key2) { - String result; - if ((stanzaTable != null) && - ((result = (String) - (((Hashtable)(stanzaTable.get(key1))).get(key2))) != null)) { - return result; - } else { - return ""; - } - } - - /** - * Reads name/value pairs to the memory from the configuration - * file. The default location of the configuration file is in java home - * directory. + * Reads lines to the memory from the configuration file. * * Configuration file contains information about the default realm, * ticket parameters, location of the KDC and the admin server for * known realms, etc. The file is divided into sections. Each section * contains one or more name/value pairs with one pair per line. A * typical file would be: + *
                                * [libdefaults]
                                *          default_realm = EXAMPLE.COM
                                *          default_tgs_enctypes = des-cbc-md5
                          @@ -568,128 +455,178 @@ public class Config {
                                * [domain_realm]
                                *          blue.sample.com = TEST.SAMPLE.COM
                                *          .backup.com     = EXAMPLE.COM
                          -     *
                          -     * @params fileName the conf file, cannot be null
                          -     * @return the content, null if fileName is empty
                          -     * @throws IOException if there is an I/O or format error
                          +     * 
                          + * @return an ordered list of strings representing the config file after + * some initial processing, including:
                            + *
                          1. Comment lines and empty lines are removed + *
                          2. "{" not at the end of a line is appended to the previous line + *
                          3. The content of a section is also placed between "{" and "}". + *
                          4. Lines are trimmed
                          + * @throws IOException if there is an I/O error + * @throws KrbException if there is a file format error */ - private Vector loadConfigFile(final String fileName) throws IOException { + private List loadConfigFile(final String fileName) + throws IOException, KrbException { try { - if (!fileName.equals("")) { - BufferedReader br = new BufferedReader(new InputStreamReader( - java.security.AccessController.doPrivileged( - new java.security.PrivilegedExceptionAction () { - public FileInputStream run() throws IOException { - return new FileInputStream(fileName); - } - }))); - String Line; - Vector v = new Vector<>(); - String previous = null; - while ((Line = br.readLine()) != null) { - // ignore comments and blank line in the configuration file. - // Comments start with #. - if (!(Line.startsWith("#") || Line.trim().isEmpty())) { - String current = Line.trim(); - // In practice, a subsection might look like: - // EXAMPLE.COM = - // { - // kdc = kerberos.example.com - // ... - // } - // Before parsed into stanza table, it needs to be - // converted into formal style: - // EXAMPLE.COM = { - // kdc = kerberos.example.com - // ... - // } - // - // So, if a line is "{", adhere to the previous line. - if (current.equals("{")) { - if (previous == null) { - throw new IOException( - "Config file should not start with \"{\""); - } - previous += " " + current; - } else { - if (previous != null) { - v.addElement(previous); - } - previous = current; + List v = new ArrayList<>(); + try (BufferedReader br = new BufferedReader(new InputStreamReader( + AccessController.doPrivileged( + new PrivilegedExceptionAction () { + public FileInputStream run() throws IOException { + return new FileInputStream(fileName); } + })))) { + String line; + String previous = null; + while ((line = br.readLine()) != null) { + line = line.trim(); + if (line.startsWith("#") || line.isEmpty()) { + // ignore comments and blank line + // Comments start with #. + continue; + } + // In practice, a subsection might look like: + // [realms] + // EXAMPLE.COM = + // { + // kdc = kerberos.example.com + // ... + // } + // Before parsed into stanza table, it needs to be + // converted into a canonicalized style (no indent): + // realms = { + // EXAMPLE.COM = { + // kdc = kerberos.example.com + // ... + // } + // } + // + if (line.startsWith("[")) { + if (!line.endsWith("]")) { + throw new KrbException("Illegal config content:" + + line); + } + if (previous != null) { + v.add(previous); + v.add("}"); + } + String title = line.substring( + 1, line.length()-1).trim(); + if (title.isEmpty()) { + throw new KrbException("Illegal config content:" + + line); + } + previous = title + " = {"; + } else if (line.startsWith("{")) { + if (previous == null) { + throw new KrbException( + "Config file should not start with \"{\""); + } + previous += " {"; + if (line.length() > 1) { + // { and content on the same line + v.add(previous); + previous = line.substring(1).trim(); + } + } else { + if (previous == null) { + throw new KrbException( + "Config file must starts with a section"); + } + v.add(previous); + previous = line; } } if (previous != null) { - v.addElement(previous); + v.add(previous); + v.add("}"); } - - br.close(); - return v; } - return null; + return v; } catch (java.security.PrivilegedActionException pe) { throw (IOException)pe.getException(); } } - /** * Parses stanza names and values from configuration file to * stanzaTable (Hashtable). Hashtable key would be stanza names, * (libdefaults, realms, domain_realms, etc), and the hashtable value * would be another hashtable which contains the key-value pairs under - * a stanza name. + * a stanza name. The value of this sub-hashtable can be another hashtable + * containing another sub-sub-section or a vector of strings for + * final values (even if there is only one value defined). + *

                          + * For duplicates section names, the latter overwrites the former. For + * duplicate value names, the values are in a vector in its appearing order. + *

                      + * Please note that this behavior is Java traditional. and it is + * not the same as the MIT krb5 behavior, where:
                        + *
                      1. Duplicated root sections will be merged + *
                      2. For duplicated sub-sections, the former overwrites the latter + *
                      3. Duplicate keys for values are always saved in a vector + *
                      + * @param v the strings in the file, never null, might be empty + * @throws KrbException if there is a file format error */ - private Hashtable parseStanzaTable(Vector v) throws KrbException { - if (v == null) { - throw new KrbException("I/O error while reading" + - " configuration file."); - } - Hashtable table = new Hashtable<>(); - for (int i = 0; i < v.size(); i++) { - String line = v.elementAt(i).trim(); - if (line.equalsIgnoreCase("[realms]")) { - for (int count = i + 1; count < v.size() + 1; count++) { - // find the next stanza name - if ((count == v.size()) || - (v.elementAt(count).startsWith("["))) { - Hashtable>> temp = - new Hashtable<>(); - temp = parseRealmField(v, i + 1, count); - table.put("realms", temp); - i = count - 1; - break; - } + @SuppressWarnings("unchecked") + private Hashtable parseStanzaTable(List v) + throws KrbException { + Hashtable current = stanzaTable; + for (String line: v) { + // There are 3 kinds of lines + // 1. a = b + // 2. a = { + // 3. } + if (line.equals("}")) { + // Go back to parent, see below + current = (Hashtable)current.remove(" PARENT "); + if (current == null) { + throw new KrbException("Unmatched close brace"); } - } else if (line.equalsIgnoreCase("[capaths]")) { - for (int count = i + 1; count < v.size() + 1; count++) { - // find the next stanza name - if ((count == v.size()) || - (v.elementAt(count).startsWith("["))) { - Hashtable>> temp = - new Hashtable<>(); - temp = parseRealmField(v, i + 1, count); - table.put("capaths", temp); - i = count - 1; - break; - } + } else { + int pos = line.indexOf('='); + if (pos < 0) { + throw new KrbException("Illegal config content:" + line); } - } else if (line.startsWith("[") && line.endsWith("]")) { - String key = line.substring(1, line.length() - 1); - for (int count = i + 1; count < v.size() + 1; count++) { - // find the next stanza name - if ((count == v.size()) || - (v.elementAt(count).startsWith("["))) { - Hashtable temp = - parseField(v, i + 1, count); - table.put(key, temp); - i = count - 1; - break; + String key = line.substring(0, pos).trim(); + String value = trimmed(line.substring(pos+1)); + if (value.equals("{")) { + Hashtable subTable; + if (current == stanzaTable) { + key = key.toLowerCase(Locale.US); } + subTable = new Hashtable<>(); + current.put(key, subTable); + // A special entry for its parent. Put whitespaces around, + // so will never be confused with a normal key + subTable.put(" PARENT ", current); + current = subTable; + } else { + Vector values; + if (current.containsKey(key)) { + Object obj = current.get(key); + // If a key first shows as a section and then a value, + // this is illegal. However, we haven't really forbid + // first value then section, which the final result + // is a section. + if (!(obj instanceof Vector)) { + throw new KrbException("Key " + key + + "used for both value and section"); + } + values = (Vector)current.get(key); + } else { + values = new Vector(); + current.put(key, values); + } + values.add(value); } } } - return table; + if (current != stanzaTable) { + throw new KrbException("Not closed"); + } + return current; } /** @@ -807,158 +744,20 @@ public class Config { private static String trimmed(String s) { s = s.trim(); + if (s.isEmpty()) return s; if (s.charAt(0) == '"' && s.charAt(s.length()-1) == '"' || s.charAt(0) == '\'' && s.charAt(s.length()-1) == '\'') { s = s.substring(1, s.length()-1).trim(); } return s; } - /** - * Parses key-value pairs under a stanza name. - */ - private Hashtable parseField(Vector v, int start, int end) { - Hashtable table = new Hashtable<>(); - String line; - for (int i = start; i < end; i++) { - line = v.elementAt(i); - for (int j = 0; j < line.length(); j++) { - if (line.charAt(j) == '=') { - String key = (line.substring(0, j)).trim(); - String value = trimmed(line.substring(j + 1)); - table.put(key, value); - break; - } - } - } - return table; - } - - /** - * Parses key-value pairs under [realms]. The key would be the realm - * name, the value would be another hashtable which contains - * information for the realm given within a pair of braces. - */ - private Hashtable>> parseRealmField(Vector v, int start, int end) { - Hashtable>> table = new Hashtable<>(); - String line; - for (int i = start; i < end; i++) { - line = v.elementAt(i).trim(); - if (line.endsWith("{")) { - String key = ""; - for (int j = 0; j < line.length(); j++) { - if (line.charAt(j) == '=') { - key = line.substring(0, j).trim(); - // get the key - break; - } - } - for (int k = i + 1; k < end; k++) { - boolean found = false; - line = v.elementAt(k).trim(); - for (int l = 0; l < line.length(); l++) { - if (line.charAt(l) == '}') { - found = true; - break; - } - } - if (found == true) { - Hashtable> temp = parseRealmFieldEx(v, i + 1, k); - table.put(key, temp); - i = k; - found = false; - break; - } - - } - } - } - return table; - } - - /** - * Parses key-value pairs within each braces under [realms]. - */ - private Hashtable> parseRealmFieldEx(Vector v, int start, int end) { - Hashtable> table = new Hashtable<>(); - Vector keyVector = new Vector<>(); - Vector nameVector = new Vector<>(); - String line = ""; - String key; - for (int i = start; i < end; i++) { - line = v.elementAt(i); - for (int j = 0; j < line.length(); j++) { - if (line.charAt(j) == '=') { - int index; - key = line.substring(0, j).trim(); - if (! exists(key, keyVector)) { - keyVector.addElement(key); - nameVector = new Vector (); - } else { - nameVector = table.get(key); - } - nameVector.addElement(trimmed(line.substring(j + 1))); - table.put(key, nameVector); - break; - } - } - } - return table; - } - - /** - * Compares the key with the known keys to see if it exists. - */ - private boolean exists(String key, Vector v) { - boolean exists = false; - for (int i = 0; i < v.size(); i++) { - if (v.elementAt(i).equals(key)) { - exists = true; - } - } - return exists; - } /** * For testing purpose. This method lists all information being parsed from * the configuration file to the hashtable. */ public void listTable() { - listTable(stanzaTable); - } - - // stanzaTable leads to a lot of unchecked casts since its value type is - // STANZATABLE = String | Hashtable - @SuppressWarnings("unchecked") - private void listTable(Hashtable table) { - Vector v = new Vector(); - String key; - if (stanzaTable != null) { - for (Enumeration e = table.keys(); e.hasMoreElements(); ) { - key = e.nextElement(); - Object object = table.get(key); - if (table == stanzaTable) { - System.out.println("[" + key + "]"); - } - if (object instanceof Hashtable) { - if (table != stanzaTable) - System.out.println("\t" + key + " = {"); - listTable((Hashtable)object); - if (table != stanzaTable) - System.out.println("\t}"); - - } else if (object instanceof String) { - System.out.println("\t" + key + " = " + - (String)table.get(key)); - } else if (object instanceof Vector) { - v = (Vector)object; - for (int i = 0; i < v.size(); i++) { - System.out.println("\t" + key + " = " + v.elementAt(i)); - } - } - } - } else { - System.out.println("Configuration file not found."); - } + System.out.println(this); } /** @@ -967,7 +766,7 @@ public class Config { */ public int[] defaultEtype(String enctypes) { String default_enctypes; - default_enctypes = getDefault(enctypes, "libdefaults"); + default_enctypes = get("libdefaults", enctypes); String delim = " "; StringTokenizer st; int[] etype; @@ -991,7 +790,7 @@ public class Config { ArrayList ls = new ArrayList<>(len); int type; for (int i = 0; i < len; i++) { - type = getType(st.nextToken()); + type = Config.getType(st.nextToken()); if ((type != -1) && (EType.isSupported(type))) { ls.add(type); @@ -1032,7 +831,7 @@ public class Config { * checksum type to int value that can be later used by EType and * Checksum classes. */ - public int getType(String input) { + public static int getType(String input) { int result = -1; if (input == null) { return result; @@ -1114,11 +913,11 @@ public class Config { public boolean useAddresses() { boolean useAddr = false; // use addresses if "no_addresses" is set to false - String value = getDefault("no_addresses", "libdefaults"); + String value = get("libdefaults", "no_addresses"); useAddr = (value != null && value.equalsIgnoreCase("false")); if (useAddr == false) { // use addresses if "noaddresses" is set to false - value = getDefault("noaddresses", "libdefaults"); + value = get("libdefaults", "noaddresses"); useAddr = (value != null && value.equalsIgnoreCase("false")); } return useAddr; @@ -1127,10 +926,10 @@ public class Config { /** * Check if need to use DNS to locate Kerberos services */ - public boolean useDNS(String name) { - String value = getDefault(name, "libdefaults"); + private boolean useDNS(String name) { + String value = get("libdefaults", name); if (value == null) { - value = getDefault("dns_fallback", "libdefaults"); + value = get("libdefaults", "dns_fallback"); if ("false".equalsIgnoreCase(value)) { return false; } else { @@ -1144,14 +943,14 @@ public class Config { /** * Check if need to use DNS to locate the KDC */ - public boolean useDNS_KDC() { + private boolean useDNS_KDC() { return useDNS("dns_lookup_kdc"); } /* * Check if need to use DNS to locate the Realm */ - public boolean useDNS_Realm() { + private boolean useDNS_Realm() { return useDNS("dns_lookup_realm"); } @@ -1165,7 +964,7 @@ public class Config { return defaultRealm; } Exception cause = null; - String realm = getDefault("default_realm", "libdefaults"); + String realm = get("libdefaults", "default_realm"); if ((realm == null) && useDNS_Realm()) { // use DNS to locate Kerberos realm try { @@ -1212,7 +1011,7 @@ public class Config { return defaultKDC; } Exception cause = null; - String kdcs = getDefault("kdc", realm); + String kdcs = getAll("realms", realm, "kdc"); if ((kdcs == null) && useDNS_KDC()) { // use DNS to locate KDC try { diff --git a/jdk/src/share/classes/sun/security/krb5/KdcComm.java b/jdk/src/share/classes/sun/security/krb5/KdcComm.java index 756beb98912..5401dfec0ac 100644 --- a/jdk/src/share/classes/sun/security/krb5/KdcComm.java +++ b/jdk/src/share/classes/sun/security/krb5/KdcComm.java @@ -142,11 +142,11 @@ public final class KdcComm { try { Config cfg = Config.getInstance(); - String temp = cfg.getDefault("kdc_timeout", "libdefaults"); + String temp = cfg.get("libdefaults", "kdc_timeout"); timeout = parsePositiveIntString(temp); - temp = cfg.getDefault("max_retries", "libdefaults"); + temp = cfg.get("libdefaults", "max_retries"); max_retries = parsePositiveIntString(temp); - temp = cfg.getDefault("udp_preference_limit", "libdefaults"); + temp = cfg.get("libdefaults", "udp_preference_limit"); udf_pref_limit = parsePositiveIntString(temp); } catch (Exception exc) { // ignore any exceptions; use default values @@ -421,7 +421,7 @@ public final class KdcComm { int temp = -1; try { String value = - Config.getInstance().getDefault(key, realm); + Config.getInstance().get("realms", realm, key); temp = parsePositiveIntString(value); } catch (Exception exc) { // Ignored, defValue will be picked up diff --git a/jdk/src/share/classes/sun/security/krb5/PrincipalName.java b/jdk/src/share/classes/sun/security/krb5/PrincipalName.java index 2a1e4753729..0386d61bae8 100644 --- a/jdk/src/share/classes/sun/security/krb5/PrincipalName.java +++ b/jdk/src/share/classes/sun/security/krb5/PrincipalName.java @@ -655,19 +655,19 @@ public class PrincipalName implements Cloneable { try { String subname = null; Config c = Config.getInstance(); - if ((result = c.getDefault(name, "domain_realm")) != null) + if ((result = c.get("domain_realm", name)) != null) return result; else { for (int i = 1; i < name.length(); i++) { if ((name.charAt(i) == '.') && (i != name.length() - 1)) { //mapping could be .ibm.com = AUSTIN.IBM.COM subname = name.substring(i); - result = c.getDefault(subname, "domain_realm"); + result = c.get("domain_realm", subname); if (result != null) { break; } else { subname = name.substring(i + 1); //or mapping could be ibm.com = AUSTIN.IBM.COM - result = c.getDefault(subname, "domain_realm"); + result = c.get("domain_realm", subname); if (result != null) { break; } diff --git a/jdk/src/share/classes/sun/security/krb5/Realm.java b/jdk/src/share/classes/sun/security/krb5/Realm.java index bfb43e757a4..151da710109 100644 --- a/jdk/src/share/classes/sun/security/krb5/Realm.java +++ b/jdk/src/share/classes/sun/security/krb5/Realm.java @@ -350,7 +350,7 @@ public class Realm implements Cloneable { return null; } - String intermediaries = cfg.getDefault(sRealm, cRealm); + String intermediaries = cfg.getAll("capaths", cRealm, sRealm); if (intermediaries == null) { if (DEBUG) { @@ -459,7 +459,7 @@ public class Realm implements Cloneable { tempTarget); } - intermediaries = cfg.getDefault(tempTarget, cRealm); + intermediaries = cfg.getAll("capaths", cRealm, tempTarget); } while (true); diff --git a/jdk/src/share/classes/sun/security/krb5/SCDynamicStoreConfig.java b/jdk/src/share/classes/sun/security/krb5/SCDynamicStoreConfig.java index c6e5e70a94b..391be5eac60 100644 --- a/jdk/src/share/classes/sun/security/krb5/SCDynamicStoreConfig.java +++ b/jdk/src/share/classes/sun/security/krb5/SCDynamicStoreConfig.java @@ -34,19 +34,25 @@ import java.util.Vector; public class SCDynamicStoreConfig { private static native void installNotificationCallback(); private static native Hashtable getKerberosConfig(); + private static boolean DEBUG = sun.security.krb5.internal.Krb5.DEBUG; static { - java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public Void run() { - System.loadLibrary("osx"); - return null; + boolean isMac = java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Boolean run() { + String osname = System.getProperty("os.name"); + if (osname.contains("OS X")) { + System.loadLibrary("osx"); + return true; + } + return false; } }); - installNotificationCallback(); + if (isMac) installNotificationCallback(); } - private static Vector unwrapHost(Collection> c) { + private static Vector unwrapHost( + Collection> c) { Vector vector = new Vector(); for (Hashtable m : c) { vector.add(m.get("host")); @@ -60,20 +66,25 @@ public class SCDynamicStoreConfig { * are wrapped inside Hashtables */ @SuppressWarnings("unchecked") - private static Hashtable convertRealmConfigs(Hashtable configs) { + private static Hashtable + convertRealmConfigs(Hashtable configs) { Hashtable realmsTable = new Hashtable(); for (String realm : configs.keySet()) { // get the kdc - Hashtable> map = (Hashtable>) configs.get(realm); - Collection> kdc = (Collection>) map.get("kdc"); + Hashtable> map = + (Hashtable>) configs.get(realm); + Hashtable> realmMap = + new Hashtable>(); // put the kdc into the realmMap - Hashtable> realmMap = new Hashtable>(); + Collection> kdc = + (Collection>) map.get("kdc"); if (kdc != null) realmMap.put("kdc", unwrapHost(kdc)); // put the admin server into the realmMap - Collection> kadmin = (Collection>) map.get("kadmin"); + Collection> kadmin = + (Collection>) map.get("kadmin"); if (kadmin != null) realmMap.put("admin_server", unwrapHost(kadmin)); // add the full entry to the realmTable @@ -90,23 +101,44 @@ public class SCDynamicStoreConfig { * @return * @throws IOException */ - @SuppressWarnings("unchecked") public static Hashtable getConfig() throws IOException { Hashtable stanzaTable = getKerberosConfig(); if (stanzaTable == null) { - throw new IOException("Could not load configuration from SCDynamicStore"); + throw new IOException( + "Could not load configuration from SCDynamicStore"); } - //System.out.println("Raw map from JNI: " + stanzaTable); + if (DEBUG) System.out.println("Raw map from JNI: " + stanzaTable); + return convertNativeConfig(stanzaTable); + } + @SuppressWarnings("unchecked") + private static Hashtable convertNativeConfig( + Hashtable stanzaTable) { // convert SCDynamicStore realm structure to Java realm structure - Hashtable realms = (Hashtable) stanzaTable.get("realms"); + Hashtable realms = + (Hashtable) stanzaTable.get("realms"); if (realms != null) { stanzaTable.remove("realms"); Hashtable realmsTable = convertRealmConfigs(realms); stanzaTable.put("realms", realmsTable); } - - // System.out.println("stanzaTable : " + stanzaTable); + WrapAllStringInVector(stanzaTable); + if (DEBUG) System.out.println("stanzaTable : " + stanzaTable); return stanzaTable; } + + @SuppressWarnings("unchecked") + private static void WrapAllStringInVector( + Hashtable stanzaTable) { + for (String s: stanzaTable.keySet()) { + Object v = stanzaTable.get(s); + if (v instanceof Hashtable) { + WrapAllStringInVector((Hashtable)v); + } else if (v instanceof String) { + Vector vec = new Vector<>(); + vec.add((String)v); + stanzaTable.put(s, vec); + } + } + } } diff --git a/jdk/src/share/classes/sun/security/krb5/internal/KDCOptions.java b/jdk/src/share/classes/sun/security/krb5/internal/KDCOptions.java index df1c549b7ba..b0d609d9a8e 100644 --- a/jdk/src/share/classes/sun/security/krb5/internal/KDCOptions.java +++ b/jdk/src/share/classes/sun/security/krb5/internal/KDCOptions.java @@ -244,25 +244,23 @@ public class KDCOptions extends KerberosFlags { Config config = Config.getInstance(); - /* - * First see if the IBM hex format is being used. - * If not, try the Sun's string (boolean) format. - */ + // If key not present, returns Integer.MIN_VALUE, which is + // almost all zero. - int options =config.getDefaultIntValue("kdc_default_options", - "libdefaults"); + int options = config.getIntValue("libdefaults", + "kdc_default_options"); if ((options & RENEWABLE_OK) == RENEWABLE_OK) { set(RENEWABLE_OK, true); } else { - if (config.getDefaultBooleanValue("renewable", "libdefaults")) { + if (config.getBooleanValue("libdefaults", "renewable")) { set(RENEWABLE_OK, true); } } if ((options & PROXIABLE) == PROXIABLE) { set(PROXIABLE, true); } else { - if (config.getDefaultBooleanValue("proxiable", "libdefaults")) { + if (config.getBooleanValue("libdefaults", "proxiable")) { set(PROXIABLE, true); } } @@ -270,7 +268,7 @@ public class KDCOptions extends KerberosFlags { if ((options & FORWARDABLE) == FORWARDABLE) { set(FORWARDABLE, true); } else { - if (config.getDefaultBooleanValue("forwardable", "libdefaults")) { + if (config.getBooleanValue("libdefaults", "forwardable")) { set(FORWARDABLE, true); } } diff --git a/jdk/src/share/classes/sun/security/krb5/internal/KerberosTime.java b/jdk/src/share/classes/sun/security/krb5/internal/KerberosTime.java index 1ad85ec50bd..ce141419f83 100644 --- a/jdk/src/share/classes/sun/security/krb5/internal/KerberosTime.java +++ b/jdk/src/share/classes/sun/security/krb5/internal/KerberosTime.java @@ -350,9 +350,9 @@ public class KerberosTime implements Cloneable { public static int getDefaultSkew() { int tdiff = Krb5.DEFAULT_ALLOWABLE_CLOCKSKEW; try { - Config c = Config.getInstance(); - if ((tdiff = c.getDefaultIntValue("clockskew", - "libdefaults")) == Integer.MIN_VALUE) { //value is not defined + if ((tdiff = Config.getInstance().getIntValue( + "libdefaults", "clockskew")) + == Integer.MIN_VALUE) { //value is not defined tdiff = Krb5.DEFAULT_ALLOWABLE_CLOCKSKEW; } } catch (KrbException e) { diff --git a/jdk/src/share/classes/sun/security/krb5/internal/crypto/CksumType.java b/jdk/src/share/classes/sun/security/krb5/internal/crypto/CksumType.java index 1896b40257a..eb4a1b1cb76 100644 --- a/jdk/src/share/classes/sun/security/krb5/internal/crypto/CksumType.java +++ b/jdk/src/share/classes/sun/security/krb5/internal/crypto/CksumType.java @@ -126,10 +126,10 @@ public abstract class CksumType { int cksumType = Checksum.CKSUMTYPE_RSA_MD5; // default try { Config c = Config.getInstance(); - if ((cksumType = (c.getType(c.getDefault("ap_req_checksum_type", - "libdefaults")))) == - 1) { - if ((cksumType = c.getType(c.getDefault("checksum_type", - "libdefaults"))) == -1) { + if ((cksumType = (Config.getType(c.get("libdefaults", + "ap_req_checksum_type")))) == - 1) { + if ((cksumType = Config.getType(c.get("libdefaults", + "checksum_type"))) == -1) { cksumType = Checksum.CKSUMTYPE_RSA_MD5; // default } } diff --git a/jdk/src/share/classes/sun/security/krb5/internal/crypto/EType.java b/jdk/src/share/classes/sun/security/krb5/internal/crypto/EType.java index 90082b12aa5..e46c049bc2f 100644 --- a/jdk/src/share/classes/sun/security/krb5/internal/crypto/EType.java +++ b/jdk/src/share/classes/sun/security/krb5/internal/crypto/EType.java @@ -48,13 +48,17 @@ import java.util.ArrayList; public abstract class EType { private static final boolean DEBUG = Krb5.DEBUG; - private static final boolean ALLOW_WEAK_CRYPTO; + private static boolean allowWeakCrypto; static { + initStatic(); + } + + public static void initStatic() { boolean allowed = true; try { Config cfg = Config.getInstance(); - String temp = cfg.getDefault("allow_weak_crypto", "libdefaults"); + String temp = cfg.get("libdefaults", "allow_weak_crypto"); if (temp != null && temp.equals("false")) allowed = false; } catch (Exception exc) { if (DEBUG) { @@ -63,7 +67,7 @@ public abstract class EType { exc.getMessage()); } } - ALLOW_WEAK_CRYPTO = allowed; + allowWeakCrypto = allowed; } public static EType getInstance (int eTypeConst) @@ -216,7 +220,7 @@ public abstract class EType { } else { result = BUILTIN_ETYPES; } - if (!ALLOW_WEAK_CRYPTO) { + if (!allowWeakCrypto) { // The last 2 etypes are now weak ones return Arrays.copyOfRange(result, 0, result.length - 2); } diff --git a/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java b/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java index 4b0ee703a0e..f5029e6767d 100644 --- a/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java +++ b/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java @@ -186,8 +186,8 @@ public class KeyTab implements KeyTabConstants { } else { String kname = null; try { - String keytab_names = Config.getInstance().getDefault - ("default_keytab_name", "libdefaults"); + String keytab_names = Config.getInstance().get + ("libdefaults", "default_keytab_name"); if (keytab_names != null) { StringTokenizer st = new StringTokenizer(keytab_names, " "); while (st.hasMoreTokens()) { diff --git a/jdk/test/sun/security/krb5/ConfPlusProp.java b/jdk/test/sun/security/krb5/ConfPlusProp.java index 9fe1adcf455..caf7d628897 100644 --- a/jdk/test/sun/security/krb5/ConfPlusProp.java +++ b/jdk/test/sun/security/krb5/ConfPlusProp.java @@ -25,6 +25,7 @@ * @bug 6857795 * @bug 6858589 * @bug 6972005 + * @compile -XDignore.symbol.file ConfPlusProp.java * @run main/othervm ConfPlusProp * @summary krb5.conf ignored if system properties on realm and kdc are provided */ @@ -75,7 +76,7 @@ public class ConfPlusProp { check("R1", "k1"); check("R2", "old"); check("R3", null); - if (!config.getDefault("forwardable", "libdefaults").equals("well")) { + if (!config.get("libdefaults", "forwardable").equals("well")) { throw new Exception("Extra config error"); } @@ -103,7 +104,7 @@ public class ConfPlusProp { check("R1", null); check("R2", null); check("R3", null); - if (config.getDefault("forwardable", "libdefaults") != null) { + if (config.get("libdefaults", "forwardable") != null) { throw new Exception("Extra config error"); } } @@ -121,7 +122,7 @@ public class ConfPlusProp { check("R1", "k1"); check("R2", "k2"); check("R3", "k2"); - if (!config.getDefault("forwardable", "libdefaults").equals("well")) { + if (!config.get("libdefaults", "forwardable").equals("well")) { throw new Exception("Extra config error"); } @@ -143,7 +144,7 @@ public class ConfPlusProp { check("R1", "k2"); check("R2", "k2"); check("R3", "k2"); - if (config.getDefault("forwardable", "libdefaults") != null) { + if (config.get("libdefaults", "forwardable") != null) { throw new Exception("Extra config error"); } } diff --git a/jdk/test/sun/security/krb5/DnsFallback.java b/jdk/test/sun/security/krb5/DnsFallback.java index 3a48b05d837..2702d365c85 100644 --- a/jdk/test/sun/security/krb5/DnsFallback.java +++ b/jdk/test/sun/security/krb5/DnsFallback.java @@ -28,12 +28,20 @@ * @summary fix dns_fallback parse error, and use dns by default */ -import sun.security.krb5.*; import java.io.*; +import java.lang.reflect.Method; +import sun.security.krb5.Config; public class DnsFallback { + + static Method useDNS_Realm; + public static void main(String[] args) throws Exception { + useDNS_Realm = Config.class.getDeclaredMethod("useDNS_Realm"); + useDNS_Realm.setAccessible(true); + + // for 6673164 check("true", "true", true); check("false", "true", false); @@ -48,22 +56,25 @@ public class DnsFallback { check(null, null, true); } - static void check(String realm, String fallback, boolean output) throws Exception { - FileOutputStream fo = new FileOutputStream("dnsfallback.conf"); - StringBuffer sb = new StringBuffer(); - sb.append("[libdefaults]\n"); - if (realm != null) { - sb.append("dns_lookup_realm=" + realm + "\n"); + static void check(String realm, String fallback, boolean output) + throws Exception { + + try (PrintStream ps = + new PrintStream(new FileOutputStream("dnsfallback.conf"))) { + ps.println("[libdefaults]\n"); + if (realm != null) { + ps.println("dns_lookup_realm=" + realm); + } + if (fallback != null) { + ps.println("dns_fallback=" + fallback); + } } - if (fallback != null) { - sb.append("dns_fallback=" + fallback + "\n"); - } - fo.write(sb.toString().getBytes()); - fo.close(); + System.setProperty("java.security.krb5.conf", "dnsfallback.conf"); Config.refresh(); System.out.println("Testing " + realm + ", " + fallback + ", " + output); - if (Config.getInstance().useDNS_Realm() != output) { + + if (!useDNS_Realm.invoke(Config.getInstance()).equals(output)) { throw new Exception("Fail"); } } diff --git a/jdk/test/sun/security/krb5/ParseConfig.java b/jdk/test/sun/security/krb5/ParseConfig.java index 43c5ce39f3a..b4e20602108 100644 --- a/jdk/test/sun/security/krb5/ParseConfig.java +++ b/jdk/test/sun/security/krb5/ParseConfig.java @@ -23,6 +23,7 @@ /* * @test * @bug 6319046 + * @compile -XDignore.symbol.file ParseConfig.java * @run main/othervm ParseConfig * @summary Problem with parsing krb5.conf */ @@ -37,7 +38,7 @@ public class ParseConfig { String sample = "kdc.example.com kdc2.example.com"; for ( int i = 0; i < 4; i++ ) { - String expected = config.getDefault("kdc", "EXAMPLE_" + i + ".COM"); + String expected = config.getAll("realms", "EXAMPLE_" + i + ".COM", "kdc"); if (!sample.equals(expected)) { throw new Exception("krb5.conf: unexpected kdc value \"" + expected + "\""); diff --git a/jdk/test/sun/security/krb5/auto/BasicKrb5Test.java b/jdk/test/sun/security/krb5/auto/BasicKrb5Test.java index aaf6b126668..bd01d253bbd 100644 --- a/jdk/test/sun/security/krb5/auto/BasicKrb5Test.java +++ b/jdk/test/sun/security/krb5/auto/BasicKrb5Test.java @@ -25,6 +25,7 @@ * @test * @bug 6706974 * @summary Add krb5 test infrastructure + * @compile -XDignore.symbol.file BasicKrb5Test.java * @run main/othervm BasicKrb5Test * @run main/othervm BasicKrb5Test des-cbc-crc * @run main/othervm BasicKrb5Test des-cbc-md5 @@ -86,7 +87,7 @@ public class BasicKrb5Test { new OneKDC(etype).writeJAASConf(); System.out.println("Testing etype " + etype); - if (etype != null && !EType.isSupported(Config.getInstance().getType(etype))) { + if (etype != null && !EType.isSupported(Config.getType(etype))) { // aes256 is not enabled on all systems System.out.println("Not supported."); return; diff --git a/jdk/test/sun/security/krb5/auto/MaxRetries.java b/jdk/test/sun/security/krb5/auto/MaxRetries.java index f4f86a3fc89..bf5d461f85f 100644 --- a/jdk/test/sun/security/krb5/auto/MaxRetries.java +++ b/jdk/test/sun/security/krb5/auto/MaxRetries.java @@ -108,7 +108,7 @@ public class MaxRetries { if (line.startsWith(">>> KDCCommunication")) { System.out.println(line); if (line.indexOf(timeoutTag) < 0) { - throw new Exception("Wrong timeout value"); + throw new Exception("Wrong timeout value" + timeoutTag); } count--; } diff --git a/jdk/test/sun/security/krb5/config/Duplicates.java b/jdk/test/sun/security/krb5/config/Duplicates.java new file mode 100644 index 00000000000..0d8bac70c6d --- /dev/null +++ b/jdk/test/sun/security/krb5/config/Duplicates.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 7184246 + * @compile -XDignore.symbol.file Duplicates.java + * @run main/othervm Duplicates + * @summary Simplify Config.get() of krb5 + */ + +import sun.security.krb5.Config; + +public class Duplicates { + public static void main(String[] args) throws Exception { + System.setProperty("java.security.krb5.conf", + System.getProperty("test.src", ".") +"/k1.conf"); + Config config = Config.getInstance(); + config.listTable(); + String s; + + // Latter overwrites former for root section + s = config.get("libdefaults", "default_realm"); + if (s != null) { + throw new Exception(); + } + // Latter overwrites former for strings + s = config.get("libdefaults", "default_tkt_enctypes"); + if (!s.equals("aes256-cts")) { + throw new Exception(); + } + // Latter overwrites former for sub-section + s = config.get("realms", "R1", "kdc"); + if (!s.equals("k2")) { + throw new Exception(s); + } + // Duplicate keys in [realms] are merged + s = config.getAll("realms", "R2", "kdc"); + if (!s.equals("k1 k2 k3 k4")) { + throw new Exception(s); + } + // Duplicate keys in [capaths] are merged + s = config.getAll("capaths", "R1", "R2"); + if (!s.equals("R3 R4 R5 R6")) { + throw new Exception(s); + } + // We can be very deep now + s = config.get("new", "x", "y", "z", "a", "b", "c"); + if (!s.equals("d")) { + throw new Exception(s); + } + } +} diff --git a/jdk/test/sun/security/krb5/config/SCDynamicConfigTest.java b/jdk/test/sun/security/krb5/config/SCDynamicConfigTest.java new file mode 100644 index 00000000000..b749927312b --- /dev/null +++ b/jdk/test/sun/security/krb5/config/SCDynamicConfigTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 7184246 + * @summary Simplify Config.get() of krb5 + */ +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Hashtable; +import java.util.Vector; +import sun.security.krb5.Config; +import sun.security.krb5.SCDynamicStoreConfig; + +public class SCDynamicConfigTest { + + static Vector>hosts() { + Vector > result = new Vector<>(); + Hashtable pair = new Hashtable<>(); + pair.put("host", "127.0.0.1"); + result.add(pair); + pair = new Hashtable<>(); + pair.put("host", "127.0.0.2"); + result.add(pair); + return result; + } + + public static void main(String[] args) throws Exception { + // Reconstruct a typical SCDynamicConfig.getKerberosConfig() output + Hashtable conf = new Hashtable<>(); + + Hashtable libdefaults = new Hashtable<>(); + libdefaults.put("default_realm", "REALM.COM"); + conf.put("libdefaults", libdefaults); + + Hashtable realms = new Hashtable<>(); + Hashtable thisRealm = new Hashtable<>(); + realms.put("REALM.COM", thisRealm); + thisRealm.put("kpasswd", hosts()); + thisRealm.put("kadmin", hosts()); + thisRealm.put("kdc", hosts()); + conf.put("realms", realms); + + Hashtable domain_realm = new Hashtable<>(); + domain_realm.put(".realm.com", "REALM.COM"); + domain_realm.put("realm.com", "REALM.COM"); + conf.put("domain_realm", domain_realm); + + System.out.println("SCDynamicConfig:\n"); + System.out.println(conf); + + // Simulate SCDynamicConfig.getConfig() output + Method m = SCDynamicStoreConfig.class.getDeclaredMethod( + "convertNativeConfig", Hashtable.class); + m.setAccessible(true); + conf = (Hashtable)m.invoke(null, conf); + + System.out.println("\nkrb5.conf:\n"); + System.out.println(conf); + + // Feed it into a Config object + System.setProperty("java.security.krb5.conf", "not-a-file"); + Config cf = Config.getInstance(); + Field f = Config.class.getDeclaredField("stanzaTable"); + f.setAccessible(true); + f.set(cf, conf); + + System.out.println("\nConfig:\n"); + System.out.println(cf); + + if (!cf.getDefaultRealm().equals("REALM.COM")) { + throw new Exception(); + } + if (!cf.getKDCList("REALM.COM").equals("127.0.0.1 127.0.0.2")) { + throw new Exception(); + } + if (!cf.get("domain_realm", ".realm.com").equals("REALM.COM")) { + throw new Exception(); + } + } +} diff --git a/jdk/test/sun/security/krb5/config/k1.conf b/jdk/test/sun/security/krb5/config/k1.conf new file mode 100644 index 00000000000..76b8513e74d --- /dev/null +++ b/jdk/test/sun/security/krb5/config/k1.conf @@ -0,0 +1,40 @@ +[libdefaults] +default_realm = R1 + +[libdefaults] +default_tkt_enctypes = aes128-cts +default_tkt_enctypes = aes256-cts + +[realms] +R1 = { + kdc = k1 +} +R1 = { + kdc = k2 +} +R2 = { + kdc = k1 + kdc = k2 k3 + admin_server = a1 + kdc = k4 +} + +[capaths] +R1 = { + R2 = R3 + R2 = R4 R5 + R2 = R6 +} + +[new] +x = { + y = { + z = { + a = { + b = { + c = d + } + } + } + } +} From 14364d11d2162763e3027bccd3c670356c553e32 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Mon, 29 Oct 2012 14:14:07 +0800 Subject: [PATCH 20/59] 7195426: kdc_default_options not supported correctly Reviewed-by: xuelei --- .../security/krb5/internal/KDCOptions.java | 12 ++--- .../krb5/config/KdcDefaultOptions.java | 46 +++++++++++++++++++ .../krb5/config/kdc_default_options.conf | 3 ++ 3 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 jdk/test/sun/security/krb5/config/KdcDefaultOptions.java create mode 100644 jdk/test/sun/security/krb5/config/kdc_default_options.conf diff --git a/jdk/src/share/classes/sun/security/krb5/internal/KDCOptions.java b/jdk/src/share/classes/sun/security/krb5/internal/KDCOptions.java index b0d609d9a8e..f154eeb1dc9 100644 --- a/jdk/src/share/classes/sun/security/krb5/internal/KDCOptions.java +++ b/jdk/src/share/classes/sun/security/krb5/internal/KDCOptions.java @@ -120,9 +120,9 @@ import java.io.IOException; public class KDCOptions extends KerberosFlags { - public final int KDC_OPT_PROXIABLE = 0x10000000; - public final int KDC_OPT_RENEWABLE_OK = 0x00000010; - public final int KDC_OPT_FORWARDABLE = 0x40000000; + private static final int KDC_OPT_PROXIABLE = 0x10000000; + private static final int KDC_OPT_RENEWABLE_OK = 0x00000010; + private static final int KDC_OPT_FORWARDABLE = 0x40000000; // KDC Options @@ -250,14 +250,14 @@ public class KDCOptions extends KerberosFlags { int options = config.getIntValue("libdefaults", "kdc_default_options"); - if ((options & RENEWABLE_OK) == RENEWABLE_OK) { + if ((options & KDC_OPT_RENEWABLE_OK) == KDC_OPT_RENEWABLE_OK) { set(RENEWABLE_OK, true); } else { if (config.getBooleanValue("libdefaults", "renewable")) { set(RENEWABLE_OK, true); } } - if ((options & PROXIABLE) == PROXIABLE) { + if ((options & KDC_OPT_PROXIABLE) == KDC_OPT_PROXIABLE) { set(PROXIABLE, true); } else { if (config.getBooleanValue("libdefaults", "proxiable")) { @@ -265,7 +265,7 @@ public class KDCOptions extends KerberosFlags { } } - if ((options & FORWARDABLE) == FORWARDABLE) { + if ((options & KDC_OPT_FORWARDABLE) == KDC_OPT_FORWARDABLE) { set(FORWARDABLE, true); } else { if (config.getBooleanValue("libdefaults", "forwardable")) { diff --git a/jdk/test/sun/security/krb5/config/KdcDefaultOptions.java b/jdk/test/sun/security/krb5/config/KdcDefaultOptions.java new file mode 100644 index 00000000000..fb920635e4e --- /dev/null +++ b/jdk/test/sun/security/krb5/config/KdcDefaultOptions.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 7195426 + * @summary kdc_default_options not supported correctly + * @compile -XDignore.symbol.file KdcDefaultOptions.java + * @run main/othervm KdcDefaultOptions + */ + +import sun.security.krb5.Config; +import sun.security.krb5.internal.KDCOptions; + +public class KdcDefaultOptions { + public static void main(String[] args) throws Exception { + System.setProperty("java.security.krb5.conf", + System.getProperty("test.src", ".") + "/kdc_default_options.conf"); + Config.refresh(); + KDCOptions options = new KDCOptions(); + if (!options.get(KDCOptions.FORWARDABLE) || + !options.get(KDCOptions.PROXIABLE) || + !options.get(KDCOptions.RENEWABLE_OK)) { + throw new Exception(options.toString()); + } + } +} diff --git a/jdk/test/sun/security/krb5/config/kdc_default_options.conf b/jdk/test/sun/security/krb5/config/kdc_default_options.conf new file mode 100644 index 00000000000..03482c823fd --- /dev/null +++ b/jdk/test/sun/security/krb5/config/kdc_default_options.conf @@ -0,0 +1,3 @@ +[libdefaults] +default_realm = EXAMPLE.COM +kdc_default_options = 0x50000010 From dc9bf2de74e5e65b206985aa7c9d682a70ef27b2 Mon Sep 17 00:00:00 2001 From: Staffan Larsen Date: Mon, 29 Oct 2012 09:23:55 +0100 Subject: [PATCH 21/59] 8001621: Update awk scripts that check output from jps/jcmd Reviewed-by: alanb --- jdk/test/sun/tools/jcmd/jcmd_Output1.awk | 2 +- jdk/test/sun/tools/jps/jps-l_Output1.awk | 2 +- jdk/test/sun/tools/jps/jps_Output1.awk | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/jdk/test/sun/tools/jcmd/jcmd_Output1.awk b/jdk/test/sun/tools/jcmd/jcmd_Output1.awk index 92bc9db6a29..986951dc178 100644 --- a/jdk/test/sun/tools/jcmd/jcmd_Output1.awk +++ b/jdk/test/sun/tools/jcmd/jcmd_Output1.awk @@ -16,7 +16,7 @@ BEGIN { } # or match on the condition that the class name is not available -/^[0-9]+ -- process information unavailable$/ { +/^[0-9]+ -- .*$/ { current=1; } diff --git a/jdk/test/sun/tools/jps/jps-l_Output1.awk b/jdk/test/sun/tools/jps/jps-l_Output1.awk index ed90256b8df..5280197ed6b 100644 --- a/jdk/test/sun/tools/jps/jps-l_Output1.awk +++ b/jdk/test/sun/tools/jps/jps-l_Output1.awk @@ -16,7 +16,7 @@ BEGIN { } # or match on the condition that the class name is not available -/^[0-9]+ -- process information unavailable$/ { +/^[0-9]+ -- .*$/ { matched++; } diff --git a/jdk/test/sun/tools/jps/jps_Output1.awk b/jdk/test/sun/tools/jps/jps_Output1.awk index 270889edfd9..1781bc560e3 100644 --- a/jdk/test/sun/tools/jps/jps_Output1.awk +++ b/jdk/test/sun/tools/jps/jps_Output1.awk @@ -16,7 +16,7 @@ BEGIN { } # or match on the condition that the class name is not available -/^[0-9]+ -- process information unavailable$/ { +/^[0-9]+ -- .*$/ { matched++; } From a5b6cdf1aed6f272ddc1922b383bbc78be3bd931 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20=C3=96hrstr=C3=B6m?= Date: Mon, 29 Oct 2012 14:10:49 +0100 Subject: [PATCH 22/59] 8000970: break out auxiliary classes that will prevent multi-core compilation of the JDK Reviewed-by: alanb, wetmore --- .../corba/se/impl/util/IdentityHashtable.java | 10 ----- .../se/impl/util/IdentityHashtableEntry.java | 43 +++++++++++++++++++ 2 files changed, 43 insertions(+), 10 deletions(-) create mode 100644 corba/src/share/classes/com/sun/corba/se/impl/util/IdentityHashtableEntry.java diff --git a/corba/src/share/classes/com/sun/corba/se/impl/util/IdentityHashtable.java b/corba/src/share/classes/com/sun/corba/se/impl/util/IdentityHashtable.java index 1e65abe073b..c4ff3971fa4 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/util/IdentityHashtable.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/util/IdentityHashtable.java @@ -42,16 +42,6 @@ import java.util.NoSuchElementException; * instead, it uses the System.identityHashcode() method and pointer comparison. * In addition, all synchronization has been removed. */ -/** - * IdentityHashtable collision list. - */ -class IdentityHashtableEntry { - int hash; - Object key; - Object value; - IdentityHashtableEntry next; -} - public final class IdentityHashtable extends Dictionary { /** * The hash table data. diff --git a/corba/src/share/classes/com/sun/corba/se/impl/util/IdentityHashtableEntry.java b/corba/src/share/classes/com/sun/corba/se/impl/util/IdentityHashtableEntry.java new file mode 100644 index 00000000000..cb4198de96e --- /dev/null +++ b/corba/src/share/classes/com/sun/corba/se/impl/util/IdentityHashtableEntry.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1999, 2004, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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. + */ + +/* + * Licensed Materials - Property of IBM + * RMI-IIOP v1.0 + * Copyright IBM Corp. 1998 1999 All Rights Reserved + * + */ + +package com.sun.corba.se.impl.util; + +/** + * IdentityHashtable collision list. + */ +class IdentityHashtableEntry { + int hash; + Object key; + Object value; + IdentityHashtableEntry next; +} From f5e72e432e8d63e86b5d00cc56f7059a54623fb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20=C3=96hrstr=C3=B6m?= Date: Mon, 29 Oct 2012 14:12:37 +0100 Subject: [PATCH 23/59] 8000970: break out auxiliary classes that will prevent multi-core compilation of the JDK Reviewed-by: alanb, wetmore --- .../generatenimbus/AbstractGradient.java | 40 + .../build/tools/generatenimbus/Border.java | 55 ++ .../build/tools/generatenimbus/Canvas.java | 45 + .../tools/generatenimbus/ComponentColor.java | 93 ++ .../build/tools/generatenimbus/Dimension.java | 38 + .../build/tools/generatenimbus/Ellipse.java | 42 + .../build/tools/generatenimbus/Gradient.java | 29 + .../tools/generatenimbus/GradientStop.java | 40 + .../build/tools/generatenimbus/Insets.java | 52 ++ .../src/build/tools/generatenimbus/Layer.java | 49 ++ .../src/build/tools/generatenimbus/Matte.java | 82 ++ .../src/build/tools/generatenimbus/Paint.java | 151 ---- .../src/build/tools/generatenimbus/Path.java | 39 + .../src/build/tools/generatenimbus/Point.java | 56 ++ .../tools/generatenimbus/RadialGradient.java | 29 + .../build/tools/generatenimbus/Rectangle.java | 61 ++ .../src/build/tools/generatenimbus/Shape.java | 85 -- .../tools/generatenimbus/SynthModel.java | 138 --- .../build/tools/generatenimbus/Typeface.java | 75 ++ .../build/tools/generatenimbus/UIColor.java | 41 + .../tools/generatenimbus/UIComponent.java | 54 ++ .../build/tools/generatenimbus/UIDefault.java | 81 -- .../build/tools/generatenimbus/UIFont.java | 40 + .../tools/generatenimbus/UIIconRegion.java | 53 ++ .../tools/generatenimbus/UIProperty.java | 84 ++ .../build/tools/generatenimbus/UIRegion.java | 200 +++++ .../build/tools/generatenimbus/UIState.java | 97 +++ .../tools/generatenimbus/UIStateType.java | 37 + .../build/tools/generatenimbus/UIStyle.java | 288 ------- .../classes/javax/management/timer/Timer.java | 51 -- .../management/timer/TimerAlarmClock.java | 80 ++ .../awt/im/ExecutableInputMethodManager.java | 632 ++++++++++++++ .../sun/awt/im/InputMethodManager.java | 575 ------------- jdk/src/share/classes/sun/misc/FDBigInt.java | 493 +++++++++++ .../classes/sun/misc/FloatingDecimal.java | 467 ----------- .../classes/sun/net/httpserver/Event.java | 8 - .../net/httpserver/WriteFinishedEvent.java | 34 + .../net/www/http/KeepAliveCleanerEntry.java | 56 ++ .../sun/net/www/http/KeepAliveStream.java | 29 - .../sun/security/ssl/ExtensionType.java | 101 +++ .../sun/security/ssl/HelloExtension.java | 45 + .../sun/security/ssl/HelloExtensions.java | 792 ------------------ .../ssl/RenegotiationInfoExtension.java | 112 +++ .../sun/security/ssl/ServerNameExtension.java | 280 +++++++ .../ssl/SignatureAlgorithmsExtension.java | 135 +++ .../ssl/SupportedEllipticCurvesExtension.java | 215 +++++ ...upportedEllipticPointFormatsExtension.java | 101 +++ .../sun/security/ssl/UnknownExtension.java | 57 ++ .../classes/sun/awt/X11/XChoicePeer.java | 14 - .../sun/awt/X11/XChoicePeerListener.java | 40 + .../classes/sun/font/DelegateStrike.java | 114 +++ .../classes/sun/font/NativeStrike.java | 85 +- .../java2d/jules/JulesAATileGenerator.java | 21 - .../sun/java2d/jules/TileTrapContainer.java | 49 ++ 54 files changed, 3976 insertions(+), 2784 deletions(-) create mode 100644 jdk/make/tools/src/build/tools/generatenimbus/AbstractGradient.java create mode 100644 jdk/make/tools/src/build/tools/generatenimbus/Border.java create mode 100644 jdk/make/tools/src/build/tools/generatenimbus/Canvas.java create mode 100644 jdk/make/tools/src/build/tools/generatenimbus/ComponentColor.java create mode 100644 jdk/make/tools/src/build/tools/generatenimbus/Dimension.java create mode 100644 jdk/make/tools/src/build/tools/generatenimbus/Ellipse.java create mode 100644 jdk/make/tools/src/build/tools/generatenimbus/Gradient.java create mode 100644 jdk/make/tools/src/build/tools/generatenimbus/GradientStop.java create mode 100644 jdk/make/tools/src/build/tools/generatenimbus/Insets.java create mode 100644 jdk/make/tools/src/build/tools/generatenimbus/Layer.java create mode 100644 jdk/make/tools/src/build/tools/generatenimbus/Matte.java create mode 100644 jdk/make/tools/src/build/tools/generatenimbus/Path.java create mode 100644 jdk/make/tools/src/build/tools/generatenimbus/Point.java create mode 100644 jdk/make/tools/src/build/tools/generatenimbus/RadialGradient.java create mode 100644 jdk/make/tools/src/build/tools/generatenimbus/Rectangle.java create mode 100644 jdk/make/tools/src/build/tools/generatenimbus/Typeface.java create mode 100644 jdk/make/tools/src/build/tools/generatenimbus/UIColor.java create mode 100644 jdk/make/tools/src/build/tools/generatenimbus/UIComponent.java create mode 100644 jdk/make/tools/src/build/tools/generatenimbus/UIFont.java create mode 100644 jdk/make/tools/src/build/tools/generatenimbus/UIIconRegion.java create mode 100644 jdk/make/tools/src/build/tools/generatenimbus/UIProperty.java create mode 100644 jdk/make/tools/src/build/tools/generatenimbus/UIRegion.java create mode 100644 jdk/make/tools/src/build/tools/generatenimbus/UIState.java create mode 100644 jdk/make/tools/src/build/tools/generatenimbus/UIStateType.java create mode 100644 jdk/src/share/classes/javax/management/timer/TimerAlarmClock.java create mode 100644 jdk/src/share/classes/sun/awt/im/ExecutableInputMethodManager.java create mode 100644 jdk/src/share/classes/sun/misc/FDBigInt.java create mode 100644 jdk/src/share/classes/sun/net/httpserver/WriteFinishedEvent.java create mode 100644 jdk/src/share/classes/sun/net/www/http/KeepAliveCleanerEntry.java create mode 100644 jdk/src/share/classes/sun/security/ssl/ExtensionType.java create mode 100644 jdk/src/share/classes/sun/security/ssl/HelloExtension.java create mode 100644 jdk/src/share/classes/sun/security/ssl/RenegotiationInfoExtension.java create mode 100644 jdk/src/share/classes/sun/security/ssl/ServerNameExtension.java create mode 100644 jdk/src/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java create mode 100644 jdk/src/share/classes/sun/security/ssl/SupportedEllipticCurvesExtension.java create mode 100644 jdk/src/share/classes/sun/security/ssl/SupportedEllipticPointFormatsExtension.java create mode 100644 jdk/src/share/classes/sun/security/ssl/UnknownExtension.java create mode 100644 jdk/src/solaris/classes/sun/awt/X11/XChoicePeerListener.java create mode 100644 jdk/src/solaris/classes/sun/font/DelegateStrike.java create mode 100644 jdk/src/solaris/classes/sun/java2d/jules/TileTrapContainer.java diff --git a/jdk/make/tools/src/build/tools/generatenimbus/AbstractGradient.java b/jdk/make/tools/src/build/tools/generatenimbus/AbstractGradient.java new file mode 100644 index 00000000000..a1164c4f105 --- /dev/null +++ b/jdk/make/tools/src/build/tools/generatenimbus/AbstractGradient.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.generatenimbus; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlElement; + +class AbstractGradient extends Paint { + public static enum CycleMethod { + NO_CYCLE, REFLECT, REPEAT + } + + @XmlElement(name="stop") private ArrayList stops; + public List getStops() { return stops; } +} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/Border.java b/jdk/make/tools/src/build/tools/generatenimbus/Border.java new file mode 100644 index 00000000000..b1f7426b572 --- /dev/null +++ b/jdk/make/tools/src/build/tools/generatenimbus/Border.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.generatenimbus; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlEnumValue; + +class Border { + enum BorderType { + @XmlEnumValue("empty") EMPTY, + @XmlEnumValue("painter") PAINTER + } + @XmlAttribute private BorderType type; + @XmlAttribute private String painter; + @XmlAttribute private int top; + @XmlAttribute private int left; + @XmlAttribute private int bottom; + @XmlAttribute private int right; + + public String write() { + switch (type) { + case PAINTER: + return String.format("new PainterBorder(\"%s\", new Insets(%d, %d, %d, %d))", + painter, top, left, bottom, right); + case EMPTY: + return String.format("BorderFactory.createEmptyBorder(%d, %d, %d, %d)", + top, left, bottom, right); + default: + return "### Look, here's an unknown border! $$$"; + } + } +} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/Canvas.java b/jdk/make/tools/src/build/tools/generatenimbus/Canvas.java new file mode 100644 index 00000000000..9e96e050332 --- /dev/null +++ b/jdk/make/tools/src/build/tools/generatenimbus/Canvas.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.generatenimbus; + +import java.util.List; + +import javax.xml.bind.annotation.XmlElement; + +class Canvas { + @XmlElement private Dimension size; + public Dimension getSize() { return size; } + + @XmlElement(name="layer") private List layers; + public List getLayers() { return layers; } + + @XmlElement private Insets stretchingInsets = null; + public Insets getStretchingInsets() { return stretchingInsets; } + + public boolean isBlank() { + return layers.size() == 0 || (layers.size() == 1 && layers.get(0).isEmpty()); + } +} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/ComponentColor.java b/jdk/make/tools/src/build/tools/generatenimbus/ComponentColor.java new file mode 100644 index 00000000000..f2fa0c5f294 --- /dev/null +++ b/jdk/make/tools/src/build/tools/generatenimbus/ComponentColor.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.generatenimbus; + +class ComponentColor { + private String propertyName; + private String defaultColorVariableName; + private float saturationOffset = 0, brightnessOffset = 0; + private int alphaOffset = 0; + + ComponentColor(String propertyName, + String defaultColorVariableName, + float saturationOffset, + float brightnessOffset, + int alphaOffset) { + this.propertyName = propertyName; + this.defaultColorVariableName = defaultColorVariableName; + this.saturationOffset = saturationOffset; + this.brightnessOffset = brightnessOffset; + this.alphaOffset = alphaOffset; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + ComponentColor c = (ComponentColor) o; + if (alphaOffset != c.alphaOffset) { + return false; + } + if (Float.compare(saturationOffset, c.saturationOffset) != 0) { + return false; + } + if (Float.compare(brightnessOffset, c.brightnessOffset) != 0) { + return false; + } + if (defaultColorVariableName != null ? !defaultColorVariableName.equals(c.defaultColorVariableName) : c.defaultColorVariableName != null) { + return false; + } + if (propertyName != null ? !propertyName.equals(c.propertyName) : c.propertyName != null) { + return false; + } + return true; + } + + @Override + public int hashCode() { + int hash = 5; + hash = 61 * hash + (this.propertyName != null ? this.propertyName.hashCode() : 0); + hash = 61 * hash + (this.defaultColorVariableName != null ? this.defaultColorVariableName.hashCode() : 0); + hash = 61 * hash + Float.floatToIntBits(this.saturationOffset); + hash = 61 * hash + Float.floatToIntBits(this.brightnessOffset); + hash = 61 * hash + this.alphaOffset; + return hash; + } + + public void write(StringBuilder sb) { + sb.append(" getComponentColor(c, \""). + append(propertyName).append("\", "). + append(defaultColorVariableName).append(", "). + append(saturationOffset).append("f, "). + append(brightnessOffset).append("f, "). + append(alphaOffset); + } +} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/Dimension.java b/jdk/make/tools/src/build/tools/generatenimbus/Dimension.java new file mode 100644 index 00000000000..96e8e0dcff3 --- /dev/null +++ b/jdk/make/tools/src/build/tools/generatenimbus/Dimension.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.generatenimbus; + +import javax.xml.bind.annotation.XmlAttribute; + +class Dimension { + @XmlAttribute int width; + @XmlAttribute int height; + + public String write(boolean uiResource) { + String uiSuffix = (uiResource ? "UIResource" : ""); + return String.format("new Dimension%s(%d, %d)", uiSuffix, width, height); + } +} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/Ellipse.java b/jdk/make/tools/src/build/tools/generatenimbus/Ellipse.java new file mode 100644 index 00000000000..20458e63d56 --- /dev/null +++ b/jdk/make/tools/src/build/tools/generatenimbus/Ellipse.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.generatenimbus; + +import javax.xml.bind.annotation.XmlAttribute; + +class Ellipse extends Shape { + @XmlAttribute private double x1; + public double getX1() { return x1; } + + @XmlAttribute private double x2; + public double getX2() { return x2; } + + @XmlAttribute private double y1; + public double getY1() { return y1; } + + @XmlAttribute private double y2; + public double getY2() { return y2; } +} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/Gradient.java b/jdk/make/tools/src/build/tools/generatenimbus/Gradient.java new file mode 100644 index 00000000000..c1fa25d19f2 --- /dev/null +++ b/jdk/make/tools/src/build/tools/generatenimbus/Gradient.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.generatenimbus; + +class Gradient extends AbstractGradient { +} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/GradientStop.java b/jdk/make/tools/src/build/tools/generatenimbus/GradientStop.java new file mode 100644 index 00000000000..41f7dd182af --- /dev/null +++ b/jdk/make/tools/src/build/tools/generatenimbus/GradientStop.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.generatenimbus; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; + +class GradientStop { + @XmlAttribute private float position; + public float getPosition() { return position; } + + @XmlAttribute private float midpoint; + public float getMidpoint() { return midpoint; } + + @XmlElement private Matte matte; + public Matte getColor() { return matte; } +} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/Insets.java b/jdk/make/tools/src/build/tools/generatenimbus/Insets.java new file mode 100644 index 00000000000..0a3e9385b30 --- /dev/null +++ b/jdk/make/tools/src/build/tools/generatenimbus/Insets.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.generatenimbus; + +import javax.xml.bind.annotation.XmlAttribute; + +class Insets { + @XmlAttribute int top; + @XmlAttribute int left; + @XmlAttribute int bottom; + @XmlAttribute int right; + + public Insets() { + this(0, 0, 0, 0); + } + + public Insets(int top, int left, int bottom, int right) { + this.top = top; + this.left = left; + this.bottom = bottom; + this.right = right; + } + + public String write(boolean uiResource) { + String uiSuffix = (uiResource ? "UIResource" : ""); + return String.format("new Insets%s(%d, %d, %d, %d)", + uiSuffix, top, left, bottom, right); + } +} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/Layer.java b/jdk/make/tools/src/build/tools/generatenimbus/Layer.java new file mode 100644 index 00000000000..fdaf8eeec51 --- /dev/null +++ b/jdk/make/tools/src/build/tools/generatenimbus/Layer.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.generatenimbus; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlElements; + +class Layer { + /** List of shapes in this layer, first shape is painted on top */ + @XmlElements({ + @XmlElement(name = "ellipse", type = Ellipse.class), + @XmlElement(name = "path", type = Path.class), + @XmlElement(name = "rectangle", type = Rectangle.class) + }) + @XmlElementWrapper(name="shapes") + private List shapes = new ArrayList(); + public List getShapes() { return shapes; } + + public boolean isEmpty() { + return shapes.isEmpty(); + } +} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/Matte.java b/jdk/make/tools/src/build/tools/generatenimbus/Matte.java new file mode 100644 index 00000000000..8281face711 --- /dev/null +++ b/jdk/make/tools/src/build/tools/generatenimbus/Matte.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.generatenimbus; + +import javax.xml.bind.annotation.XmlAttribute; + +class Matte extends Paint { + @XmlAttribute private int red; + @XmlAttribute private int green; + @XmlAttribute private int blue; + @XmlAttribute private int alpha; + + @XmlAttribute private String uiDefaultParentName = null; + @XmlAttribute private float hueOffset = 0; + @XmlAttribute private float saturationOffset = 0; + @XmlAttribute private float brightnessOffset = 0; + @XmlAttribute private int alphaOffset = 0; + + @XmlAttribute private String componentPropertyName = null; + public String getComponentPropertyName() { return componentPropertyName; } + + @XmlAttribute private boolean uiResource = true; + + public boolean isAbsolute() { + return uiDefaultParentName == null; + } + + public String getDeclaration() { + if (isAbsolute()) { + return String.format("new Color(%d, %d, %d, %d)", + red, green, blue, alpha); + } else { + return String.format("decodeColor(\"%s\", %sf, %sf, %sf, %d)", + uiDefaultParentName, String.valueOf(hueOffset), + String.valueOf(saturationOffset), + String.valueOf(brightnessOffset), alphaOffset); + } + } + + public String write() { + if (isAbsolute()) { + return String.format("%s, %s, %s, %s", red, green, blue, alpha); + } else { + String s = String.format("\"%s\", %sf, %sf, %sf, %d", + uiDefaultParentName, String.valueOf(hueOffset), + String.valueOf(saturationOffset), + String.valueOf(brightnessOffset), alphaOffset); + if (! uiResource) { + s += ", false"; + } + return s; + } + } + + public ComponentColor createComponentColor(String variableName) { + return new ComponentColor(componentPropertyName, variableName, + saturationOffset, brightnessOffset, alphaOffset); + } +} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/Paint.java b/jdk/make/tools/src/build/tools/generatenimbus/Paint.java index 7a0d85d88a3..49822ca6ccc 100644 --- a/jdk/make/tools/src/build/tools/generatenimbus/Paint.java +++ b/jdk/make/tools/src/build/tools/generatenimbus/Paint.java @@ -25,157 +25,6 @@ package build.tools.generatenimbus; -import java.util.ArrayList; -import java.util.List; -import javax.xml.bind.annotation.XmlAttribute; -import javax.xml.bind.annotation.XmlElement; public abstract class Paint { } - -class Matte extends Paint { - @XmlAttribute private int red; - @XmlAttribute private int green; - @XmlAttribute private int blue; - @XmlAttribute private int alpha; - - @XmlAttribute private String uiDefaultParentName = null; - @XmlAttribute private float hueOffset = 0; - @XmlAttribute private float saturationOffset = 0; - @XmlAttribute private float brightnessOffset = 0; - @XmlAttribute private int alphaOffset = 0; - - @XmlAttribute private String componentPropertyName = null; - public String getComponentPropertyName() { return componentPropertyName; } - - @XmlAttribute private boolean uiResource = true; - - public boolean isAbsolute() { - return uiDefaultParentName == null; - } - - public String getDeclaration() { - if (isAbsolute()) { - return String.format("new Color(%d, %d, %d, %d)", - red, green, blue, alpha); - } else { - return String.format("decodeColor(\"%s\", %sf, %sf, %sf, %d)", - uiDefaultParentName, String.valueOf(hueOffset), - String.valueOf(saturationOffset), - String.valueOf(brightnessOffset), alphaOffset); - } - } - - public String write() { - if (isAbsolute()) { - return String.format("%s, %s, %s, %s", red, green, blue, alpha); - } else { - String s = String.format("\"%s\", %sf, %sf, %sf, %d", - uiDefaultParentName, String.valueOf(hueOffset), - String.valueOf(saturationOffset), - String.valueOf(brightnessOffset), alphaOffset); - if (! uiResource) { - s += ", false"; - } - return s; - } - } - - public ComponentColor createComponentColor(String variableName) { - return new ComponentColor(componentPropertyName, variableName, - saturationOffset, brightnessOffset, alphaOffset); - } -} - -class ComponentColor { - private String propertyName; - private String defaultColorVariableName; - private float saturationOffset = 0, brightnessOffset = 0; - private int alphaOffset = 0; - - ComponentColor(String propertyName, - String defaultColorVariableName, - float saturationOffset, - float brightnessOffset, - int alphaOffset) { - this.propertyName = propertyName; - this.defaultColorVariableName = defaultColorVariableName; - this.saturationOffset = saturationOffset; - this.brightnessOffset = brightnessOffset; - this.alphaOffset = alphaOffset; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - ComponentColor c = (ComponentColor) o; - if (alphaOffset != c.alphaOffset) { - return false; - } - if (Float.compare(saturationOffset, c.saturationOffset) != 0) { - return false; - } - if (Float.compare(brightnessOffset, c.brightnessOffset) != 0) { - return false; - } - if (defaultColorVariableName != null ? !defaultColorVariableName.equals(c.defaultColorVariableName) : c.defaultColorVariableName != null) { - return false; - } - if (propertyName != null ? !propertyName.equals(c.propertyName) : c.propertyName != null) { - return false; - } - return true; - } - - @Override - public int hashCode() { - int hash = 5; - hash = 61 * hash + (this.propertyName != null ? this.propertyName.hashCode() : 0); - hash = 61 * hash + (this.defaultColorVariableName != null ? this.defaultColorVariableName.hashCode() : 0); - hash = 61 * hash + Float.floatToIntBits(this.saturationOffset); - hash = 61 * hash + Float.floatToIntBits(this.brightnessOffset); - hash = 61 * hash + this.alphaOffset; - return hash; - } - - public void write(StringBuilder sb) { - sb.append(" getComponentColor(c, \""). - append(propertyName).append("\", "). - append(defaultColorVariableName).append(", "). - append(saturationOffset).append("f, "). - append(brightnessOffset).append("f, "). - append(alphaOffset); - } -} - -class GradientStop { - @XmlAttribute private float position; - public float getPosition() { return position; } - - @XmlAttribute private float midpoint; - public float getMidpoint() { return midpoint; } - - @XmlElement private Matte matte; - public Matte getColor() { return matte; } -} - -class AbstractGradient extends Paint { - public static enum CycleMethod { - NO_CYCLE, REFLECT, REPEAT - } - - @XmlElement(name="stop") private ArrayList stops; - public List getStops() { return stops; } -} - -class Gradient extends AbstractGradient { -} - -class RadialGradient extends AbstractGradient { -} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/Path.java b/jdk/make/tools/src/build/tools/generatenimbus/Path.java new file mode 100644 index 00000000000..5ee390b414c --- /dev/null +++ b/jdk/make/tools/src/build/tools/generatenimbus/Path.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.generatenimbus; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; + +class Path extends Shape { + @XmlElement(name="point") + @XmlElementWrapper(name="points") + private List controlPoints = new ArrayList(); + public List getControlPoints() { return controlPoints; } +} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/Point.java b/jdk/make/tools/src/build/tools/generatenimbus/Point.java new file mode 100644 index 00000000000..c69c2813b2a --- /dev/null +++ b/jdk/make/tools/src/build/tools/generatenimbus/Point.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.generatenimbus; + +import javax.xml.bind.annotation.XmlAttribute; + +class Point { + @XmlAttribute private double x; + public double getX() { return x; } + + @XmlAttribute private double y; + public double getY() { return y; } + + @XmlAttribute(name="cp1x") private double cp1x; + public double getCp1X() { return cp1x; } + + @XmlAttribute(name="cp1y") private double cp1y; + public double getCp1Y() { return cp1y; } + + @XmlAttribute(name="cp2x") private double cp2x; + public double getCp2X() { return cp2x; } + + @XmlAttribute(name="cp2y") private double cp2y; + public double getCp2Y() { return cp2y; } + + public boolean isP1Sharp() { + return cp1x == x && cp1y == y; + } + + public boolean isP2Sharp() { + return cp2x == x && cp2y == y; + } +} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/RadialGradient.java b/jdk/make/tools/src/build/tools/generatenimbus/RadialGradient.java new file mode 100644 index 00000000000..df1584820e8 --- /dev/null +++ b/jdk/make/tools/src/build/tools/generatenimbus/RadialGradient.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.generatenimbus; + +class RadialGradient extends AbstractGradient { +} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/Rectangle.java b/jdk/make/tools/src/build/tools/generatenimbus/Rectangle.java new file mode 100644 index 00000000000..3e15b4438ee --- /dev/null +++ b/jdk/make/tools/src/build/tools/generatenimbus/Rectangle.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.generatenimbus; + +import javax.xml.bind.annotation.XmlAttribute; + +class Rectangle extends Shape { + @XmlAttribute private double x1; + public double getX1() { return x1; } + + @XmlAttribute private double x2; + public double getX2() { return x2; } + + @XmlAttribute private double y1; + public double getY1() { return y1; } + + @XmlAttribute private double y2; + public double getY2() { return y2; } + + @XmlAttribute + public double getRounding() { + double rounding = Math.abs(roundingX - x1) * 2; + return rounding > 2 ? rounding : 0; + } + + public void setRounding(double rounding) { + if (rounding > 0 && rounding < 2) { + rounding = 0; + } + roundingX = rounding / 2d + x1; + } + private double roundingX; + + public boolean isRounded() { + return getRounding() > 0; + } + +} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/Shape.java b/jdk/make/tools/src/build/tools/generatenimbus/Shape.java index 7fd97620177..f06a0760bbf 100644 --- a/jdk/make/tools/src/build/tools/generatenimbus/Shape.java +++ b/jdk/make/tools/src/build/tools/generatenimbus/Shape.java @@ -25,11 +25,8 @@ package build.tools.generatenimbus; -import java.util.ArrayList; -import java.util.List; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlElements; @@ -56,85 +53,3 @@ public abstract class Shape { @XmlAttribute double y2; } } - -class Point { - @XmlAttribute private double x; - public double getX() { return x; } - - @XmlAttribute private double y; - public double getY() { return y; } - - @XmlAttribute(name="cp1x") private double cp1x; - public double getCp1X() { return cp1x; } - - @XmlAttribute(name="cp1y") private double cp1y; - public double getCp1Y() { return cp1y; } - - @XmlAttribute(name="cp2x") private double cp2x; - public double getCp2X() { return cp2x; } - - @XmlAttribute(name="cp2y") private double cp2y; - public double getCp2Y() { return cp2y; } - - public boolean isP1Sharp() { - return cp1x == x && cp1y == y; - } - - public boolean isP2Sharp() { - return cp2x == x && cp2y == y; - } -} - -class Path extends Shape { - @XmlElement(name="point") - @XmlElementWrapper(name="points") - private List controlPoints = new ArrayList(); - public List getControlPoints() { return controlPoints; } -} - -class Rectangle extends Shape { - @XmlAttribute private double x1; - public double getX1() { return x1; } - - @XmlAttribute private double x2; - public double getX2() { return x2; } - - @XmlAttribute private double y1; - public double getY1() { return y1; } - - @XmlAttribute private double y2; - public double getY2() { return y2; } - - @XmlAttribute - public double getRounding() { - double rounding = Math.abs(roundingX - x1) * 2; - return rounding > 2 ? rounding : 0; - } - - public void setRounding(double rounding) { - if (rounding > 0 && rounding < 2) { - rounding = 0; - } - roundingX = rounding / 2d + x1; - } - private double roundingX; - - public boolean isRounded() { - return getRounding() > 0; - } - -} - -class Ellipse extends Shape { - @XmlAttribute private double x1; - public double getX1() { return x1; } - - @XmlAttribute private double x2; - public double getX2() { return x2; } - - @XmlAttribute private double y1; - public double getY1() { return y1; } - - @XmlAttribute private double y2; - public double getY2() { return y2; } -} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/SynthModel.java b/jdk/make/tools/src/build/tools/generatenimbus/SynthModel.java index d63dd8beeaa..e2d82731e25 100644 --- a/jdk/make/tools/src/build/tools/generatenimbus/SynthModel.java +++ b/jdk/make/tools/src/build/tools/generatenimbus/SynthModel.java @@ -25,9 +25,7 @@ package build.tools.generatenimbus; -import java.awt.Font; import java.util.ArrayList; -import java.util.List; import javax.xml.bind.annotation.*; @@ -78,139 +76,3 @@ public class SynthModel { } } } - -class Typeface { - public enum DeriveStyle { - Default, Off, On; - - @Override public String toString() { - switch (this) { - default: return "null"; - case On: return "true"; - case Off: return "false"; - } - } - } - - @XmlAttribute private String uiDefaultParentName; - @XmlAttribute(name="family") private String name; - @XmlAttribute private int size; - @XmlAttribute private DeriveStyle bold = DeriveStyle.Default; - @XmlAttribute private DeriveStyle italic = DeriveStyle.Default; - @XmlAttribute private float sizeOffset = 1f; - - public boolean isAbsolute() { - return uiDefaultParentName == null; - } - - public String write() { - if (isAbsolute()) { - int style = Font.PLAIN; - if (bold == DeriveStyle.On) { - style = style | Font.BOLD; - } - if (italic == DeriveStyle.On) { - style = style | Font.ITALIC; - } - - return String.format( - "new javax.swing.plaf.FontUIResource(\"%s\", %d, %d)", - name, style, size); - } else { - return String.format( - "new DerivedFont(\"%s\", %sf, %s, %s)", - uiDefaultParentName, String.valueOf(sizeOffset), bold, italic); - } - } -} - -class Border { - enum BorderType { - @XmlEnumValue("empty") EMPTY, - @XmlEnumValue("painter") PAINTER - } - @XmlAttribute private BorderType type; - @XmlAttribute private String painter; - @XmlAttribute private int top; - @XmlAttribute private int left; - @XmlAttribute private int bottom; - @XmlAttribute private int right; - - public String write() { - switch (type) { - case PAINTER: - return String.format("new PainterBorder(\"%s\", new Insets(%d, %d, %d, %d))", - painter, top, left, bottom, right); - case EMPTY: - return String.format("BorderFactory.createEmptyBorder(%d, %d, %d, %d)", - top, left, bottom, right); - default: - return "### Look, here's an unknown border! $$$"; - } - } -} - -class Insets { - @XmlAttribute int top; - @XmlAttribute int left; - @XmlAttribute int bottom; - @XmlAttribute int right; - - public Insets() { - this(0, 0, 0, 0); - } - - public Insets(int top, int left, int bottom, int right) { - this.top = top; - this.left = left; - this.bottom = bottom; - this.right = right; - } - - public String write(boolean uiResource) { - String uiSuffix = (uiResource ? "UIResource" : ""); - return String.format("new Insets%s(%d, %d, %d, %d)", - uiSuffix, top, left, bottom, right); - } -} - -class Dimension { - @XmlAttribute int width; - @XmlAttribute int height; - - public String write(boolean uiResource) { - String uiSuffix = (uiResource ? "UIResource" : ""); - return String.format("new Dimension%s(%d, %d)", uiSuffix, width, height); - } -} - -class Canvas { - @XmlElement private Dimension size; - public Dimension getSize() { return size; } - - @XmlElement(name="layer") private List layers; - public List getLayers() { return layers; } - - @XmlElement private Insets stretchingInsets = null; - public Insets getStretchingInsets() { return stretchingInsets; } - - public boolean isBlank() { - return layers.size() == 0 || (layers.size() == 1 && layers.get(0).isEmpty()); - } -} - -class Layer { - /** List of shapes in this layer, first shape is painted on top */ - @XmlElements({ - @XmlElement(name = "ellipse", type = Ellipse.class), - @XmlElement(name = "path", type = Path.class), - @XmlElement(name = "rectangle", type = Rectangle.class) - }) - @XmlElementWrapper(name="shapes") - private List shapes = new ArrayList(); - public List getShapes() { return shapes; } - - public boolean isEmpty() { - return shapes.isEmpty(); - } -} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/Typeface.java b/jdk/make/tools/src/build/tools/generatenimbus/Typeface.java new file mode 100644 index 00000000000..cf17093d4d7 --- /dev/null +++ b/jdk/make/tools/src/build/tools/generatenimbus/Typeface.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.generatenimbus; + +import java.awt.Font; + +import javax.xml.bind.annotation.XmlAttribute; + +class Typeface { + public enum DeriveStyle { + Default, Off, On; + + @Override public String toString() { + switch (this) { + default: return "null"; + case On: return "true"; + case Off: return "false"; + } + } + } + + @XmlAttribute private String uiDefaultParentName; + @XmlAttribute(name="family") private String name; + @XmlAttribute private int size; + @XmlAttribute private DeriveStyle bold = DeriveStyle.Default; + @XmlAttribute private DeriveStyle italic = DeriveStyle.Default; + @XmlAttribute private float sizeOffset = 1f; + + public boolean isAbsolute() { + return uiDefaultParentName == null; + } + + public String write() { + if (isAbsolute()) { + int style = Font.PLAIN; + if (bold == DeriveStyle.On) { + style = style | Font.BOLD; + } + if (italic == DeriveStyle.On) { + style = style | Font.ITALIC; + } + + return String.format( + "new javax.swing.plaf.FontUIResource(\"%s\", %d, %d)", + name, style, size); + } else { + return String.format( + "new DerivedFont(\"%s\", %sf, %s, %s)", + uiDefaultParentName, String.valueOf(sizeOffset), bold, italic); + } + } +} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/UIColor.java b/jdk/make/tools/src/build/tools/generatenimbus/UIColor.java new file mode 100644 index 00000000000..1bf3d579f18 --- /dev/null +++ b/jdk/make/tools/src/build/tools/generatenimbus/UIColor.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.generatenimbus; + +import javax.xml.bind.annotation.XmlElement; + +class UIColor extends UIDefault { + + @XmlElement + public void setMatte(Matte m) { + setValue(m); + } + + public String write() { + return String.format(" addColor(d, \"%s\", %s);\n", + getName(), getValue().write()); + } +} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/UIComponent.java b/jdk/make/tools/src/build/tools/generatenimbus/UIComponent.java new file mode 100644 index 00000000000..861f52f486f --- /dev/null +++ b/jdk/make/tools/src/build/tools/generatenimbus/UIComponent.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.generatenimbus; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; + +class UIComponent extends UIRegion { + @XmlAttribute private String componentName; + + @XmlElement(name="stateType") + @XmlElementWrapper(name="stateTypes") + private List stateTypes = new ArrayList(); + public List getStateTypes() { return stateTypes; } + + @Override public String getKey() { + if (key == null || "".equals(key)) { + if (componentName == null || "".equals(componentName)) { + return name; + } else { + return "\"" + componentName + "\""; + } + } else { + return key; + } + } +} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/UIDefault.java b/jdk/make/tools/src/build/tools/generatenimbus/UIDefault.java index 55bd0e412b7..26827e6247f 100644 --- a/jdk/make/tools/src/build/tools/generatenimbus/UIDefault.java +++ b/jdk/make/tools/src/build/tools/generatenimbus/UIDefault.java @@ -26,7 +26,6 @@ package build.tools.generatenimbus; import javax.xml.bind.annotation.XmlAttribute; -import javax.xml.bind.annotation.XmlElement; public class UIDefault { @XmlAttribute private String name; @@ -44,83 +43,3 @@ public class UIDefault { this.value = value; } } - -class UIColor extends UIDefault { - - @XmlElement - public void setMatte(Matte m) { - setValue(m); - } - - public String write() { - return String.format(" addColor(d, \"%s\", %s);\n", - getName(), getValue().write()); - } -} - -class UIFont extends UIDefault { - @XmlElement - public void setTypeface(Typeface t) { - setValue(t); - } - - public String write() { - return String.format(" d.put(\"%s\", %s);\n", - getName(), getValue().write()); - } -} - -class UIProperty extends UIDefault { - public static enum PropertyType { - BOOLEAN, INT, FLOAT, DOUBLE, STRING, FONT, COLOR, INSETS, DIMENSION, BORDER - } - @XmlAttribute private PropertyType type; - - @XmlElement private Border border; - @XmlElement private Dimension dimension; - @XmlElement private Insets insets; - @XmlElement private Matte matte; - @XmlElement private Typeface typeface; - - @XmlAttribute - @Override public void setValue(String value) { - super.setValue(value); - } - - public String write(String prefix) { - switch (type) { - case BOOLEAN: - return String.format(" d.put(\"%s%s\", Boolean.%s);\n", - prefix, getName(), getValue().toUpperCase()); ///autobox - case STRING: - return String.format(" d.put(\"%s%s\", \"%s\");\n", - prefix, getName(), getValue()); - case INT: - return String.format(" d.put(\"%s%s\", new Integer(%s));\n", - prefix, getName(), getValue()); - case FLOAT: - return String.format(" d.put(\"%s%s\", new Float(%sf));\n", - prefix, getName(), getValue()); - case DOUBLE: - return String.format(" d.put(\"%s%s\", new Double(%s));\n", - prefix, getName(), getValue()); - case COLOR: - return String.format(" addColor(d, \"%s%s\", %s);\n", - prefix, getName(), matte.write()); - case FONT: - return String.format(" d.put(\"%s%s\", %s);\n", - prefix, getName(), typeface.write()); - case INSETS: - return String.format(" d.put(\"%s%s\", %s);\n", - prefix, getName(), insets.write(true)); - case DIMENSION: - return String.format(" d.put(\"%s%s\", new DimensionUIResource(%d, %d));\n", - prefix, getName(), dimension.width, dimension.height); - case BORDER: - return String.format(" d.put(\"%s%s\", new BorderUIResource(%s));\n", - prefix, getName(), border.write()); - default: - return "### Look, something's wrong with UIProperty.write() $$$"; - } - } -} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/UIFont.java b/jdk/make/tools/src/build/tools/generatenimbus/UIFont.java new file mode 100644 index 00000000000..13b37336f17 --- /dev/null +++ b/jdk/make/tools/src/build/tools/generatenimbus/UIFont.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.generatenimbus; + +import javax.xml.bind.annotation.XmlElement; + +class UIFont extends UIDefault { + @XmlElement + public void setTypeface(Typeface t) { + setValue(t); + } + + public String write() { + return String.format(" d.put(\"%s\", %s);\n", + getName(), getValue().write()); + } +} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/UIIconRegion.java b/jdk/make/tools/src/build/tools/generatenimbus/UIIconRegion.java new file mode 100644 index 00000000000..ef8f8b654bc --- /dev/null +++ b/jdk/make/tools/src/build/tools/generatenimbus/UIIconRegion.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.generatenimbus; + +import javax.xml.bind.annotation.XmlAttribute; + +class UIIconRegion extends UIRegion { + @XmlAttribute private String basicKey; + + @Override public void write(StringBuilder sb, StringBuilder styleBuffer, UIComponent comp, String prefix, String pkg) { + Dimension size = null; + String fileNamePrefix = Utils.normalize(prefix) + "Painter"; + // write states ui defaults + for (UIState state : backgroundStates) { + Canvas canvas = state.getCanvas(); + if (!canvas.isBlank()) { + state.write(sb, prefix, pkg, fileNamePrefix, getKey()); + size = canvas.getSize(); + } + } + + if (size != null) { + // Put SynthIconImpl wrapper in UiDefaults + String k = (basicKey == null ? prefix + "." + getKey() : basicKey); + sb.append(String.format( + " d.put(\"%s\", new NimbusIcon(\"%s\", \"%sPainter\", %d, %d));\n", + k, prefix, getKey(), size.width, size.height)); + } + } +} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/UIProperty.java b/jdk/make/tools/src/build/tools/generatenimbus/UIProperty.java new file mode 100644 index 00000000000..c0a33ceca60 --- /dev/null +++ b/jdk/make/tools/src/build/tools/generatenimbus/UIProperty.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.generatenimbus; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; + +class UIProperty extends UIDefault { + public static enum PropertyType { + BOOLEAN, INT, FLOAT, DOUBLE, STRING, FONT, COLOR, INSETS, DIMENSION, BORDER + } + @XmlAttribute private PropertyType type; + + @XmlElement private Border border; + @XmlElement private Dimension dimension; + @XmlElement private Insets insets; + @XmlElement private Matte matte; + @XmlElement private Typeface typeface; + + @XmlAttribute + @Override public void setValue(String value) { + super.setValue(value); + } + + public String write(String prefix) { + switch (type) { + case BOOLEAN: + return String.format(" d.put(\"%s%s\", Boolean.%s);\n", + prefix, getName(), getValue().toUpperCase()); ///autobox + case STRING: + return String.format(" d.put(\"%s%s\", \"%s\");\n", + prefix, getName(), getValue()); + case INT: + return String.format(" d.put(\"%s%s\", new Integer(%s));\n", + prefix, getName(), getValue()); + case FLOAT: + return String.format(" d.put(\"%s%s\", new Float(%sf));\n", + prefix, getName(), getValue()); + case DOUBLE: + return String.format(" d.put(\"%s%s\", new Double(%s));\n", + prefix, getName(), getValue()); + case COLOR: + return String.format(" addColor(d, \"%s%s\", %s);\n", + prefix, getName(), matte.write()); + case FONT: + return String.format(" d.put(\"%s%s\", %s);\n", + prefix, getName(), typeface.write()); + case INSETS: + return String.format(" d.put(\"%s%s\", %s);\n", + prefix, getName(), insets.write(true)); + case DIMENSION: + return String.format(" d.put(\"%s%s\", new DimensionUIResource(%d, %d));\n", + prefix, getName(), dimension.width, dimension.height); + case BORDER: + return String.format(" d.put(\"%s%s\", new BorderUIResource(%s));\n", + prefix, getName(), border.write()); + default: + return "### Look, something's wrong with UIProperty.write() $$$"; + } + } +} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/UIRegion.java b/jdk/make/tools/src/build/tools/generatenimbus/UIRegion.java new file mode 100644 index 00000000000..250b0fee25d --- /dev/null +++ b/jdk/make/tools/src/build/tools/generatenimbus/UIRegion.java @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.generatenimbus; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlElements; + +class UIRegion { + @XmlAttribute protected String name; + @XmlAttribute protected String key; + @XmlAttribute private boolean opaque = false; + + @XmlElement private Insets contentMargins = new Insets(0, 0, 0, 0); + + @XmlElement(name="state") + @XmlElementWrapper(name="backgroundStates") + protected List backgroundStates = new ArrayList(); + public List getBackgroundStates() { return backgroundStates; } + + @XmlElement(name="state") + @XmlElementWrapper(name="foregroundStates") + protected List foregroundStates = new ArrayList(); + public List getForegroundStates() { return foregroundStates; } + + @XmlElement(name="state") + @XmlElementWrapper(name="borderStates") + protected List borderStates = new ArrayList(); + public List getBorderStates() { return borderStates; } + + @XmlElement private UIStyle style = new UIStyle(); + + @XmlElements({ + @XmlElement(name = "region", type = UIRegion.class), + @XmlElement(name = "uiComponent", type = UIComponent.class), + @XmlElement(name = "uiIconRegion", type = UIIconRegion.class) + }) + @XmlElementWrapper(name="regions") + private List subRegions = new ArrayList(); + public List getSubRegions() { return subRegions; } + + protected void initStyles(UIStyle parentStyle) { + style.setParentStyle(parentStyle); + for (UIState state: backgroundStates) { + state.getStyle().setParentStyle(this.style); + } + for (UIState state: foregroundStates) { + state.getStyle().setParentStyle(this.style); + } + for (UIState state: borderStates) { + state.getStyle().setParentStyle(this.style); + } + for (UIRegion region: subRegions) { + region.initStyles(this.style); + } + } + + public String getKey() { + return key == null || "".equals(key) ? name : key; + } + + private boolean hasCanvas() { + for (UIState s : backgroundStates) { + if (s.hasCanvas()) return true; + } + for (UIState s : borderStates) { + if (s.hasCanvas()) return true; + } + for (UIState s : foregroundStates) { + if (s.hasCanvas()) return true; + } + for (UIRegion r: subRegions) { + if (r.hasCanvas()) return true; + } + return false; + } + + public void write(StringBuilder sb, StringBuilder styleBuffer, + UIComponent comp, String prefix, String pkg) { + // write content margins + sb.append(String.format(" d.put(\"%s.contentMargins\", %s);\n", + prefix, contentMargins.write(true))); + // write opaque if true + if (opaque) { + sb.append(String.format(" d.put(\"%s.opaque\", Boolean.TRUE);\n", prefix)); + } + + // register component with LAF + String regionCode = "Region." + Utils.regionNameToCaps(name); + styleBuffer.append(String.format(" register(%s, \"%s\");\n", + regionCode, prefix)); + + //write the State, if necessary + StringBuffer regString = new StringBuffer(); + List types = comp.getStateTypes(); + if (types != null && types.size() > 0) { + for (UIStateType type : types) { + regString.append(type.getKey()); + regString.append(","); + } + //remove the last "," + regString.deleteCharAt(regString.length() - 1); + } + + if (! regString.equals("Enabled,MouseOver,Pressed,Disabled,Focused,Selected,Default") && types.size() > 0) { + //there were either custom states, or the normal states were in a custom order + //so go ahead and write out prefix.State + sb.append(String.format(" d.put(\"%s.States\", \"%s\");\n", + prefix, regString)); + } + + // write out any custom states, if necessary + for (UIStateType type : types) { + String synthState = type.getKey(); + if (! "Enabled".equals(synthState) && + ! "MouseOver".equals(synthState) && + ! "Pressed".equals(synthState) && + ! "Disabled".equals(synthState) && + ! "Focused".equals(synthState) && + ! "Selected".equals(synthState) && + ! "Default".equals(synthState)) { + + //what we have here, gentlemen, is a bona-fide custom state. + //if the type is not one of the standard types, then construct a name for + //the new type, and write out a new subclass of State. + String className = Utils.normalize(prefix) + synthState + "State"; + sb.append(String.format(" d.put(\"%s.%s\", new %s());\n", + prefix, synthState, className)); + + String body = type.getCodeSnippet(); + Map variables = Generator.getVariables(); + variables.put("STATE_NAME", className); + variables.put("STATE_KEY", synthState); + variables.put("BODY", body); + + Generator.writeSrcFile("StateImpl", variables, className); + } + } + + // write style + sb.append(style.write(prefix + '.')); + + String fileName = Utils.normalize(prefix) + "Painter"; + boolean hasCanvas = hasCanvas(); + if (hasCanvas) { + PainterGenerator.writePainter(this, fileName); + } + // write states ui defaults + for (UIState state : backgroundStates) { + state.write(sb, prefix, pkg, fileName, "background"); + } + for (UIState state : foregroundStates) { + state.write(sb, prefix, pkg, fileName, "foreground"); + } + for (UIState state : borderStates) { + state.write(sb, prefix, pkg, fileName, "border"); + } + + // handle sub regions + for (UIRegion subreg : subRegions) { + String p = prefix; + if (! (subreg instanceof UIIconRegion)) { + p = prefix + ":" + Utils.escape(subreg.getKey()); + } + UIComponent c = comp; + if (subreg instanceof UIComponent) { + c = (UIComponent) subreg; + } + subreg.write(sb, styleBuffer, c, p, pkg); + } + } +} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/UIState.java b/jdk/make/tools/src/build/tools/generatenimbus/UIState.java new file mode 100644 index 00000000000..ff9800afe0e --- /dev/null +++ b/jdk/make/tools/src/build/tools/generatenimbus/UIState.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.generatenimbus; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; + +class UIState { + @XmlAttribute private String stateKeys; + public String getStateKeys() { return stateKeys; } + + /** Indicates whether to invert the meaning of the 9-square stretching insets */ + @XmlAttribute private boolean inverted; + + /** A cached string representing the list of stateKeys deliminated with "+" */ + private String cachedName = null; + + @XmlElement private Canvas canvas; + public Canvas getCanvas() { return canvas; } + + @XmlElement private UIStyle style; + public UIStyle getStyle() { return style; } + + public boolean hasCanvas() { + return ! canvas.isBlank(); + } + + public static List stringToKeys(String keysString) { + return Arrays.asList(keysString.split("\\+")); + } + + public String getName() { + if (cachedName == null) { + StringBuilder buf = new StringBuilder(); + List keys = stringToKeys(stateKeys); + Collections.sort(keys); + for (Iterator iter = keys.iterator(); iter.hasNext();) { + buf.append(iter.next()); + if (iter.hasNext()) { + buf.append('+'); + } + } + cachedName = buf.toString(); + } + return cachedName; + } + + public void write(StringBuilder sb, String prefix, String pkg, String fileNamePrefix, String painterPrefix) { + String statePrefix = prefix + "[" + getName() + "]"; + // write state style + sb.append(style.write(statePrefix + '.')); + // write painter + if (hasCanvas()) { + writeLazyPainter(sb, statePrefix, pkg, fileNamePrefix, painterPrefix); + } + } + + private void writeLazyPainter(StringBuilder sb, String statePrefix, String packageNamePrefix, String fileNamePrefix, String painterPrefix) { + String cacheModeString = "AbstractRegionPainter.PaintContext.CacheMode." + style.getCacheMode(); + String stateConstant = Utils.statesToConstantName(painterPrefix + "_" + stateKeys); + sb.append(String.format( + " d.put(\"%s.%sPainter\", new LazyPainter(\"%s.%s\", %s.%s, %s, %s, %b, %s, %s, %s));\n", + statePrefix, painterPrefix, packageNamePrefix, fileNamePrefix, + fileNamePrefix, stateConstant, canvas.getStretchingInsets().write(false), + canvas.getSize().write(false), inverted, cacheModeString, + Utils.formatDouble(style.getMaxHozCachedImgScaling()), + Utils.formatDouble(style.getMaxVertCachedImgScaling()))); + } +} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/UIStateType.java b/jdk/make/tools/src/build/tools/generatenimbus/UIStateType.java new file mode 100644 index 00000000000..b569dd9faed --- /dev/null +++ b/jdk/make/tools/src/build/tools/generatenimbus/UIStateType.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.generatenimbus; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; + +class UIStateType { + @XmlAttribute private String key; + public String getKey() { return key; } + + @XmlElement private String codeSnippet; + public String getCodeSnippet() { return codeSnippet; } +} diff --git a/jdk/make/tools/src/build/tools/generatenimbus/UIStyle.java b/jdk/make/tools/src/build/tools/generatenimbus/UIStyle.java index 4b81e892d37..72f6f786622 100644 --- a/jdk/make/tools/src/build/tools/generatenimbus/UIStyle.java +++ b/jdk/make/tools/src/build/tools/generatenimbus/UIStyle.java @@ -26,15 +26,9 @@ package build.tools.generatenimbus; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; import java.util.List; -import java.util.Map; -import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElementWrapper; -import javax.xml.bind.annotation.XmlElements; class UIStyle { @@ -115,285 +109,3 @@ class UIStyle { return sb.toString(); } } - -class UIRegion { - @XmlAttribute protected String name; - @XmlAttribute protected String key; - @XmlAttribute private boolean opaque = false; - - @XmlElement private Insets contentMargins = new Insets(0, 0, 0, 0); - - @XmlElement(name="state") - @XmlElementWrapper(name="backgroundStates") - protected List backgroundStates = new ArrayList(); - public List getBackgroundStates() { return backgroundStates; } - - @XmlElement(name="state") - @XmlElementWrapper(name="foregroundStates") - protected List foregroundStates = new ArrayList(); - public List getForegroundStates() { return foregroundStates; } - - @XmlElement(name="state") - @XmlElementWrapper(name="borderStates") - protected List borderStates = new ArrayList(); - public List getBorderStates() { return borderStates; } - - @XmlElement private UIStyle style = new UIStyle(); - - @XmlElements({ - @XmlElement(name = "region", type = UIRegion.class), - @XmlElement(name = "uiComponent", type = UIComponent.class), - @XmlElement(name = "uiIconRegion", type = UIIconRegion.class) - }) - @XmlElementWrapper(name="regions") - private List subRegions = new ArrayList(); - public List getSubRegions() { return subRegions; } - - protected void initStyles(UIStyle parentStyle) { - style.setParentStyle(parentStyle); - for (UIState state: backgroundStates) { - state.getStyle().setParentStyle(this.style); - } - for (UIState state: foregroundStates) { - state.getStyle().setParentStyle(this.style); - } - for (UIState state: borderStates) { - state.getStyle().setParentStyle(this.style); - } - for (UIRegion region: subRegions) { - region.initStyles(this.style); - } - } - - public String getKey() { - return key == null || "".equals(key) ? name : key; - } - - private boolean hasCanvas() { - for (UIState s : backgroundStates) { - if (s.hasCanvas()) return true; - } - for (UIState s : borderStates) { - if (s.hasCanvas()) return true; - } - for (UIState s : foregroundStates) { - if (s.hasCanvas()) return true; - } - for (UIRegion r: subRegions) { - if (r.hasCanvas()) return true; - } - return false; - } - - public void write(StringBuilder sb, StringBuilder styleBuffer, - UIComponent comp, String prefix, String pkg) { - // write content margins - sb.append(String.format(" d.put(\"%s.contentMargins\", %s);\n", - prefix, contentMargins.write(true))); - // write opaque if true - if (opaque) { - sb.append(String.format(" d.put(\"%s.opaque\", Boolean.TRUE);\n", prefix)); - } - - // register component with LAF - String regionCode = "Region." + Utils.regionNameToCaps(name); - styleBuffer.append(String.format(" register(%s, \"%s\");\n", - regionCode, prefix)); - - //write the State, if necessary - StringBuffer regString = new StringBuffer(); - List types = comp.getStateTypes(); - if (types != null && types.size() > 0) { - for (UIStateType type : types) { - regString.append(type.getKey()); - regString.append(","); - } - //remove the last "," - regString.deleteCharAt(regString.length() - 1); - } - - if (! regString.equals("Enabled,MouseOver,Pressed,Disabled,Focused,Selected,Default") && types.size() > 0) { - //there were either custom states, or the normal states were in a custom order - //so go ahead and write out prefix.State - sb.append(String.format(" d.put(\"%s.States\", \"%s\");\n", - prefix, regString)); - } - - // write out any custom states, if necessary - for (UIStateType type : types) { - String synthState = type.getKey(); - if (! "Enabled".equals(synthState) && - ! "MouseOver".equals(synthState) && - ! "Pressed".equals(synthState) && - ! "Disabled".equals(synthState) && - ! "Focused".equals(synthState) && - ! "Selected".equals(synthState) && - ! "Default".equals(synthState)) { - - //what we have here, gentlemen, is a bona-fide custom state. - //if the type is not one of the standard types, then construct a name for - //the new type, and write out a new subclass of State. - String className = Utils.normalize(prefix) + synthState + "State"; - sb.append(String.format(" d.put(\"%s.%s\", new %s());\n", - prefix, synthState, className)); - - String body = type.getCodeSnippet(); - Map variables = Generator.getVariables(); - variables.put("STATE_NAME", className); - variables.put("STATE_KEY", synthState); - variables.put("BODY", body); - - Generator.writeSrcFile("StateImpl", variables, className); - } - } - - // write style - sb.append(style.write(prefix + '.')); - - String fileName = Utils.normalize(prefix) + "Painter"; - boolean hasCanvas = hasCanvas(); - if (hasCanvas) { - PainterGenerator.writePainter(this, fileName); - } - // write states ui defaults - for (UIState state : backgroundStates) { - state.write(sb, prefix, pkg, fileName, "background"); - } - for (UIState state : foregroundStates) { - state.write(sb, prefix, pkg, fileName, "foreground"); - } - for (UIState state : borderStates) { - state.write(sb, prefix, pkg, fileName, "border"); - } - - // handle sub regions - for (UIRegion subreg : subRegions) { - String p = prefix; - if (! (subreg instanceof UIIconRegion)) { - p = prefix + ":" + Utils.escape(subreg.getKey()); - } - UIComponent c = comp; - if (subreg instanceof UIComponent) { - c = (UIComponent) subreg; - } - subreg.write(sb, styleBuffer, c, p, pkg); - } - } -} - -class UIIconRegion extends UIRegion { - @XmlAttribute private String basicKey; - - @Override public void write(StringBuilder sb, StringBuilder styleBuffer, UIComponent comp, String prefix, String pkg) { - Dimension size = null; - String fileNamePrefix = Utils.normalize(prefix) + "Painter"; - // write states ui defaults - for (UIState state : backgroundStates) { - Canvas canvas = state.getCanvas(); - if (!canvas.isBlank()) { - state.write(sb, prefix, pkg, fileNamePrefix, getKey()); - size = canvas.getSize(); - } - } - - if (size != null) { - // Put SynthIconImpl wrapper in UiDefaults - String k = (basicKey == null ? prefix + "." + getKey() : basicKey); - sb.append(String.format( - " d.put(\"%s\", new NimbusIcon(\"%s\", \"%sPainter\", %d, %d));\n", - k, prefix, getKey(), size.width, size.height)); - } - } -} - -class UIComponent extends UIRegion { - @XmlAttribute private String componentName; - - @XmlElement(name="stateType") - @XmlElementWrapper(name="stateTypes") - private List stateTypes = new ArrayList(); - public List getStateTypes() { return stateTypes; } - - @Override public String getKey() { - if (key == null || "".equals(key)) { - if (componentName == null || "".equals(componentName)) { - return name; - } else { - return "\"" + componentName + "\""; - } - } else { - return key; - } - } -} - -class UIState { - @XmlAttribute private String stateKeys; - public String getStateKeys() { return stateKeys; } - - /** Indicates whether to invert the meaning of the 9-square stretching insets */ - @XmlAttribute private boolean inverted; - - /** A cached string representing the list of stateKeys deliminated with "+" */ - private String cachedName = null; - - @XmlElement private Canvas canvas; - public Canvas getCanvas() { return canvas; } - - @XmlElement private UIStyle style; - public UIStyle getStyle() { return style; } - - public boolean hasCanvas() { - return ! canvas.isBlank(); - } - - public static List stringToKeys(String keysString) { - return Arrays.asList(keysString.split("\\+")); - } - - public String getName() { - if (cachedName == null) { - StringBuilder buf = new StringBuilder(); - List keys = stringToKeys(stateKeys); - Collections.sort(keys); - for (Iterator iter = keys.iterator(); iter.hasNext();) { - buf.append(iter.next()); - if (iter.hasNext()) { - buf.append('+'); - } - } - cachedName = buf.toString(); - } - return cachedName; - } - - public void write(StringBuilder sb, String prefix, String pkg, String fileNamePrefix, String painterPrefix) { - String statePrefix = prefix + "[" + getName() + "]"; - // write state style - sb.append(style.write(statePrefix + '.')); - // write painter - if (hasCanvas()) { - writeLazyPainter(sb, statePrefix, pkg, fileNamePrefix, painterPrefix); - } - } - - private void writeLazyPainter(StringBuilder sb, String statePrefix, String packageNamePrefix, String fileNamePrefix, String painterPrefix) { - String cacheModeString = "AbstractRegionPainter.PaintContext.CacheMode." + style.getCacheMode(); - String stateConstant = Utils.statesToConstantName(painterPrefix + "_" + stateKeys); - sb.append(String.format( - " d.put(\"%s.%sPainter\", new LazyPainter(\"%s.%s\", %s.%s, %s, %s, %b, %s, %s, %s));\n", - statePrefix, painterPrefix, packageNamePrefix, fileNamePrefix, - fileNamePrefix, stateConstant, canvas.getStretchingInsets().write(false), - canvas.getSize().write(false), inverted, cacheModeString, - Utils.formatDouble(style.getMaxHozCachedImgScaling()), - Utils.formatDouble(style.getMaxVertCachedImgScaling()))); - } -} - -class UIStateType { - @XmlAttribute private String key; - public String getKey() { return key; } - - @XmlElement private String codeSnippet; - public String getCodeSnippet() { return codeSnippet; } -} diff --git a/jdk/src/share/classes/javax/management/timer/Timer.java b/jdk/src/share/classes/javax/management/timer/Timer.java index aafd0ab35eb..b13153ec674 100644 --- a/jdk/src/share/classes/javax/management/timer/Timer.java +++ b/jdk/src/share/classes/javax/management/timer/Timer.java @@ -1240,54 +1240,3 @@ public class Timer extends NotificationBroadcasterSupport "sendNotification", "timer notification sent"); } } - -/** - * TimerAlarmClock inner class: - * This class provides a simple implementation of an alarm clock MBean. - * The aim of this MBean is to set up an alarm which wakes up the timer every timeout (fixed-delay) - * or at the specified date (fixed-rate). - */ - -class TimerAlarmClock extends java.util.TimerTask { - - Timer listener = null; - long timeout = 10000; - Date next = null; - - /* - * ------------------------------------------ - * CONSTRUCTORS - * ------------------------------------------ - */ - - public TimerAlarmClock(Timer listener, long timeout) { - this.listener = listener; - this.timeout = Math.max(0L, timeout); - } - - public TimerAlarmClock(Timer listener, Date next) { - this.listener = listener; - this.next = next; - } - - /* - * ------------------------------------------ - * PUBLIC METHODS - * ------------------------------------------ - */ - - /** - * This method is called by the timer when it is started. - */ - public void run() { - - try { - //this.sleep(timeout); - TimerAlarmClockNotification notif = new TimerAlarmClockNotification(this); - listener.notifyAlarmClock(notif); - } catch (Exception e) { - TIMER_LOGGER.logp(Level.FINEST, Timer.class.getName(), "run", - "Got unexpected exception when sending a notification", e); - } - } -} diff --git a/jdk/src/share/classes/javax/management/timer/TimerAlarmClock.java b/jdk/src/share/classes/javax/management/timer/TimerAlarmClock.java new file mode 100644 index 00000000000..154ff440775 --- /dev/null +++ b/jdk/src/share/classes/javax/management/timer/TimerAlarmClock.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 javax.management.timer; + +import java.util.Date; +import java.util.logging.Level; +import static com.sun.jmx.defaults.JmxProperties.TIMER_LOGGER; + +/** + * This class provides a simple implementation of an alarm clock MBean. + * The aim of this MBean is to set up an alarm which wakes up the timer every timeout (fixed-delay) + * or at the specified date (fixed-rate). + */ + +class TimerAlarmClock extends java.util.TimerTask { + + Timer listener = null; + long timeout = 10000; + Date next = null; + + /* + * ------------------------------------------ + * CONSTRUCTORS + * ------------------------------------------ + */ + + public TimerAlarmClock(Timer listener, long timeout) { + this.listener = listener; + this.timeout = Math.max(0L, timeout); + } + + public TimerAlarmClock(Timer listener, Date next) { + this.listener = listener; + this.next = next; + } + + /* + * ------------------------------------------ + * PUBLIC METHODS + * ------------------------------------------ + */ + + /** + * This method is called by the timer when it is started. + */ + public void run() { + + try { + //this.sleep(timeout); + TimerAlarmClockNotification notif = new TimerAlarmClockNotification(this); + listener.notifyAlarmClock(notif); + } catch (Exception e) { + TIMER_LOGGER.logp(Level.FINEST, Timer.class.getName(), "run", + "Got unexpected exception when sending a notification", e); + } + } +} diff --git a/jdk/src/share/classes/sun/awt/im/ExecutableInputMethodManager.java b/jdk/src/share/classes/sun/awt/im/ExecutableInputMethodManager.java new file mode 100644 index 00000000000..853d9d46055 --- /dev/null +++ b/jdk/src/share/classes/sun/awt/im/ExecutableInputMethodManager.java @@ -0,0 +1,632 @@ +/* + * Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.awt.im; + +import java.awt.AWTException; +import java.awt.CheckboxMenuItem; +import java.awt.Component; +import java.awt.Dialog; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.PopupMenu; +import java.awt.Menu; +import java.awt.MenuItem; +import java.awt.Toolkit; +import sun.awt.AppContext; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InvocationEvent; +import java.awt.im.spi.InputMethodDescriptor; +import java.lang.reflect.InvocationTargetException; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Locale; +import java.util.ServiceLoader; +import java.util.Vector; +import java.util.Set; +import java.util.prefs.BackingStoreException; +import java.util.prefs.Preferences; +import sun.awt.InputMethodSupport; +import sun.awt.SunToolkit; + +/** + * ExecutableInputMethodManager is the implementation of the + * InputMethodManager class. It is runnable as a separate + * thread in the AWT environment.  + * InputMethodManager.getInstance() creates an instance of + * ExecutableInputMethodManager and executes it as a deamon + * thread. + * + * @see InputMethodManager + */ +class ExecutableInputMethodManager extends InputMethodManager + implements Runnable +{ + // the input context that's informed about selections from the user interface + private InputContext currentInputContext; + + // Menu item string for the trigger menu. + private String triggerMenuString; + + // popup menu for selecting an input method + private InputMethodPopupMenu selectionMenu; + private static String selectInputMethodMenuTitle; + + // locator and name of host adapter + private InputMethodLocator hostAdapterLocator; + + // locators for Java input methods + private int javaInputMethodCount; // number of Java input methods found + private Vector javaInputMethodLocatorList; + + // component that is requesting input method switch + // must be Frame or Dialog + private Component requestComponent; + + // input context that is requesting input method switch + private InputContext requestInputContext; + + // IM preference stuff + private static final String preferredIMNode = "/sun/awt/im/preferredInputMethod"; + private static final String descriptorKey = "descriptor"; + private Hashtable preferredLocatorCache = new Hashtable<>(); + private Preferences userRoot; + + ExecutableInputMethodManager() { + + // set up host adapter locator + Toolkit toolkit = Toolkit.getDefaultToolkit(); + try { + if (toolkit instanceof InputMethodSupport) { + InputMethodDescriptor hostAdapterDescriptor = + ((InputMethodSupport)toolkit) + .getInputMethodAdapterDescriptor(); + if (hostAdapterDescriptor != null) { + hostAdapterLocator = new InputMethodLocator(hostAdapterDescriptor, null, null); + } + } + } catch (AWTException e) { + // if we can't get a descriptor, we'll just have to do without native input methods + } + + javaInputMethodLocatorList = new Vector(); + initializeInputMethodLocatorList(); + } + + synchronized void initialize() { + selectInputMethodMenuTitle = Toolkit.getProperty("AWT.InputMethodSelectionMenu", "Select Input Method"); + + triggerMenuString = selectInputMethodMenuTitle; + } + + public void run() { + // If there are no multiple input methods to choose from, wait forever + while (!hasMultipleInputMethods()) { + try { + synchronized (this) { + wait(); + } + } catch (InterruptedException e) { + } + } + + // Loop for processing input method change requests + while (true) { + waitForChangeRequest(); + initializeInputMethodLocatorList(); + try { + if (requestComponent != null) { + showInputMethodMenuOnRequesterEDT(requestComponent); + } else { + // show the popup menu within the event thread + EventQueue.invokeAndWait(new Runnable() { + public void run() { + showInputMethodMenu(); + } + }); + } + } catch (InterruptedException ie) { + } catch (InvocationTargetException ite) { + // should we do anything under these exceptions? + } + } + } + + // Shows Input Method Menu on the EDT of requester component + // to avoid side effects. See 6544309. + private void showInputMethodMenuOnRequesterEDT(Component requester) + throws InterruptedException, InvocationTargetException { + + if (requester == null){ + return; + } + + class AWTInvocationLock {} + Object lock = new AWTInvocationLock(); + + InvocationEvent event = + new InvocationEvent(requester, + new Runnable() { + public void run() { + showInputMethodMenu(); + } + }, + lock, + true); + + AppContext requesterAppContext = SunToolkit.targetToAppContext(requester); + synchronized (lock) { + SunToolkit.postEvent(requesterAppContext, event); + while (!event.isDispatched()) { + lock.wait(); + } + } + + Throwable eventThrowable = event.getThrowable(); + if (eventThrowable != null) { + throw new InvocationTargetException(eventThrowable); + } + } + + void setInputContext(InputContext inputContext) { + if (currentInputContext != null && inputContext != null) { + // don't throw this exception until 4237852 is fixed + // throw new IllegalStateException("Can't have two active InputContext at the same time"); + } + currentInputContext = inputContext; + } + + public synchronized void notifyChangeRequest(Component comp) { + if (!(comp instanceof Frame || comp instanceof Dialog)) + return; + + // if busy with the current request, ignore this request. + if (requestComponent != null) + return; + + requestComponent = comp; + notify(); + } + + public synchronized void notifyChangeRequestByHotKey(Component comp) { + while (!(comp instanceof Frame || comp instanceof Dialog)) { + if (comp == null) { + // no Frame or Dialog found in containment hierarchy. + return; + } + comp = comp.getParent(); + } + + notifyChangeRequest(comp); + } + + public String getTriggerMenuString() { + return triggerMenuString; + } + + /* + * Returns true if the environment indicates there are multiple input methods + */ + boolean hasMultipleInputMethods() { + return ((hostAdapterLocator != null) && (javaInputMethodCount > 0) + || (javaInputMethodCount > 1)); + } + + private synchronized void waitForChangeRequest() { + try { + while (requestComponent == null) { + wait(); + } + } catch (InterruptedException e) { + } + } + + /* + * initializes the input method locator list for all + * installed input method descriptors. + */ + private void initializeInputMethodLocatorList() { + synchronized (javaInputMethodLocatorList) { + javaInputMethodLocatorList.clear(); + try { + AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Object run() { + for (InputMethodDescriptor descriptor : + ServiceLoader.loadInstalled(InputMethodDescriptor.class)) { + ClassLoader cl = descriptor.getClass().getClassLoader(); + javaInputMethodLocatorList.add(new InputMethodLocator(descriptor, cl, null)); + } + return null; + } + }); + } catch (PrivilegedActionException e) { + e.printStackTrace(); + } + javaInputMethodCount = javaInputMethodLocatorList.size(); + } + + if (hasMultipleInputMethods()) { + // initialize preferences + if (userRoot == null) { + userRoot = getUserRoot(); + } + } else { + // indicate to clients not to offer the menu + triggerMenuString = null; + } + } + + private void showInputMethodMenu() { + + if (!hasMultipleInputMethods()) { + requestComponent = null; + return; + } + + // initialize pop-up menu + selectionMenu = InputMethodPopupMenu.getInstance(requestComponent, selectInputMethodMenuTitle); + + // we have to rebuild the menu each time because + // some input methods (such as IIIMP) may change + // their list of supported locales dynamically + selectionMenu.removeAll(); + + // get information about the currently selected input method + // ??? if there's no current input context, what's the point + // of showing the menu? + String currentSelection = getCurrentSelection(); + + // Add menu item for host adapter + if (hostAdapterLocator != null) { + selectionMenu.addOneInputMethodToMenu(hostAdapterLocator, currentSelection); + selectionMenu.addSeparator(); + } + + // Add menu items for other input methods + for (int i = 0; i < javaInputMethodLocatorList.size(); i++) { + InputMethodLocator locator = javaInputMethodLocatorList.get(i); + selectionMenu.addOneInputMethodToMenu(locator, currentSelection); + } + + synchronized (this) { + selectionMenu.addToComponent(requestComponent); + requestInputContext = currentInputContext; + selectionMenu.show(requestComponent, 60, 80); // TODO: get proper x, y... + requestComponent = null; + } + } + + private String getCurrentSelection() { + InputContext inputContext = currentInputContext; + if (inputContext != null) { + InputMethodLocator locator = inputContext.getInputMethodLocator(); + if (locator != null) { + return locator.getActionCommandString(); + } + } + return null; + } + + synchronized void changeInputMethod(String choice) { + InputMethodLocator locator = null; + + String inputMethodName = choice; + String localeString = null; + int index = choice.indexOf('\n'); + if (index != -1) { + localeString = choice.substring(index + 1); + inputMethodName = choice.substring(0, index); + } + if (hostAdapterLocator.getActionCommandString().equals(inputMethodName)) { + locator = hostAdapterLocator; + } else { + for (int i = 0; i < javaInputMethodLocatorList.size(); i++) { + InputMethodLocator candidate = javaInputMethodLocatorList.get(i); + String name = candidate.getActionCommandString(); + if (name.equals(inputMethodName)) { + locator = candidate; + break; + } + } + } + + if (locator != null && localeString != null) { + String language = "", country = "", variant = ""; + int postIndex = localeString.indexOf('_'); + if (postIndex == -1) { + language = localeString; + } else { + language = localeString.substring(0, postIndex); + int preIndex = postIndex + 1; + postIndex = localeString.indexOf('_', preIndex); + if (postIndex == -1) { + country = localeString.substring(preIndex); + } else { + country = localeString.substring(preIndex, postIndex); + variant = localeString.substring(postIndex + 1); + } + } + Locale locale = new Locale(language, country, variant); + locator = locator.deriveLocator(locale); + } + + if (locator == null) + return; + + // tell the input context about the change + if (requestInputContext != null) { + requestInputContext.changeInputMethod(locator); + requestInputContext = null; + + // remember the selection + putPreferredInputMethod(locator); + } + } + + InputMethodLocator findInputMethod(Locale locale) { + // look for preferred input method first + InputMethodLocator locator = getPreferredInputMethod(locale); + if (locator != null) { + return locator; + } + + if (hostAdapterLocator != null && hostAdapterLocator.isLocaleAvailable(locale)) { + return hostAdapterLocator.deriveLocator(locale); + } + + // Update the locator list + initializeInputMethodLocatorList(); + + for (int i = 0; i < javaInputMethodLocatorList.size(); i++) { + InputMethodLocator candidate = javaInputMethodLocatorList.get(i); + if (candidate.isLocaleAvailable(locale)) { + return candidate.deriveLocator(locale); + } + } + return null; + } + + Locale getDefaultKeyboardLocale() { + Toolkit toolkit = Toolkit.getDefaultToolkit(); + if (toolkit instanceof InputMethodSupport) { + return ((InputMethodSupport)toolkit).getDefaultKeyboardLocale(); + } else { + return Locale.getDefault(); + } + } + + /** + * Returns a InputMethodLocator object that the + * user prefers for the given locale. + * + * @param locale Locale for which the user prefers the input method. + */ + private synchronized InputMethodLocator getPreferredInputMethod(Locale locale) { + InputMethodLocator preferredLocator = null; + + if (!hasMultipleInputMethods()) { + // No need to look for a preferred Java input method + return null; + } + + // look for the cached preference first. + preferredLocator = preferredLocatorCache.get(locale.toString().intern()); + if (preferredLocator != null) { + return preferredLocator; + } + + // look for the preference in the user preference tree + String nodePath = findPreferredInputMethodNode(locale); + String descriptorName = readPreferredInputMethod(nodePath); + Locale advertised; + + // get the locator object + if (descriptorName != null) { + // check for the host adapter first + if (hostAdapterLocator != null && + hostAdapterLocator.getDescriptor().getClass().getName().equals(descriptorName)) { + advertised = getAdvertisedLocale(hostAdapterLocator, locale); + if (advertised != null) { + preferredLocator = hostAdapterLocator.deriveLocator(advertised); + preferredLocatorCache.put(locale.toString().intern(), preferredLocator); + } + return preferredLocator; + } + // look for Java input methods + for (int i = 0; i < javaInputMethodLocatorList.size(); i++) { + InputMethodLocator locator = javaInputMethodLocatorList.get(i); + InputMethodDescriptor descriptor = locator.getDescriptor(); + if (descriptor.getClass().getName().equals(descriptorName)) { + advertised = getAdvertisedLocale(locator, locale); + if (advertised != null) { + preferredLocator = locator.deriveLocator(advertised); + preferredLocatorCache.put(locale.toString().intern(), preferredLocator); + } + return preferredLocator; + } + } + + // maybe preferred input method information is bogus. + writePreferredInputMethod(nodePath, null); + } + + return null; + } + + private String findPreferredInputMethodNode(Locale locale) { + if (userRoot == null) { + return null; + } + + // create locale node relative path + String nodePath = preferredIMNode + "/" + createLocalePath(locale); + + // look for the descriptor + while (!nodePath.equals(preferredIMNode)) { + try { + if (userRoot.nodeExists(nodePath)) { + if (readPreferredInputMethod(nodePath) != null) { + return nodePath; + } + } + } catch (BackingStoreException bse) { + } + + // search at parent's node + nodePath = nodePath.substring(0, nodePath.lastIndexOf('/')); + } + + return null; + } + + private String readPreferredInputMethod(String nodePath) { + if ((userRoot == null) || (nodePath == null)) { + return null; + } + + return userRoot.node(nodePath).get(descriptorKey, null); + } + + /** + * Writes the preferred input method descriptor class name into + * the user's Preferences tree in accordance with the given locale. + * + * @param inputMethodLocator input method locator to remember. + */ + private synchronized void putPreferredInputMethod(InputMethodLocator locator) { + InputMethodDescriptor descriptor = locator.getDescriptor(); + Locale preferredLocale = locator.getLocale(); + + if (preferredLocale == null) { + // check available locales of the input method + try { + Locale[] availableLocales = descriptor.getAvailableLocales(); + if (availableLocales.length == 1) { + preferredLocale = availableLocales[0]; + } else { + // there is no way to know which locale is the preferred one, so do nothing. + return; + } + } catch (AWTException ae) { + // do nothing here, either. + return; + } + } + + // for regions that have only one language, we need to regard + // "xx_YY" as "xx" when putting the preference into tree + if (preferredLocale.equals(Locale.JAPAN)) { + preferredLocale = Locale.JAPANESE; + } + if (preferredLocale.equals(Locale.KOREA)) { + preferredLocale = Locale.KOREAN; + } + if (preferredLocale.equals(new Locale("th", "TH"))) { + preferredLocale = new Locale("th"); + } + + // obtain node + String path = preferredIMNode + "/" + createLocalePath(preferredLocale); + + // write in the preference tree + writePreferredInputMethod(path, descriptor.getClass().getName()); + preferredLocatorCache.put(preferredLocale.toString().intern(), + locator.deriveLocator(preferredLocale)); + + return; + } + + private String createLocalePath(Locale locale) { + String language = locale.getLanguage(); + String country = locale.getCountry(); + String variant = locale.getVariant(); + String localePath = null; + if (!variant.equals("")) { + localePath = "_" + language + "/_" + country + "/_" + variant; + } else if (!country.equals("")) { + localePath = "_" + language + "/_" + country; + } else { + localePath = "_" + language; + } + + return localePath; + } + + private void writePreferredInputMethod(String path, String descriptorName) { + if (userRoot != null) { + Preferences node = userRoot.node(path); + + // record it + if (descriptorName != null) { + node.put(descriptorKey, descriptorName); + } else { + node.remove(descriptorKey); + } + } + } + + private Preferences getUserRoot() { + return AccessController.doPrivileged(new PrivilegedAction() { + public Preferences run() { + return Preferences.userRoot(); + } + }); + } + + private Locale getAdvertisedLocale(InputMethodLocator locator, Locale locale) { + Locale advertised = null; + + if (locator.isLocaleAvailable(locale)) { + advertised = locale; + } else if (locale.getLanguage().equals("ja")) { + // for Japanese, Korean, and Thai, check whether the input method supports + // language or language_COUNTRY. + if (locator.isLocaleAvailable(Locale.JAPAN)) { + advertised = Locale.JAPAN; + } else if (locator.isLocaleAvailable(Locale.JAPANESE)) { + advertised = Locale.JAPANESE; + } + } else if (locale.getLanguage().equals("ko")) { + if (locator.isLocaleAvailable(Locale.KOREA)) { + advertised = Locale.KOREA; + } else if (locator.isLocaleAvailable(Locale.KOREAN)) { + advertised = Locale.KOREAN; + } + } else if (locale.getLanguage().equals("th")) { + if (locator.isLocaleAvailable(new Locale("th", "TH"))) { + advertised = new Locale("th", "TH"); + } else if (locator.isLocaleAvailable(new Locale("th"))) { + advertised = new Locale("th"); + } + } + + return advertised; + } +} diff --git a/jdk/src/share/classes/sun/awt/im/InputMethodManager.java b/jdk/src/share/classes/sun/awt/im/InputMethodManager.java index 0e15b7e7fce..055970fb77b 100644 --- a/jdk/src/share/classes/sun/awt/im/InputMethodManager.java +++ b/jdk/src/share/classes/sun/awt/im/InputMethodManager.java @@ -229,578 +229,3 @@ public abstract class InputMethodManager { abstract boolean hasMultipleInputMethods(); } - -/** - * ExecutableInputMethodManager is the implementation of the - * InputMethodManager class. It is runnable as a separate - * thread in the AWT environment.  - * InputMethodManager.getInstance() creates an instance of - * ExecutableInputMethodManager and executes it as a deamon - * thread. - * - * @see InputMethodManager - */ -class ExecutableInputMethodManager extends InputMethodManager - implements Runnable -{ - // the input context that's informed about selections from the user interface - private InputContext currentInputContext; - - // Menu item string for the trigger menu. - private String triggerMenuString; - - // popup menu for selecting an input method - private InputMethodPopupMenu selectionMenu; - private static String selectInputMethodMenuTitle; - - // locator and name of host adapter - private InputMethodLocator hostAdapterLocator; - - // locators for Java input methods - private int javaInputMethodCount; // number of Java input methods found - private Vector javaInputMethodLocatorList; - - // component that is requesting input method switch - // must be Frame or Dialog - private Component requestComponent; - - // input context that is requesting input method switch - private InputContext requestInputContext; - - // IM preference stuff - private static final String preferredIMNode = "/sun/awt/im/preferredInputMethod"; - private static final String descriptorKey = "descriptor"; - private Hashtable preferredLocatorCache = new Hashtable<>(); - private Preferences userRoot; - - ExecutableInputMethodManager() { - - // set up host adapter locator - Toolkit toolkit = Toolkit.getDefaultToolkit(); - try { - if (toolkit instanceof InputMethodSupport) { - InputMethodDescriptor hostAdapterDescriptor = - ((InputMethodSupport)toolkit) - .getInputMethodAdapterDescriptor(); - if (hostAdapterDescriptor != null) { - hostAdapterLocator = new InputMethodLocator(hostAdapterDescriptor, null, null); - } - } - } catch (AWTException e) { - // if we can't get a descriptor, we'll just have to do without native input methods - } - - javaInputMethodLocatorList = new Vector(); - initializeInputMethodLocatorList(); - } - - synchronized void initialize() { - selectInputMethodMenuTitle = Toolkit.getProperty("AWT.InputMethodSelectionMenu", "Select Input Method"); - - triggerMenuString = selectInputMethodMenuTitle; - } - - public void run() { - // If there are no multiple input methods to choose from, wait forever - while (!hasMultipleInputMethods()) { - try { - synchronized (this) { - wait(); - } - } catch (InterruptedException e) { - } - } - - // Loop for processing input method change requests - while (true) { - waitForChangeRequest(); - initializeInputMethodLocatorList(); - try { - if (requestComponent != null) { - showInputMethodMenuOnRequesterEDT(requestComponent); - } else { - // show the popup menu within the event thread - EventQueue.invokeAndWait(new Runnable() { - public void run() { - showInputMethodMenu(); - } - }); - } - } catch (InterruptedException ie) { - } catch (InvocationTargetException ite) { - // should we do anything under these exceptions? - } - } - } - - // Shows Input Method Menu on the EDT of requester component - // to avoid side effects. See 6544309. - private void showInputMethodMenuOnRequesterEDT(Component requester) - throws InterruptedException, InvocationTargetException { - - if (requester == null){ - return; - } - - class AWTInvocationLock {} - Object lock = new AWTInvocationLock(); - - InvocationEvent event = - new InvocationEvent(requester, - new Runnable() { - public void run() { - showInputMethodMenu(); - } - }, - lock, - true); - - AppContext requesterAppContext = SunToolkit.targetToAppContext(requester); - synchronized (lock) { - SunToolkit.postEvent(requesterAppContext, event); - while (!event.isDispatched()) { - lock.wait(); - } - } - - Throwable eventThrowable = event.getThrowable(); - if (eventThrowable != null) { - throw new InvocationTargetException(eventThrowable); - } - } - - void setInputContext(InputContext inputContext) { - if (currentInputContext != null && inputContext != null) { - // don't throw this exception until 4237852 is fixed - // throw new IllegalStateException("Can't have two active InputContext at the same time"); - } - currentInputContext = inputContext; - } - - public synchronized void notifyChangeRequest(Component comp) { - if (!(comp instanceof Frame || comp instanceof Dialog)) - return; - - // if busy with the current request, ignore this request. - if (requestComponent != null) - return; - - requestComponent = comp; - notify(); - } - - public synchronized void notifyChangeRequestByHotKey(Component comp) { - while (!(comp instanceof Frame || comp instanceof Dialog)) { - if (comp == null) { - // no Frame or Dialog found in containment hierarchy. - return; - } - comp = comp.getParent(); - } - - notifyChangeRequest(comp); - } - - public String getTriggerMenuString() { - return triggerMenuString; - } - - /* - * Returns true if the environment indicates there are multiple input methods - */ - boolean hasMultipleInputMethods() { - return ((hostAdapterLocator != null) && (javaInputMethodCount > 0) - || (javaInputMethodCount > 1)); - } - - private synchronized void waitForChangeRequest() { - try { - while (requestComponent == null) { - wait(); - } - } catch (InterruptedException e) { - } - } - - /* - * initializes the input method locator list for all - * installed input method descriptors. - */ - private void initializeInputMethodLocatorList() { - synchronized (javaInputMethodLocatorList) { - javaInputMethodLocatorList.clear(); - try { - AccessController.doPrivileged(new PrivilegedExceptionAction() { - public Object run() { - for (InputMethodDescriptor descriptor : - ServiceLoader.loadInstalled(InputMethodDescriptor.class)) { - ClassLoader cl = descriptor.getClass().getClassLoader(); - javaInputMethodLocatorList.add(new InputMethodLocator(descriptor, cl, null)); - } - return null; - } - }); - } catch (PrivilegedActionException e) { - e.printStackTrace(); - } - javaInputMethodCount = javaInputMethodLocatorList.size(); - } - - if (hasMultipleInputMethods()) { - // initialize preferences - if (userRoot == null) { - userRoot = getUserRoot(); - } - } else { - // indicate to clients not to offer the menu - triggerMenuString = null; - } - } - - private void showInputMethodMenu() { - - if (!hasMultipleInputMethods()) { - requestComponent = null; - return; - } - - // initialize pop-up menu - selectionMenu = InputMethodPopupMenu.getInstance(requestComponent, selectInputMethodMenuTitle); - - // we have to rebuild the menu each time because - // some input methods (such as IIIMP) may change - // their list of supported locales dynamically - selectionMenu.removeAll(); - - // get information about the currently selected input method - // ??? if there's no current input context, what's the point - // of showing the menu? - String currentSelection = getCurrentSelection(); - - // Add menu item for host adapter - if (hostAdapterLocator != null) { - selectionMenu.addOneInputMethodToMenu(hostAdapterLocator, currentSelection); - selectionMenu.addSeparator(); - } - - // Add menu items for other input methods - for (int i = 0; i < javaInputMethodLocatorList.size(); i++) { - InputMethodLocator locator = javaInputMethodLocatorList.get(i); - selectionMenu.addOneInputMethodToMenu(locator, currentSelection); - } - - synchronized (this) { - selectionMenu.addToComponent(requestComponent); - requestInputContext = currentInputContext; - selectionMenu.show(requestComponent, 60, 80); // TODO: get proper x, y... - requestComponent = null; - } - } - - private String getCurrentSelection() { - InputContext inputContext = currentInputContext; - if (inputContext != null) { - InputMethodLocator locator = inputContext.getInputMethodLocator(); - if (locator != null) { - return locator.getActionCommandString(); - } - } - return null; - } - - synchronized void changeInputMethod(String choice) { - InputMethodLocator locator = null; - - String inputMethodName = choice; - String localeString = null; - int index = choice.indexOf('\n'); - if (index != -1) { - localeString = choice.substring(index + 1); - inputMethodName = choice.substring(0, index); - } - if (hostAdapterLocator.getActionCommandString().equals(inputMethodName)) { - locator = hostAdapterLocator; - } else { - for (int i = 0; i < javaInputMethodLocatorList.size(); i++) { - InputMethodLocator candidate = javaInputMethodLocatorList.get(i); - String name = candidate.getActionCommandString(); - if (name.equals(inputMethodName)) { - locator = candidate; - break; - } - } - } - - if (locator != null && localeString != null) { - String language = "", country = "", variant = ""; - int postIndex = localeString.indexOf('_'); - if (postIndex == -1) { - language = localeString; - } else { - language = localeString.substring(0, postIndex); - int preIndex = postIndex + 1; - postIndex = localeString.indexOf('_', preIndex); - if (postIndex == -1) { - country = localeString.substring(preIndex); - } else { - country = localeString.substring(preIndex, postIndex); - variant = localeString.substring(postIndex + 1); - } - } - Locale locale = new Locale(language, country, variant); - locator = locator.deriveLocator(locale); - } - - if (locator == null) - return; - - // tell the input context about the change - if (requestInputContext != null) { - requestInputContext.changeInputMethod(locator); - requestInputContext = null; - - // remember the selection - putPreferredInputMethod(locator); - } - } - - InputMethodLocator findInputMethod(Locale locale) { - // look for preferred input method first - InputMethodLocator locator = getPreferredInputMethod(locale); - if (locator != null) { - return locator; - } - - if (hostAdapterLocator != null && hostAdapterLocator.isLocaleAvailable(locale)) { - return hostAdapterLocator.deriveLocator(locale); - } - - // Update the locator list - initializeInputMethodLocatorList(); - - for (int i = 0; i < javaInputMethodLocatorList.size(); i++) { - InputMethodLocator candidate = javaInputMethodLocatorList.get(i); - if (candidate.isLocaleAvailable(locale)) { - return candidate.deriveLocator(locale); - } - } - return null; - } - - Locale getDefaultKeyboardLocale() { - Toolkit toolkit = Toolkit.getDefaultToolkit(); - if (toolkit instanceof InputMethodSupport) { - return ((InputMethodSupport)toolkit).getDefaultKeyboardLocale(); - } else { - return Locale.getDefault(); - } - } - - /** - * Returns a InputMethodLocator object that the - * user prefers for the given locale. - * - * @param locale Locale for which the user prefers the input method. - */ - private synchronized InputMethodLocator getPreferredInputMethod(Locale locale) { - InputMethodLocator preferredLocator = null; - - if (!hasMultipleInputMethods()) { - // No need to look for a preferred Java input method - return null; - } - - // look for the cached preference first. - preferredLocator = preferredLocatorCache.get(locale.toString().intern()); - if (preferredLocator != null) { - return preferredLocator; - } - - // look for the preference in the user preference tree - String nodePath = findPreferredInputMethodNode(locale); - String descriptorName = readPreferredInputMethod(nodePath); - Locale advertised; - - // get the locator object - if (descriptorName != null) { - // check for the host adapter first - if (hostAdapterLocator != null && - hostAdapterLocator.getDescriptor().getClass().getName().equals(descriptorName)) { - advertised = getAdvertisedLocale(hostAdapterLocator, locale); - if (advertised != null) { - preferredLocator = hostAdapterLocator.deriveLocator(advertised); - preferredLocatorCache.put(locale.toString().intern(), preferredLocator); - } - return preferredLocator; - } - // look for Java input methods - for (int i = 0; i < javaInputMethodLocatorList.size(); i++) { - InputMethodLocator locator = javaInputMethodLocatorList.get(i); - InputMethodDescriptor descriptor = locator.getDescriptor(); - if (descriptor.getClass().getName().equals(descriptorName)) { - advertised = getAdvertisedLocale(locator, locale); - if (advertised != null) { - preferredLocator = locator.deriveLocator(advertised); - preferredLocatorCache.put(locale.toString().intern(), preferredLocator); - } - return preferredLocator; - } - } - - // maybe preferred input method information is bogus. - writePreferredInputMethod(nodePath, null); - } - - return null; - } - - private String findPreferredInputMethodNode(Locale locale) { - if (userRoot == null) { - return null; - } - - // create locale node relative path - String nodePath = preferredIMNode + "/" + createLocalePath(locale); - - // look for the descriptor - while (!nodePath.equals(preferredIMNode)) { - try { - if (userRoot.nodeExists(nodePath)) { - if (readPreferredInputMethod(nodePath) != null) { - return nodePath; - } - } - } catch (BackingStoreException bse) { - } - - // search at parent's node - nodePath = nodePath.substring(0, nodePath.lastIndexOf('/')); - } - - return null; - } - - private String readPreferredInputMethod(String nodePath) { - if ((userRoot == null) || (nodePath == null)) { - return null; - } - - return userRoot.node(nodePath).get(descriptorKey, null); - } - - /** - * Writes the preferred input method descriptor class name into - * the user's Preferences tree in accordance with the given locale. - * - * @param inputMethodLocator input method locator to remember. - */ - private synchronized void putPreferredInputMethod(InputMethodLocator locator) { - InputMethodDescriptor descriptor = locator.getDescriptor(); - Locale preferredLocale = locator.getLocale(); - - if (preferredLocale == null) { - // check available locales of the input method - try { - Locale[] availableLocales = descriptor.getAvailableLocales(); - if (availableLocales.length == 1) { - preferredLocale = availableLocales[0]; - } else { - // there is no way to know which locale is the preferred one, so do nothing. - return; - } - } catch (AWTException ae) { - // do nothing here, either. - return; - } - } - - // for regions that have only one language, we need to regard - // "xx_YY" as "xx" when putting the preference into tree - if (preferredLocale.equals(Locale.JAPAN)) { - preferredLocale = Locale.JAPANESE; - } - if (preferredLocale.equals(Locale.KOREA)) { - preferredLocale = Locale.KOREAN; - } - if (preferredLocale.equals(new Locale("th", "TH"))) { - preferredLocale = new Locale("th"); - } - - // obtain node - String path = preferredIMNode + "/" + createLocalePath(preferredLocale); - - // write in the preference tree - writePreferredInputMethod(path, descriptor.getClass().getName()); - preferredLocatorCache.put(preferredLocale.toString().intern(), - locator.deriveLocator(preferredLocale)); - - return; - } - - private String createLocalePath(Locale locale) { - String language = locale.getLanguage(); - String country = locale.getCountry(); - String variant = locale.getVariant(); - String localePath = null; - if (!variant.equals("")) { - localePath = "_" + language + "/_" + country + "/_" + variant; - } else if (!country.equals("")) { - localePath = "_" + language + "/_" + country; - } else { - localePath = "_" + language; - } - - return localePath; - } - - private void writePreferredInputMethod(String path, String descriptorName) { - if (userRoot != null) { - Preferences node = userRoot.node(path); - - // record it - if (descriptorName != null) { - node.put(descriptorKey, descriptorName); - } else { - node.remove(descriptorKey); - } - } - } - - private Preferences getUserRoot() { - return AccessController.doPrivileged(new PrivilegedAction() { - public Preferences run() { - return Preferences.userRoot(); - } - }); - } - - private Locale getAdvertisedLocale(InputMethodLocator locator, Locale locale) { - Locale advertised = null; - - if (locator.isLocaleAvailable(locale)) { - advertised = locale; - } else if (locale.getLanguage().equals("ja")) { - // for Japanese, Korean, and Thai, check whether the input method supports - // language or language_COUNTRY. - if (locator.isLocaleAvailable(Locale.JAPAN)) { - advertised = Locale.JAPAN; - } else if (locator.isLocaleAvailable(Locale.JAPANESE)) { - advertised = Locale.JAPANESE; - } - } else if (locale.getLanguage().equals("ko")) { - if (locator.isLocaleAvailable(Locale.KOREA)) { - advertised = Locale.KOREA; - } else if (locator.isLocaleAvailable(Locale.KOREAN)) { - advertised = Locale.KOREAN; - } - } else if (locale.getLanguage().equals("th")) { - if (locator.isLocaleAvailable(new Locale("th", "TH"))) { - advertised = new Locale("th", "TH"); - } else if (locator.isLocaleAvailable(new Locale("th"))) { - advertised = new Locale("th"); - } - } - - return advertised; - } -} diff --git a/jdk/src/share/classes/sun/misc/FDBigInt.java b/jdk/src/share/classes/sun/misc/FDBigInt.java new file mode 100644 index 00000000000..601fcb5b40c --- /dev/null +++ b/jdk/src/share/classes/sun/misc/FDBigInt.java @@ -0,0 +1,493 @@ +/* + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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.misc; + +/* + * A really, really simple bigint package + * tailored to the needs of floating base conversion. + */ +class FDBigInt { + int nWords; // number of words used + int data[]; // value: data[0] is least significant + + + public FDBigInt( int v ){ + nWords = 1; + data = new int[1]; + data[0] = v; + } + + public FDBigInt( long v ){ + data = new int[2]; + data[0] = (int)v; + data[1] = (int)(v>>>32); + nWords = (data[1]==0) ? 1 : 2; + } + + public FDBigInt( FDBigInt other ){ + data = new int[nWords = other.nWords]; + System.arraycopy( other.data, 0, data, 0, nWords ); + } + + private FDBigInt( int [] d, int n ){ + data = d; + nWords = n; + } + + public FDBigInt( long seed, char digit[], int nd0, int nd ){ + int n= (nd+8)/9; // estimate size needed. + if ( n < 2 ) n = 2; + data = new int[n]; // allocate enough space + data[0] = (int)seed; // starting value + data[1] = (int)(seed>>>32); + nWords = (data[1]==0) ? 1 : 2; + int i = nd0; + int limit = nd-5; // slurp digits 5 at a time. + int v; + while ( i < limit ){ + int ilim = i+5; + v = (int)digit[i++]-(int)'0'; + while( i >5; + int bitcount = c & 0x1f; + int anticount = 32-bitcount; + int t[] = data; + int s[] = data; + if ( nWords+wordcount+1 > t.length ){ + // reallocate. + t = new int[ nWords+wordcount+1 ]; + } + int target = nWords+wordcount; + int src = nWords-1; + if ( bitcount == 0 ){ + // special hack, since an anticount of 32 won't go! + System.arraycopy( s, 0, t, wordcount, nWords ); + target = wordcount-1; + } else { + t[target--] = s[src]>>>anticount; + while ( src >= 1 ){ + t[target--] = (s[src]<>>anticount); + } + t[target--] = s[src]<= 0 ){ + t[target--] = 0; + } + data = t; + nWords += wordcount + 1; + // may have constructed high-order word of 0. + // if so, trim it + while ( nWords > 1 && data[nWords-1] == 0 ) + nWords--; + } + + /* + * normalize this number by shifting until + * the MSB of the number is at 0x08000000. + * This is in preparation for quoRemIteration, below. + * The idea is that, to make division easier, we want the + * divisor to be "normalized" -- usually this means shifting + * the MSB into the high words sign bit. But because we know that + * the quotient will be 0 < q < 10, we would like to arrange that + * the dividend not span up into another word of precision. + * (This needs to be explained more clearly!) + */ + public int + normalizeMe() throws IllegalArgumentException { + int src; + int wordcount = 0; + int bitcount = 0; + int v = 0; + for ( src= nWords-1 ; src >= 0 && (v=data[src]) == 0 ; src--){ + wordcount += 1; + } + if ( src < 0 ){ + // oops. Value is zero. Cannot normalize it! + throw new IllegalArgumentException("zero value"); + } + /* + * In most cases, we assume that wordcount is zero. This only + * makes sense, as we try not to maintain any high-order + * words full of zeros. In fact, if there are zeros, we will + * simply SHORTEN our number at this point. Watch closely... + */ + nWords -= wordcount; + /* + * Compute how far left we have to shift v s.t. its highest- + * order bit is in the right place. Then call lshiftMe to + * do the work. + */ + if ( (v & 0xf0000000) != 0 ){ + // will have to shift up into the next word. + // too bad. + for( bitcount = 32 ; (v & 0xf0000000) != 0 ; bitcount-- ) + v >>>= 1; + } else { + while ( v <= 0x000fffff ){ + // hack: byte-at-a-time shifting + v <<= 8; + bitcount += 8; + } + while ( v <= 0x07ffffff ){ + v <<= 1; + bitcount += 1; + } + } + if ( bitcount != 0 ) + lshiftMe( bitcount ); + return bitcount; + } + + /* + * Multiply a FDBigInt by an int. + * Result is a new FDBigInt. + */ + public FDBigInt + mult( int iv ) { + long v = iv; + int r[]; + long p; + + // guess adequate size of r. + r = new int[ ( v * ((long)data[nWords-1]&0xffffffffL) > 0xfffffffL ) ? nWords+1 : nWords ]; + p = 0L; + for( int i=0; i < nWords; i++ ) { + p += v * ((long)data[i]&0xffffffffL); + r[i] = (int)p; + p >>>= 32; + } + if ( p == 0L){ + return new FDBigInt( r, nWords ); + } else { + r[nWords] = (int)p; + return new FDBigInt( r, nWords+1 ); + } + } + + /* + * Multiply a FDBigInt by an int and add another int. + * Result is computed in place. + * Hope it fits! + */ + public void + multaddMe( int iv, int addend ) { + long v = iv; + long p; + + // unroll 0th iteration, doing addition. + p = v * ((long)data[0]&0xffffffffL) + ((long)addend&0xffffffffL); + data[0] = (int)p; + p >>>= 32; + for( int i=1; i < nWords; i++ ) { + p += v * ((long)data[i]&0xffffffffL); + data[i] = (int)p; + p >>>= 32; + } + if ( p != 0L){ + data[nWords] = (int)p; // will fail noisily if illegal! + nWords++; + } + } + + /* + * Multiply a FDBigInt by another FDBigInt. + * Result is a new FDBigInt. + */ + public FDBigInt + mult( FDBigInt other ){ + // crudely guess adequate size for r + int r[] = new int[ nWords + other.nWords ]; + int i; + // I think I am promised zeros... + + for( i = 0; i < this.nWords; i++ ){ + long v = (long)this.data[i] & 0xffffffffL; // UNSIGNED CONVERSION + long p = 0L; + int j; + for( j = 0; j < other.nWords; j++ ){ + p += ((long)r[i+j]&0xffffffffL) + v*((long)other.data[j]&0xffffffffL); // UNSIGNED CONVERSIONS ALL 'ROUND. + r[i+j] = (int)p; + p >>>= 32; + } + r[i+j] = (int)p; + } + // compute how much of r we actually needed for all that. + for ( i = r.length-1; i> 0; i--) + if ( r[i] != 0 ) + break; + return new FDBigInt( r, i+1 ); + } + + /* + * Add one FDBigInt to another. Return a FDBigInt + */ + public FDBigInt + add( FDBigInt other ){ + int i; + int a[], b[]; + int n, m; + long c = 0L; + // arrange such that a.nWords >= b.nWords; + // n = a.nWords, m = b.nWords + if ( this.nWords >= other.nWords ){ + a = this.data; + n = this.nWords; + b = other.data; + m = other.nWords; + } else { + a = other.data; + n = other.nWords; + b = this.data; + m = this.nWords; + } + int r[] = new int[ n ]; + for ( i = 0; i < n; i++ ){ + c += (long)a[i] & 0xffffffffL; + if ( i < m ){ + c += (long)b[i] & 0xffffffffL; + } + r[i] = (int) c; + c >>= 32; // signed shift. + } + if ( c != 0L ){ + // oops -- carry out -- need longer result. + int s[] = new int[ r.length+1 ]; + System.arraycopy( r, 0, s, 0, r.length ); + s[i++] = (int)c; + return new FDBigInt( s, i ); + } + return new FDBigInt( r, i ); + } + + /* + * Subtract one FDBigInt from another. Return a FDBigInt + * Assert that the result is positive. + */ + public FDBigInt + sub( FDBigInt other ){ + int r[] = new int[ this.nWords ]; + int i; + int n = this.nWords; + int m = other.nWords; + int nzeros = 0; + long c = 0L; + for ( i = 0; i < n; i++ ){ + c += (long)this.data[i] & 0xffffffffL; + if ( i < m ){ + c -= (long)other.data[i] & 0xffffffffL; + } + if ( ( r[i] = (int) c ) == 0 ) + nzeros++; + else + nzeros = 0; + c >>= 32; // signed shift + } + assert c == 0L : c; // borrow out of subtract + assert dataInRangeIsZero(i, m, other); // negative result of subtract + return new FDBigInt( r, n-nzeros ); + } + + private static boolean dataInRangeIsZero(int i, int m, FDBigInt other) { + while ( i < m ) + if (other.data[i++] != 0) + return false; + return true; + } + + /* + * Compare FDBigInt with another FDBigInt. Return an integer + * >0: this > other + * 0: this == other + * <0: this < other + */ + public int + cmp( FDBigInt other ){ + int i; + if ( this.nWords > other.nWords ){ + // if any of my high-order words is non-zero, + // then the answer is evident + int j = other.nWords-1; + for ( i = this.nWords-1; i > j ; i-- ) + if ( this.data[i] != 0 ) return 1; + }else if ( this.nWords < other.nWords ){ + // if any of other's high-order words is non-zero, + // then the answer is evident + int j = this.nWords-1; + for ( i = other.nWords-1; i > j ; i-- ) + if ( other.data[i] != 0 ) return -1; + } else{ + i = this.nWords-1; + } + for ( ; i > 0 ; i-- ) + if ( this.data[i] != other.data[i] ) + break; + // careful! want unsigned compare! + // use brute force here. + int a = this.data[i]; + int b = other.data[i]; + if ( a < 0 ){ + // a is really big, unsigned + if ( b < 0 ){ + return a-b; // both big, negative + } else { + return 1; // b not big, answer is obvious; + } + } else { + // a is not really big + if ( b < 0 ) { + // but b is really big + return -1; + } else { + return a - b; + } + } + } + + /* + * Compute + * q = (int)( this / S ) + * this = 10 * ( this mod S ) + * Return q. + * This is the iteration step of digit development for output. + * We assume that S has been normalized, as above, and that + * "this" has been lshift'ed accordingly. + * Also assume, of course, that the result, q, can be expressed + * as an integer, 0 <= q < 10. + */ + public int + quoRemIteration( FDBigInt S )throws IllegalArgumentException { + // ensure that this and S have the same number of + // digits. If S is properly normalized and q < 10 then + // this must be so. + if ( nWords != S.nWords ){ + throw new IllegalArgumentException("disparate values"); + } + // estimate q the obvious way. We will usually be + // right. If not, then we're only off by a little and + // will re-add. + int n = nWords-1; + long q = ((long)data[n]&0xffffffffL) / (long)S.data[n]; + long diff = 0L; + for ( int i = 0; i <= n ; i++ ){ + diff += ((long)data[i]&0xffffffffL) - q*((long)S.data[i]&0xffffffffL); + data[i] = (int)diff; + diff >>= 32; // N.B. SIGNED shift. + } + if ( diff != 0L ) { + // damn, damn, damn. q is too big. + // add S back in until this turns +. This should + // not be very many times! + long sum = 0L; + while ( sum == 0L ){ + sum = 0L; + for ( int i = 0; i <= n; i++ ){ + sum += ((long)data[i]&0xffffffffL) + ((long)S.data[i]&0xffffffffL); + data[i] = (int) sum; + sum >>= 32; // Signed or unsigned, answer is 0 or 1 + } + /* + * Originally the following line read + * "if ( sum !=0 && sum != -1 )" + * but that would be wrong, because of the + * treatment of the two values as entirely unsigned, + * it would be impossible for a carry-out to be interpreted + * as -1 -- it would have to be a single-bit carry-out, or + * +1. + */ + assert sum == 0 || sum == 1 : sum; // carry out of division correction + q -= 1; + } + } + // finally, we can multiply this by 10. + // it cannot overflow, right, as the high-order word has + // at least 4 high-order zeros! + long p = 0L; + for ( int i = 0; i <= n; i++ ){ + p += 10*((long)data[i]&0xffffffffL); + data[i] = (int)p; + p >>= 32; // SIGNED shift. + } + assert p == 0L : p; // Carry out of *10 + return (int)q; + } + + public long + longValue(){ + // if this can be represented as a long, return the value + assert this.nWords > 0 : this.nWords; // longValue confused + + if (this.nWords == 1) + return ((long)data[0]&0xffffffffL); + + assert dataInRangeIsZero(2, this.nWords, this); // value too big + assert data[1] >= 0; // value too big + return ((long)(data[1]) << 32) | ((long)data[0]&0xffffffffL); + } + + public String + toString() { + StringBuffer r = new StringBuffer(30); + r.append('['); + int i = Math.min( nWords-1, data.length-1) ; + if ( nWords > data.length ){ + r.append( "("+data.length+"<"+nWords+"!)" ); + } + for( ; i> 0 ; i-- ){ + r.append( Integer.toHexString( data[i] ) ); + r.append(' '); + } + r.append( Integer.toHexString( data[0] ) ); + r.append(']'); + return new String( r ); + } +} diff --git a/jdk/src/share/classes/sun/misc/FloatingDecimal.java b/jdk/src/share/classes/sun/misc/FloatingDecimal.java index 478f120035c..0071936cf61 100644 --- a/jdk/src/share/classes/sun/misc/FloatingDecimal.java +++ b/jdk/src/share/classes/sun/misc/FloatingDecimal.java @@ -2409,470 +2409,3 @@ public class FloatingDecimal{ } - -/* - * A really, really simple bigint package - * tailored to the needs of floating base conversion. - */ -class FDBigInt { - int nWords; // number of words used - int data[]; // value: data[0] is least significant - - - public FDBigInt( int v ){ - nWords = 1; - data = new int[1]; - data[0] = v; - } - - public FDBigInt( long v ){ - data = new int[2]; - data[0] = (int)v; - data[1] = (int)(v>>>32); - nWords = (data[1]==0) ? 1 : 2; - } - - public FDBigInt( FDBigInt other ){ - data = new int[nWords = other.nWords]; - System.arraycopy( other.data, 0, data, 0, nWords ); - } - - private FDBigInt( int [] d, int n ){ - data = d; - nWords = n; - } - - public FDBigInt( long seed, char digit[], int nd0, int nd ){ - int n= (nd+8)/9; // estimate size needed. - if ( n < 2 ) n = 2; - data = new int[n]; // allocate enough space - data[0] = (int)seed; // starting value - data[1] = (int)(seed>>>32); - nWords = (data[1]==0) ? 1 : 2; - int i = nd0; - int limit = nd-5; // slurp digits 5 at a time. - int v; - while ( i < limit ){ - int ilim = i+5; - v = (int)digit[i++]-(int)'0'; - while( i >5; - int bitcount = c & 0x1f; - int anticount = 32-bitcount; - int t[] = data; - int s[] = data; - if ( nWords+wordcount+1 > t.length ){ - // reallocate. - t = new int[ nWords+wordcount+1 ]; - } - int target = nWords+wordcount; - int src = nWords-1; - if ( bitcount == 0 ){ - // special hack, since an anticount of 32 won't go! - System.arraycopy( s, 0, t, wordcount, nWords ); - target = wordcount-1; - } else { - t[target--] = s[src]>>>anticount; - while ( src >= 1 ){ - t[target--] = (s[src]<>>anticount); - } - t[target--] = s[src]<= 0 ){ - t[target--] = 0; - } - data = t; - nWords += wordcount + 1; - // may have constructed high-order word of 0. - // if so, trim it - while ( nWords > 1 && data[nWords-1] == 0 ) - nWords--; - } - - /* - * normalize this number by shifting until - * the MSB of the number is at 0x08000000. - * This is in preparation for quoRemIteration, below. - * The idea is that, to make division easier, we want the - * divisor to be "normalized" -- usually this means shifting - * the MSB into the high words sign bit. But because we know that - * the quotient will be 0 < q < 10, we would like to arrange that - * the dividend not span up into another word of precision. - * (This needs to be explained more clearly!) - */ - public int - normalizeMe() throws IllegalArgumentException { - int src; - int wordcount = 0; - int bitcount = 0; - int v = 0; - for ( src= nWords-1 ; src >= 0 && (v=data[src]) == 0 ; src--){ - wordcount += 1; - } - if ( src < 0 ){ - // oops. Value is zero. Cannot normalize it! - throw new IllegalArgumentException("zero value"); - } - /* - * In most cases, we assume that wordcount is zero. This only - * makes sense, as we try not to maintain any high-order - * words full of zeros. In fact, if there are zeros, we will - * simply SHORTEN our number at this point. Watch closely... - */ - nWords -= wordcount; - /* - * Compute how far left we have to shift v s.t. its highest- - * order bit is in the right place. Then call lshiftMe to - * do the work. - */ - if ( (v & 0xf0000000) != 0 ){ - // will have to shift up into the next word. - // too bad. - for( bitcount = 32 ; (v & 0xf0000000) != 0 ; bitcount-- ) - v >>>= 1; - } else { - while ( v <= 0x000fffff ){ - // hack: byte-at-a-time shifting - v <<= 8; - bitcount += 8; - } - while ( v <= 0x07ffffff ){ - v <<= 1; - bitcount += 1; - } - } - if ( bitcount != 0 ) - lshiftMe( bitcount ); - return bitcount; - } - - /* - * Multiply a FDBigInt by an int. - * Result is a new FDBigInt. - */ - public FDBigInt - mult( int iv ) { - long v = iv; - int r[]; - long p; - - // guess adequate size of r. - r = new int[ ( v * ((long)data[nWords-1]&0xffffffffL) > 0xfffffffL ) ? nWords+1 : nWords ]; - p = 0L; - for( int i=0; i < nWords; i++ ) { - p += v * ((long)data[i]&0xffffffffL); - r[i] = (int)p; - p >>>= 32; - } - if ( p == 0L){ - return new FDBigInt( r, nWords ); - } else { - r[nWords] = (int)p; - return new FDBigInt( r, nWords+1 ); - } - } - - /* - * Multiply a FDBigInt by an int and add another int. - * Result is computed in place. - * Hope it fits! - */ - public void - multaddMe( int iv, int addend ) { - long v = iv; - long p; - - // unroll 0th iteration, doing addition. - p = v * ((long)data[0]&0xffffffffL) + ((long)addend&0xffffffffL); - data[0] = (int)p; - p >>>= 32; - for( int i=1; i < nWords; i++ ) { - p += v * ((long)data[i]&0xffffffffL); - data[i] = (int)p; - p >>>= 32; - } - if ( p != 0L){ - data[nWords] = (int)p; // will fail noisily if illegal! - nWords++; - } - } - - /* - * Multiply a FDBigInt by another FDBigInt. - * Result is a new FDBigInt. - */ - public FDBigInt - mult( FDBigInt other ){ - // crudely guess adequate size for r - int r[] = new int[ nWords + other.nWords ]; - int i; - // I think I am promised zeros... - - for( i = 0; i < this.nWords; i++ ){ - long v = (long)this.data[i] & 0xffffffffL; // UNSIGNED CONVERSION - long p = 0L; - int j; - for( j = 0; j < other.nWords; j++ ){ - p += ((long)r[i+j]&0xffffffffL) + v*((long)other.data[j]&0xffffffffL); // UNSIGNED CONVERSIONS ALL 'ROUND. - r[i+j] = (int)p; - p >>>= 32; - } - r[i+j] = (int)p; - } - // compute how much of r we actually needed for all that. - for ( i = r.length-1; i> 0; i--) - if ( r[i] != 0 ) - break; - return new FDBigInt( r, i+1 ); - } - - /* - * Add one FDBigInt to another. Return a FDBigInt - */ - public FDBigInt - add( FDBigInt other ){ - int i; - int a[], b[]; - int n, m; - long c = 0L; - // arrange such that a.nWords >= b.nWords; - // n = a.nWords, m = b.nWords - if ( this.nWords >= other.nWords ){ - a = this.data; - n = this.nWords; - b = other.data; - m = other.nWords; - } else { - a = other.data; - n = other.nWords; - b = this.data; - m = this.nWords; - } - int r[] = new int[ n ]; - for ( i = 0; i < n; i++ ){ - c += (long)a[i] & 0xffffffffL; - if ( i < m ){ - c += (long)b[i] & 0xffffffffL; - } - r[i] = (int) c; - c >>= 32; // signed shift. - } - if ( c != 0L ){ - // oops -- carry out -- need longer result. - int s[] = new int[ r.length+1 ]; - System.arraycopy( r, 0, s, 0, r.length ); - s[i++] = (int)c; - return new FDBigInt( s, i ); - } - return new FDBigInt( r, i ); - } - - /* - * Subtract one FDBigInt from another. Return a FDBigInt - * Assert that the result is positive. - */ - public FDBigInt - sub( FDBigInt other ){ - int r[] = new int[ this.nWords ]; - int i; - int n = this.nWords; - int m = other.nWords; - int nzeros = 0; - long c = 0L; - for ( i = 0; i < n; i++ ){ - c += (long)this.data[i] & 0xffffffffL; - if ( i < m ){ - c -= (long)other.data[i] & 0xffffffffL; - } - if ( ( r[i] = (int) c ) == 0 ) - nzeros++; - else - nzeros = 0; - c >>= 32; // signed shift - } - assert c == 0L : c; // borrow out of subtract - assert dataInRangeIsZero(i, m, other); // negative result of subtract - return new FDBigInt( r, n-nzeros ); - } - - private static boolean dataInRangeIsZero(int i, int m, FDBigInt other) { - while ( i < m ) - if (other.data[i++] != 0) - return false; - return true; - } - - /* - * Compare FDBigInt with another FDBigInt. Return an integer - * >0: this > other - * 0: this == other - * <0: this < other - */ - public int - cmp( FDBigInt other ){ - int i; - if ( this.nWords > other.nWords ){ - // if any of my high-order words is non-zero, - // then the answer is evident - int j = other.nWords-1; - for ( i = this.nWords-1; i > j ; i-- ) - if ( this.data[i] != 0 ) return 1; - }else if ( this.nWords < other.nWords ){ - // if any of other's high-order words is non-zero, - // then the answer is evident - int j = this.nWords-1; - for ( i = other.nWords-1; i > j ; i-- ) - if ( other.data[i] != 0 ) return -1; - } else{ - i = this.nWords-1; - } - for ( ; i > 0 ; i-- ) - if ( this.data[i] != other.data[i] ) - break; - // careful! want unsigned compare! - // use brute force here. - int a = this.data[i]; - int b = other.data[i]; - if ( a < 0 ){ - // a is really big, unsigned - if ( b < 0 ){ - return a-b; // both big, negative - } else { - return 1; // b not big, answer is obvious; - } - } else { - // a is not really big - if ( b < 0 ) { - // but b is really big - return -1; - } else { - return a - b; - } - } - } - - /* - * Compute - * q = (int)( this / S ) - * this = 10 * ( this mod S ) - * Return q. - * This is the iteration step of digit development for output. - * We assume that S has been normalized, as above, and that - * "this" has been lshift'ed accordingly. - * Also assume, of course, that the result, q, can be expressed - * as an integer, 0 <= q < 10. - */ - public int - quoRemIteration( FDBigInt S )throws IllegalArgumentException { - // ensure that this and S have the same number of - // digits. If S is properly normalized and q < 10 then - // this must be so. - if ( nWords != S.nWords ){ - throw new IllegalArgumentException("disparate values"); - } - // estimate q the obvious way. We will usually be - // right. If not, then we're only off by a little and - // will re-add. - int n = nWords-1; - long q = ((long)data[n]&0xffffffffL) / (long)S.data[n]; - long diff = 0L; - for ( int i = 0; i <= n ; i++ ){ - diff += ((long)data[i]&0xffffffffL) - q*((long)S.data[i]&0xffffffffL); - data[i] = (int)diff; - diff >>= 32; // N.B. SIGNED shift. - } - if ( diff != 0L ) { - // damn, damn, damn. q is too big. - // add S back in until this turns +. This should - // not be very many times! - long sum = 0L; - while ( sum == 0L ){ - sum = 0L; - for ( int i = 0; i <= n; i++ ){ - sum += ((long)data[i]&0xffffffffL) + ((long)S.data[i]&0xffffffffL); - data[i] = (int) sum; - sum >>= 32; // Signed or unsigned, answer is 0 or 1 - } - /* - * Originally the following line read - * "if ( sum !=0 && sum != -1 )" - * but that would be wrong, because of the - * treatment of the two values as entirely unsigned, - * it would be impossible for a carry-out to be interpreted - * as -1 -- it would have to be a single-bit carry-out, or - * +1. - */ - assert sum == 0 || sum == 1 : sum; // carry out of division correction - q -= 1; - } - } - // finally, we can multiply this by 10. - // it cannot overflow, right, as the high-order word has - // at least 4 high-order zeros! - long p = 0L; - for ( int i = 0; i <= n; i++ ){ - p += 10*((long)data[i]&0xffffffffL); - data[i] = (int)p; - p >>= 32; // SIGNED shift. - } - assert p == 0L : p; // Carry out of *10 - return (int)q; - } - - public long - longValue(){ - // if this can be represented as a long, return the value - assert this.nWords > 0 : this.nWords; // longValue confused - - if (this.nWords == 1) - return ((long)data[0]&0xffffffffL); - - assert dataInRangeIsZero(2, this.nWords, this); // value too big - assert data[1] >= 0; // value too big - return ((long)(data[1]) << 32) | ((long)data[0]&0xffffffffL); - } - - public String - toString() { - StringBuffer r = new StringBuffer(30); - r.append('['); - int i = Math.min( nWords-1, data.length-1) ; - if ( nWords > data.length ){ - r.append( "("+data.length+"<"+nWords+"!)" ); - } - for( ; i> 0 ; i-- ){ - r.append( Integer.toHexString( data[i] ) ); - r.append(' '); - } - r.append( Integer.toHexString( data[0] ) ); - r.append(']'); - return new String( r ); - } -} diff --git a/jdk/src/share/classes/sun/net/httpserver/Event.java b/jdk/src/share/classes/sun/net/httpserver/Event.java index f019ede6e52..3214a2a92c8 100644 --- a/jdk/src/share/classes/sun/net/httpserver/Event.java +++ b/jdk/src/share/classes/sun/net/httpserver/Event.java @@ -36,11 +36,3 @@ class Event { this.exchange = t; } } - -class WriteFinishedEvent extends Event { - WriteFinishedEvent (ExchangeImpl t) { - super (t); - assert !t.writefinished; - t.writefinished = true; - } -} diff --git a/jdk/src/share/classes/sun/net/httpserver/WriteFinishedEvent.java b/jdk/src/share/classes/sun/net/httpserver/WriteFinishedEvent.java new file mode 100644 index 00000000000..c613a17d971 --- /dev/null +++ b/jdk/src/share/classes/sun/net/httpserver/WriteFinishedEvent.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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.net.httpserver; + +class WriteFinishedEvent extends Event { + WriteFinishedEvent (ExchangeImpl t) { + super (t); + assert !t.writefinished; + t.writefinished = true; + } +} diff --git a/jdk/src/share/classes/sun/net/www/http/KeepAliveCleanerEntry.java b/jdk/src/share/classes/sun/net/www/http/KeepAliveCleanerEntry.java new file mode 100644 index 00000000000..9d2bb61ab24 --- /dev/null +++ b/jdk/src/share/classes/sun/net/www/http/KeepAliveCleanerEntry.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute 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.net.www.http; + +import java.io.*; + +class KeepAliveCleanerEntry +{ + KeepAliveStream kas; + HttpClient hc; + + public KeepAliveCleanerEntry(KeepAliveStream kas, HttpClient hc) { + this.kas = kas; + this.hc = hc; + } + + protected KeepAliveStream getKeepAliveStream() { + return kas; + } + + protected HttpClient getHttpClient() { + return hc; + } + + protected void setQueuedForCleanup() { + kas.queuedForCleanup = true; + } + + protected boolean getQueuedForCleanup() { + return kas.queuedForCleanup; + } + +} diff --git a/jdk/src/share/classes/sun/net/www/http/KeepAliveStream.java b/jdk/src/share/classes/sun/net/www/http/KeepAliveStream.java index db9b7b03041..50304d23dc3 100644 --- a/jdk/src/share/classes/sun/net/www/http/KeepAliveStream.java +++ b/jdk/src/share/classes/sun/net/www/http/KeepAliveStream.java @@ -206,32 +206,3 @@ class KeepAliveStream extends MeteredStream implements Hurryable { closed = true; } } - - -class KeepAliveCleanerEntry -{ - KeepAliveStream kas; - HttpClient hc; - - public KeepAliveCleanerEntry(KeepAliveStream kas, HttpClient hc) { - this.kas = kas; - this.hc = hc; - } - - protected KeepAliveStream getKeepAliveStream() { - return kas; - } - - protected HttpClient getHttpClient() { - return hc; - } - - protected void setQueuedForCleanup() { - kas.queuedForCleanup = true; - } - - protected boolean getQueuedForCleanup() { - return kas.queuedForCleanup; - } - -} diff --git a/jdk/src/share/classes/sun/security/ssl/ExtensionType.java b/jdk/src/share/classes/sun/security/ssl/ExtensionType.java new file mode 100644 index 00000000000..ee3f5c8c7b1 --- /dev/null +++ b/jdk/src/share/classes/sun/security/ssl/ExtensionType.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +import java.util.ArrayList; +import java.util.List; + +final class ExtensionType { + + final int id; + final String name; + + private ExtensionType(int id, String name) { + this.id = id; + this.name = name; + } + + public String toString() { + return name; + } + + static List knownExtensions = new ArrayList(9); + + static ExtensionType get(int id) { + for (ExtensionType ext : knownExtensions) { + if (ext.id == id) { + return ext; + } + } + return new ExtensionType(id, "type_" + id); + } + + private static ExtensionType e(int id, String name) { + ExtensionType ext = new ExtensionType(id, name); + knownExtensions.add(ext); + return ext; + } + + // extensions defined in RFC 3546 + final static ExtensionType EXT_SERVER_NAME = + e(0x0000, "server_name"); // IANA registry value: 0 + final static ExtensionType EXT_MAX_FRAGMENT_LENGTH = + e(0x0001, "max_fragment_length"); // IANA registry value: 1 + final static ExtensionType EXT_CLIENT_CERTIFICATE_URL = + e(0x0002, "client_certificate_url"); // IANA registry value: 2 + final static ExtensionType EXT_TRUSTED_CA_KEYS = + e(0x0003, "trusted_ca_keys"); // IANA registry value: 3 + final static ExtensionType EXT_TRUNCATED_HMAC = + e(0x0004, "truncated_hmac"); // IANA registry value: 4 + final static ExtensionType EXT_STATUS_REQUEST = + e(0x0005, "status_request"); // IANA registry value: 5 + + // extensions defined in RFC 4681 + final static ExtensionType EXT_USER_MAPPING = + e(0x0006, "user_mapping"); // IANA registry value: 6 + + // extensions defined in RFC 5081 + final static ExtensionType EXT_CERT_TYPE = + e(0x0009, "cert_type"); // IANA registry value: 9 + + // extensions defined in RFC 4492 (ECC) + final static ExtensionType EXT_ELLIPTIC_CURVES = + e(0x000A, "elliptic_curves"); // IANA registry value: 10 + final static ExtensionType EXT_EC_POINT_FORMATS = + e(0x000B, "ec_point_formats"); // IANA registry value: 11 + + // extensions defined in RFC 5054 + final static ExtensionType EXT_SRP = + e(0x000C, "srp"); // IANA registry value: 12 + + // extensions defined in RFC 5246 + final static ExtensionType EXT_SIGNATURE_ALGORITHMS = + e(0x000D, "signature_algorithms"); // IANA registry value: 13 + + // extensions defined in RFC 5746 + final static ExtensionType EXT_RENEGOTIATION_INFO = + e(0xff01, "renegotiation_info"); // IANA registry value: 65281 +} diff --git a/jdk/src/share/classes/sun/security/ssl/HelloExtension.java b/jdk/src/share/classes/sun/security/ssl/HelloExtension.java new file mode 100644 index 00000000000..bc7f0c94632 --- /dev/null +++ b/jdk/src/share/classes/sun/security/ssl/HelloExtension.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +import java.io.IOException; + +abstract class HelloExtension { + + final ExtensionType type; + + HelloExtension(ExtensionType type) { + this.type = type; + } + + // Length of the encoded extension, including the type and length fields + abstract int length(); + + abstract void send(HandshakeOutStream s) throws IOException; + + public abstract String toString(); + +} diff --git a/jdk/src/share/classes/sun/security/ssl/HelloExtensions.java b/jdk/src/share/classes/sun/security/ssl/HelloExtensions.java index ea769fd30dd..d8c734c7184 100644 --- a/jdk/src/share/classes/sun/security/ssl/HelloExtensions.java +++ b/jdk/src/share/classes/sun/security/ssl/HelloExtensions.java @@ -153,795 +153,3 @@ final class HelloExtensions { } } } - -final class ExtensionType { - - final int id; - final String name; - - private ExtensionType(int id, String name) { - this.id = id; - this.name = name; - } - - public String toString() { - return name; - } - - static List knownExtensions = new ArrayList<>(9); - - static ExtensionType get(int id) { - for (ExtensionType ext : knownExtensions) { - if (ext.id == id) { - return ext; - } - } - return new ExtensionType(id, "type_" + id); - } - - private static ExtensionType e(int id, String name) { - ExtensionType ext = new ExtensionType(id, name); - knownExtensions.add(ext); - return ext; - } - - // extensions defined in RFC 3546 - final static ExtensionType EXT_SERVER_NAME = - e(0x0000, "server_name"); // IANA registry value: 0 - final static ExtensionType EXT_MAX_FRAGMENT_LENGTH = - e(0x0001, "max_fragment_length"); // IANA registry value: 1 - final static ExtensionType EXT_CLIENT_CERTIFICATE_URL = - e(0x0002, "client_certificate_url"); // IANA registry value: 2 - final static ExtensionType EXT_TRUSTED_CA_KEYS = - e(0x0003, "trusted_ca_keys"); // IANA registry value: 3 - final static ExtensionType EXT_TRUNCATED_HMAC = - e(0x0004, "truncated_hmac"); // IANA registry value: 4 - final static ExtensionType EXT_STATUS_REQUEST = - e(0x0005, "status_request"); // IANA registry value: 5 - - // extensions defined in RFC 4681 - final static ExtensionType EXT_USER_MAPPING = - e(0x0006, "user_mapping"); // IANA registry value: 6 - - // extensions defined in RFC 5081 - final static ExtensionType EXT_CERT_TYPE = - e(0x0009, "cert_type"); // IANA registry value: 9 - - // extensions defined in RFC 4492 (ECC) - final static ExtensionType EXT_ELLIPTIC_CURVES = - e(0x000A, "elliptic_curves"); // IANA registry value: 10 - final static ExtensionType EXT_EC_POINT_FORMATS = - e(0x000B, "ec_point_formats"); // IANA registry value: 11 - - // extensions defined in RFC 5054 - final static ExtensionType EXT_SRP = - e(0x000C, "srp"); // IANA registry value: 12 - - // extensions defined in RFC 5246 - final static ExtensionType EXT_SIGNATURE_ALGORITHMS = - e(0x000D, "signature_algorithms"); // IANA registry value: 13 - - // extensions defined in RFC 5746 - final static ExtensionType EXT_RENEGOTIATION_INFO = - e(0xff01, "renegotiation_info"); // IANA registry value: 65281 -} - -abstract class HelloExtension { - - final ExtensionType type; - - HelloExtension(ExtensionType type) { - this.type = type; - } - - // Length of the encoded extension, including the type and length fields - abstract int length(); - - abstract void send(HandshakeOutStream s) throws IOException; - - public abstract String toString(); - -} - -final class UnknownExtension extends HelloExtension { - - private final byte[] data; - - UnknownExtension(HandshakeInStream s, int len, ExtensionType type) - throws IOException { - super(type); - data = new byte[len]; - // s.read() does not handle 0-length arrays. - if (len != 0) { - s.read(data); - } - } - - int length() { - return 4 + data.length; - } - - void send(HandshakeOutStream s) throws IOException { - s.putInt16(type.id); - s.putBytes16(data); - } - - public String toString() { - return "Unsupported extension " + type + ", data: " + - Debug.toString(data); - } -} - -/* - * [RFC 4366/6066] To facilitate secure connections to servers that host - * multiple 'virtual' servers at a single underlying network address, clients - * MAY include an extension of type "server_name" in the (extended) client - * hello. The "extension_data" field of this extension SHALL contain - * "ServerNameList" where: - * - * struct { - * NameType name_type; - * select (name_type) { - * case host_name: HostName; - * } name; - * } ServerName; - * - * enum { - * host_name(0), (255) - * } NameType; - * - * opaque HostName<1..2^16-1>; - * - * struct { - * ServerName server_name_list<1..2^16-1> - * } ServerNameList; - */ -final class ServerNameExtension extends HelloExtension { - - // For backward compatibility, all future data structures associated with - // new NameTypes MUST begin with a 16-bit length field. - final static int NAME_HEADER_LENGTH = 3; // NameType: 1 byte - // Name length: 2 bytes - private Map sniMap; - private int listLength; // ServerNameList length - - // constructor for ServerHello - ServerNameExtension() throws IOException { - super(ExtensionType.EXT_SERVER_NAME); - - listLength = 0; - sniMap = Collections.emptyMap(); - } - - // constructor for ClientHello - ServerNameExtension(List serverNames) - throws IOException { - super(ExtensionType.EXT_SERVER_NAME); - - listLength = 0; - sniMap = new LinkedHashMap<>(); - for (SNIServerName serverName : serverNames) { - // check for duplicated server name type - if (sniMap.put(serverName.getType(), serverName) != null) { - // unlikely to happen, but in case ... - throw new RuntimeException( - "Duplicated server name of type " + serverName.getType()); - } - - listLength += serverName.getEncoded().length + NAME_HEADER_LENGTH; - } - - // This constructor is used for ClientHello only. Empty list is - // not allowed in client mode. - if (listLength == 0) { - throw new RuntimeException("The ServerNameList cannot be empty"); - } - } - - // constructor for ServerHello for parsing SNI extension - ServerNameExtension(HandshakeInStream s, int len) - throws IOException { - super(ExtensionType.EXT_SERVER_NAME); - - int remains = len; - if (len >= 2) { // "server_name" extension in ClientHello - listLength = s.getInt16(); // ServerNameList length - if (listLength == 0 || listLength + 2 != len) { - throw new SSLProtocolException( - "Invalid " + type + " extension"); - } - - remains -= 2; - sniMap = new LinkedHashMap<>(); - while (remains > 0) { - int code = s.getInt8(); // NameType - - // HostName (length read in getBytes16); - byte[] encoded = s.getBytes16(); - SNIServerName serverName; - switch (code) { - case StandardConstants.SNI_HOST_NAME: - if (encoded.length == 0) { - throw new SSLProtocolException( - "Empty HostName in server name indication"); - } - try { - serverName = new SNIHostName(encoded); - } catch (IllegalArgumentException iae) { - SSLProtocolException spe = new SSLProtocolException( - "Illegal server name, type=host_name(" + - code + "), name=" + - (new String(encoded, StandardCharsets.UTF_8)) + - ", value=" + Debug.toString(encoded)); - spe.initCause(iae); - throw spe; - } - break; - default: - try { - serverName = new UnknownServerName(code, encoded); - } catch (IllegalArgumentException iae) { - SSLProtocolException spe = new SSLProtocolException( - "Illegal server name, type=(" + code + - "), value=" + Debug.toString(encoded)); - spe.initCause(iae); - throw spe; - } - } - // check for duplicated server name type - if (sniMap.put(serverName.getType(), serverName) != null) { - throw new SSLProtocolException( - "Duplicated server name of type " + - serverName.getType()); - } - - remains -= encoded.length + NAME_HEADER_LENGTH; - } - } else if (len == 0) { // "server_name" extension in ServerHello - listLength = 0; - sniMap = Collections.emptyMap(); - } - - if (remains != 0) { - throw new SSLProtocolException("Invalid server_name extension"); - } - } - - List getServerNames() { - if (sniMap != null && !sniMap.isEmpty()) { - return Collections.unmodifiableList( - new ArrayList<>(sniMap.values())); - } - - return Collections.emptyList(); - } - - /* - * Is the extension recognized by the corresponding matcher? - * - * This method is used to check whether the server name indication can - * be recognized by the server name matchers. - * - * Per RFC 6066, if the server understood the ClientHello extension but - * does not recognize the server name, the server SHOULD take one of two - * actions: either abort the handshake by sending a fatal-level - * unrecognized_name(112) alert or continue the handshake. - * - * If there is an instance of SNIMatcher defined for a particular name - * type, it must be used to perform match operations on the server name. - */ - boolean isMatched(Collection matchers) { - if (sniMap != null && !sniMap.isEmpty()) { - for (SNIMatcher matcher : matchers) { - SNIServerName sniName = sniMap.get(matcher.getType()); - if (sniName != null && (!matcher.matches(sniName))) { - return false; - } - } - } - - return true; - } - - /* - * Is the extension is identical to a server name list? - * - * This method is used to check the server name indication during session - * resumption. - * - * Per RFC 6066, when the server is deciding whether or not to accept a - * request to resume a session, the contents of a server_name extension - * MAY be used in the lookup of the session in the session cache. The - * client SHOULD include the same server_name extension in the session - * resumption request as it did in the full handshake that established - * the session. A server that implements this extension MUST NOT accept - * the request to resume the session if the server_name extension contains - * a different name. Instead, it proceeds with a full handshake to - * establish a new session. When resuming a session, the server MUST NOT - * include a server_name extension in the server hello. - */ - boolean isIdentical(List other) { - if (other.size() == sniMap.size()) { - for(SNIServerName sniInOther : other) { - SNIServerName sniName = sniMap.get(sniInOther.getType()); - if (sniName == null || !sniInOther.equals(sniName)) { - return false; - } - } - - return true; - } - - return false; - } - - int length() { - return listLength == 0 ? 4 : 6 + listLength; - } - - void send(HandshakeOutStream s) throws IOException { - s.putInt16(type.id); - if (listLength == 0) { - s.putInt16(listLength); // in ServerHello, empty extension_data - } else { - s.putInt16(listLength + 2); // length of extension_data - s.putInt16(listLength); // length of ServerNameList - - for (SNIServerName sniName : sniMap.values()) { - s.putInt8(sniName.getType()); // server name type - s.putBytes16(sniName.getEncoded()); // server name value - } - } - } - - public String toString() { - StringBuffer buffer = new StringBuffer(); - for (SNIServerName sniName : sniMap.values()) { - buffer.append("[" + sniName + "]"); - } - - return "Extension " + type + ", server_name: " + buffer; - } - - private static class UnknownServerName extends SNIServerName { - UnknownServerName(int code, byte[] encoded) { - super(code, encoded); - } - } - -} - -final class SupportedEllipticCurvesExtension extends HelloExtension { - - // the extension value to send in the ClientHello message - static final SupportedEllipticCurvesExtension DEFAULT; - - private static final boolean fips; - - static { - int[] ids; - fips = SunJSSE.isFIPS(); - if (fips == false) { - ids = new int[] { - // NIST curves first - // prefer NIST P-256, rest in order of increasing key length - 23, 1, 3, 19, 21, 6, 7, 9, 10, 24, 11, 12, 25, 13, 14, - // non-NIST curves - 15, 16, 17, 2, 18, 4, 5, 20, 8, 22, - }; - } else { - ids = new int[] { - // same as above, but allow only NIST curves in FIPS mode - 23, 1, 3, 19, 21, 6, 7, 9, 10, 24, 11, 12, 25, 13, 14, - }; - } - DEFAULT = new SupportedEllipticCurvesExtension(ids); - } - - private final int[] curveIds; - - private SupportedEllipticCurvesExtension(int[] curveIds) { - super(ExtensionType.EXT_ELLIPTIC_CURVES); - this.curveIds = curveIds; - } - - SupportedEllipticCurvesExtension(HandshakeInStream s, int len) - throws IOException { - super(ExtensionType.EXT_ELLIPTIC_CURVES); - int k = s.getInt16(); - if (((len & 1) != 0) || (k + 2 != len)) { - throw new SSLProtocolException("Invalid " + type + " extension"); - } - curveIds = new int[k >> 1]; - for (int i = 0; i < curveIds.length; i++) { - curveIds[i] = s.getInt16(); - } - } - - boolean contains(int index) { - for (int curveId : curveIds) { - if (index == curveId) { - return true; - } - } - return false; - } - - // Return a reference to the internal curveIds array. - // The caller must NOT modify the contents. - int[] curveIds() { - return curveIds; - } - - int length() { - return 6 + (curveIds.length << 1); - } - - void send(HandshakeOutStream s) throws IOException { - s.putInt16(type.id); - int k = curveIds.length << 1; - s.putInt16(k + 2); - s.putInt16(k); - for (int curveId : curveIds) { - s.putInt16(curveId); - } - } - - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("Extension " + type + ", curve names: {"); - boolean first = true; - for (int curveId : curveIds) { - if (first) { - first = false; - } else { - sb.append(", "); - } - // first check if it is a known named curve, then try other cases. - String oid = getCurveOid(curveId); - if (oid != null) { - ECParameterSpec spec = JsseJce.getECParameterSpec(oid); - // this toString() output will look nice for the current - // implementation of the ECParameterSpec class in the Sun - // provider, but may not look good for other implementations. - if (spec != null) { - sb.append(spec.toString().split(" ")[0]); - } else { - sb.append(oid); - } - } else if (curveId == ARBITRARY_PRIME) { - sb.append("arbitrary_explicit_prime_curves"); - } else if (curveId == ARBITRARY_CHAR2) { - sb.append("arbitrary_explicit_char2_curves"); - } else { - sb.append("unknown curve " + curveId); - } - } - sb.append("}"); - return sb.toString(); - } - - // Test whether we support the curve with the given index. - static boolean isSupported(int index) { - if ((index <= 0) || (index >= NAMED_CURVE_OID_TABLE.length)) { - return false; - } - if (fips == false) { - // in non-FIPS mode, we support all valid indices - return true; - } - return DEFAULT.contains(index); - } - - static int getCurveIndex(ECParameterSpec params) { - String oid = JsseJce.getNamedCurveOid(params); - if (oid == null) { - return -1; - } - Integer n = curveIndices.get(oid); - return (n == null) ? -1 : n; - } - - static String getCurveOid(int index) { - if ((index > 0) && (index < NAMED_CURVE_OID_TABLE.length)) { - return NAMED_CURVE_OID_TABLE[index]; - } - return null; - } - - private final static int ARBITRARY_PRIME = 0xff01; - private final static int ARBITRARY_CHAR2 = 0xff02; - - // See sun.security.ec.NamedCurve for the OIDs - private final static String[] NAMED_CURVE_OID_TABLE = new String[] { - null, // (0) unused - "1.3.132.0.1", // (1) sect163k1, NIST K-163 - "1.3.132.0.2", // (2) sect163r1 - "1.3.132.0.15", // (3) sect163r2, NIST B-163 - "1.3.132.0.24", // (4) sect193r1 - "1.3.132.0.25", // (5) sect193r2 - "1.3.132.0.26", // (6) sect233k1, NIST K-233 - "1.3.132.0.27", // (7) sect233r1, NIST B-233 - "1.3.132.0.3", // (8) sect239k1 - "1.3.132.0.16", // (9) sect283k1, NIST K-283 - "1.3.132.0.17", // (10) sect283r1, NIST B-283 - "1.3.132.0.36", // (11) sect409k1, NIST K-409 - "1.3.132.0.37", // (12) sect409r1, NIST B-409 - "1.3.132.0.38", // (13) sect571k1, NIST K-571 - "1.3.132.0.39", // (14) sect571r1, NIST B-571 - "1.3.132.0.9", // (15) secp160k1 - "1.3.132.0.8", // (16) secp160r1 - "1.3.132.0.30", // (17) secp160r2 - "1.3.132.0.31", // (18) secp192k1 - "1.2.840.10045.3.1.1", // (19) secp192r1, NIST P-192 - "1.3.132.0.32", // (20) secp224k1 - "1.3.132.0.33", // (21) secp224r1, NIST P-224 - "1.3.132.0.10", // (22) secp256k1 - "1.2.840.10045.3.1.7", // (23) secp256r1, NIST P-256 - "1.3.132.0.34", // (24) secp384r1, NIST P-384 - "1.3.132.0.35", // (25) secp521r1, NIST P-521 - }; - - private final static Map curveIndices; - - static { - curveIndices = new HashMap(); - for (int i = 1; i < NAMED_CURVE_OID_TABLE.length; i++) { - curveIndices.put(NAMED_CURVE_OID_TABLE[i], i); - } - } - -} - -final class SupportedEllipticPointFormatsExtension extends HelloExtension { - - final static int FMT_UNCOMPRESSED = 0; - final static int FMT_ANSIX962_COMPRESSED_PRIME = 1; - final static int FMT_ANSIX962_COMPRESSED_CHAR2 = 2; - - static final HelloExtension DEFAULT = - new SupportedEllipticPointFormatsExtension( - new byte[] {FMT_UNCOMPRESSED}); - - private final byte[] formats; - - private SupportedEllipticPointFormatsExtension(byte[] formats) { - super(ExtensionType.EXT_EC_POINT_FORMATS); - this.formats = formats; - } - - SupportedEllipticPointFormatsExtension(HandshakeInStream s, int len) - throws IOException { - super(ExtensionType.EXT_EC_POINT_FORMATS); - formats = s.getBytes8(); - // RFC 4492 says uncompressed points must always be supported. - // Check just to make sure. - boolean uncompressed = false; - for (int format : formats) { - if (format == FMT_UNCOMPRESSED) { - uncompressed = true; - break; - } - } - if (uncompressed == false) { - throw new SSLProtocolException - ("Peer does not support uncompressed points"); - } - } - - int length() { - return 5 + formats.length; - } - - void send(HandshakeOutStream s) throws IOException { - s.putInt16(type.id); - s.putInt16(formats.length + 1); - s.putBytes8(formats); - } - - private static String toString(byte format) { - int f = format & 0xff; - switch (f) { - case FMT_UNCOMPRESSED: - return "uncompressed"; - case FMT_ANSIX962_COMPRESSED_PRIME: - return "ansiX962_compressed_prime"; - case FMT_ANSIX962_COMPRESSED_CHAR2: - return "ansiX962_compressed_char2"; - default: - return "unknown-" + f; - } - } - - public String toString() { - List list = new ArrayList<>(); - for (byte format : formats) { - list.add(toString(format)); - } - return "Extension " + type + ", formats: " + list; - } -} - -/* - * For secure renegotiation, RFC5746 defines a new TLS extension, - * "renegotiation_info" (with extension type 0xff01), which contains a - * cryptographic binding to the enclosing TLS connection (if any) for - * which the renegotiation is being performed. The "extension data" - * field of this extension contains a "RenegotiationInfo" structure: - * - * struct { - * opaque renegotiated_connection<0..255>; - * } RenegotiationInfo; - */ -final class RenegotiationInfoExtension extends HelloExtension { - private final byte[] renegotiated_connection; - - RenegotiationInfoExtension(byte[] clientVerifyData, - byte[] serverVerifyData) { - super(ExtensionType.EXT_RENEGOTIATION_INFO); - - if (clientVerifyData.length != 0) { - renegotiated_connection = - new byte[clientVerifyData.length + serverVerifyData.length]; - System.arraycopy(clientVerifyData, 0, renegotiated_connection, - 0, clientVerifyData.length); - - if (serverVerifyData.length != 0) { - System.arraycopy(serverVerifyData, 0, renegotiated_connection, - clientVerifyData.length, serverVerifyData.length); - } - } else { - // ignore both the client and server verify data. - renegotiated_connection = new byte[0]; - } - } - - RenegotiationInfoExtension(HandshakeInStream s, int len) - throws IOException { - super(ExtensionType.EXT_RENEGOTIATION_INFO); - - // check the extension length - if (len < 1) { - throw new SSLProtocolException("Invalid " + type + " extension"); - } - - int renegoInfoDataLen = s.getInt8(); - if (renegoInfoDataLen + 1 != len) { // + 1 = the byte we just read - throw new SSLProtocolException("Invalid " + type + " extension"); - } - - renegotiated_connection = new byte[renegoInfoDataLen]; - if (renegoInfoDataLen != 0) { - s.read(renegotiated_connection, 0, renegoInfoDataLen); - } - } - - - // Length of the encoded extension, including the type and length fields - int length() { - return 5 + renegotiated_connection.length; - } - - void send(HandshakeOutStream s) throws IOException { - s.putInt16(type.id); - s.putInt16(renegotiated_connection.length + 1); - s.putBytes8(renegotiated_connection); - } - - boolean isEmpty() { - return renegotiated_connection.length == 0; - } - - byte[] getRenegotiatedConnection() { - return renegotiated_connection; - } - - public String toString() { - return "Extension " + type + ", renegotiated_connection: " + - (renegotiated_connection.length == 0 ? "" : - Debug.toString(renegotiated_connection)); - } - -} - -/* - * [RFC5246] The client uses the "signature_algorithms" extension to - * indicate to the server which signature/hash algorithm pairs may be - * used in digital signatures. The "extension_data" field of this - * extension contains a "supported_signature_algorithms" value. - * - * enum { - * none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5), - * sha512(6), (255) - * } HashAlgorithm; - * - * enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) } - * SignatureAlgorithm; - * - * struct { - * HashAlgorithm hash; - * SignatureAlgorithm signature; - * } SignatureAndHashAlgorithm; - * - * SignatureAndHashAlgorithm - * supported_signature_algorithms<2..2^16-2>; - */ -final class SignatureAlgorithmsExtension extends HelloExtension { - - private Collection algorithms; - private int algorithmsLen; // length of supported_signature_algorithms - - SignatureAlgorithmsExtension( - Collection signAlgs) { - - super(ExtensionType.EXT_SIGNATURE_ALGORITHMS); - - algorithms = new ArrayList(signAlgs); - algorithmsLen = - SignatureAndHashAlgorithm.sizeInRecord() * algorithms.size(); - } - - SignatureAlgorithmsExtension(HandshakeInStream s, int len) - throws IOException { - super(ExtensionType.EXT_SIGNATURE_ALGORITHMS); - - algorithmsLen = s.getInt16(); - if (algorithmsLen == 0 || algorithmsLen + 2 != len) { - throw new SSLProtocolException("Invalid " + type + " extension"); - } - - algorithms = new ArrayList(); - int remains = algorithmsLen; - int sequence = 0; - while (remains > 1) { // needs at least two bytes - int hash = s.getInt8(); // hash algorithm - int signature = s.getInt8(); // signature algorithm - - SignatureAndHashAlgorithm algorithm = - SignatureAndHashAlgorithm.valueOf(hash, signature, ++sequence); - algorithms.add(algorithm); - remains -= 2; // one byte for hash, one byte for signature - } - - if (remains != 0) { - throw new SSLProtocolException("Invalid server_name extension"); - } - } - - Collection getSignAlgorithms() { - return algorithms; - } - - @Override - int length() { - return 6 + algorithmsLen; - } - - @Override - void send(HandshakeOutStream s) throws IOException { - s.putInt16(type.id); - s.putInt16(algorithmsLen + 2); - s.putInt16(algorithmsLen); - - for (SignatureAndHashAlgorithm algorithm : algorithms) { - s.putInt8(algorithm.getHashValue()); // HashAlgorithm - s.putInt8(algorithm.getSignatureValue()); // SignatureAlgorithm - } - } - - @Override - public String toString() { - StringBuffer buffer = new StringBuffer(); - boolean opened = false; - for (SignatureAndHashAlgorithm signAlg : algorithms) { - if (opened) { - buffer.append(", " + signAlg.getAlgorithmName()); - } else { - buffer.append(signAlg.getAlgorithmName()); - opened = true; - } - } - - return "Extension " + type + ", signature_algorithms: " + buffer; - } -} diff --git a/jdk/src/share/classes/sun/security/ssl/RenegotiationInfoExtension.java b/jdk/src/share/classes/sun/security/ssl/RenegotiationInfoExtension.java new file mode 100644 index 00000000000..400b2e3682d --- /dev/null +++ b/jdk/src/share/classes/sun/security/ssl/RenegotiationInfoExtension.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +import java.io.IOException; + +import javax.net.ssl.SSLProtocolException; + +/* + * For secure renegotiation, RFC5746 defines a new TLS extension, + * "renegotiation_info" (with extension type 0xff01), which contains a + * cryptographic binding to the enclosing TLS connection (if any) for + * which the renegotiation is being performed. The "extension data" + * field of this extension contains a "RenegotiationInfo" structure: + * + * struct { + * opaque renegotiated_connection<0..255>; + * } RenegotiationInfo; + */ +final class RenegotiationInfoExtension extends HelloExtension { + private final byte[] renegotiated_connection; + + RenegotiationInfoExtension(byte[] clientVerifyData, + byte[] serverVerifyData) { + super(ExtensionType.EXT_RENEGOTIATION_INFO); + + if (clientVerifyData.length != 0) { + renegotiated_connection = + new byte[clientVerifyData.length + serverVerifyData.length]; + System.arraycopy(clientVerifyData, 0, renegotiated_connection, + 0, clientVerifyData.length); + + if (serverVerifyData.length != 0) { + System.arraycopy(serverVerifyData, 0, renegotiated_connection, + clientVerifyData.length, serverVerifyData.length); + } + } else { + // ignore both the client and server verify data. + renegotiated_connection = new byte[0]; + } + } + + RenegotiationInfoExtension(HandshakeInStream s, int len) + throws IOException { + super(ExtensionType.EXT_RENEGOTIATION_INFO); + + // check the extension length + if (len < 1) { + throw new SSLProtocolException("Invalid " + type + " extension"); + } + + int renegoInfoDataLen = s.getInt8(); + if (renegoInfoDataLen + 1 != len) { // + 1 = the byte we just read + throw new SSLProtocolException("Invalid " + type + " extension"); + } + + renegotiated_connection = new byte[renegoInfoDataLen]; + if (renegoInfoDataLen != 0) { + s.read(renegotiated_connection, 0, renegoInfoDataLen); + } + } + + + // Length of the encoded extension, including the type and length fields + int length() { + return 5 + renegotiated_connection.length; + } + + void send(HandshakeOutStream s) throws IOException { + s.putInt16(type.id); + s.putInt16(renegotiated_connection.length + 1); + s.putBytes8(renegotiated_connection); + } + + boolean isEmpty() { + return renegotiated_connection.length == 0; + } + + byte[] getRenegotiatedConnection() { + return renegotiated_connection; + } + + public String toString() { + return "Extension " + type + ", renegotiated_connection: " + + (renegotiated_connection.length == 0 ? "" : + Debug.toString(renegotiated_connection)); + } + +} diff --git a/jdk/src/share/classes/sun/security/ssl/ServerNameExtension.java b/jdk/src/share/classes/sun/security/ssl/ServerNameExtension.java new file mode 100644 index 00000000000..ad251822ca1 --- /dev/null +++ b/jdk/src/share/classes/sun/security/ssl/ServerNameExtension.java @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.LinkedHashMap; +import java.util.Map; + +import javax.net.ssl.SNIHostName; +import javax.net.ssl.SNIMatcher; +import javax.net.ssl.SNIServerName; +import javax.net.ssl.SSLProtocolException; +import javax.net.ssl.StandardConstants; + +/* + * [RFC 4366/6066] To facilitate secure connections to servers that host + * multiple 'virtual' servers at a single underlying network address, clients + * MAY include an extension of type "server_name" in the (extended) client + * hello. The "extension_data" field of this extension SHALL contain + * "ServerNameList" where: + * + * struct { + * NameType name_type; + * select (name_type) { + * case host_name: HostName; + * } name; + * } ServerName; + * + * enum { + * host_name(0), (255) + * } NameType; + * + * opaque HostName<1..2^16-1>; + * + * struct { + * ServerName server_name_list<1..2^16-1> + * } ServerNameList; + */ +final class ServerNameExtension extends HelloExtension { + + // For backward compatibility, all future data structures associated with + // new NameTypes MUST begin with a 16-bit length field. + final static int NAME_HEADER_LENGTH = 3; // NameType: 1 byte + // Name length: 2 bytes + private Map sniMap; + private int listLength; // ServerNameList length + + // constructor for ServerHello + ServerNameExtension() throws IOException { + super(ExtensionType.EXT_SERVER_NAME); + + listLength = 0; + sniMap = Collections.emptyMap(); + } + + // constructor for ClientHello + ServerNameExtension(List serverNames) + throws IOException { + super(ExtensionType.EXT_SERVER_NAME); + + listLength = 0; + sniMap = new LinkedHashMap<>(); + for (SNIServerName serverName : serverNames) { + // check for duplicated server name type + if (sniMap.put(serverName.getType(), serverName) != null) { + // unlikely to happen, but in case ... + throw new RuntimeException( + "Duplicated server name of type " + serverName.getType()); + } + + listLength += serverName.getEncoded().length + NAME_HEADER_LENGTH; + } + + // This constructor is used for ClientHello only. Empty list is + // not allowed in client mode. + if (listLength == 0) { + throw new RuntimeException("The ServerNameList cannot be empty"); + } + } + + // constructor for ServerHello for parsing SNI extension + ServerNameExtension(HandshakeInStream s, int len) + throws IOException { + super(ExtensionType.EXT_SERVER_NAME); + + int remains = len; + if (len >= 2) { // "server_name" extension in ClientHello + listLength = s.getInt16(); // ServerNameList length + if (listLength == 0 || listLength + 2 != len) { + throw new SSLProtocolException( + "Invalid " + type + " extension"); + } + + remains -= 2; + sniMap = new LinkedHashMap<>(); + while (remains > 0) { + int code = s.getInt8(); // NameType + + // HostName (length read in getBytes16); + byte[] encoded = s.getBytes16(); + SNIServerName serverName; + switch (code) { + case StandardConstants.SNI_HOST_NAME: + if (encoded.length == 0) { + throw new SSLProtocolException( + "Empty HostName in server name indication"); + } + try { + serverName = new SNIHostName(encoded); + } catch (IllegalArgumentException iae) { + SSLProtocolException spe = new SSLProtocolException( + "Illegal server name, type=host_name(" + + code + "), name=" + + (new String(encoded, StandardCharsets.UTF_8)) + + ", value=" + Debug.toString(encoded)); + spe.initCause(iae); + throw spe; + } + break; + default: + try { + serverName = new UnknownServerName(code, encoded); + } catch (IllegalArgumentException iae) { + SSLProtocolException spe = new SSLProtocolException( + "Illegal server name, type=(" + code + + "), value=" + Debug.toString(encoded)); + spe.initCause(iae); + throw spe; + } + } + // check for duplicated server name type + if (sniMap.put(serverName.getType(), serverName) != null) { + throw new SSLProtocolException( + "Duplicated server name of type " + + serverName.getType()); + } + + remains -= encoded.length + NAME_HEADER_LENGTH; + } + } else if (len == 0) { // "server_name" extension in ServerHello + listLength = 0; + sniMap = Collections.emptyMap(); + } + + if (remains != 0) { + throw new SSLProtocolException("Invalid server_name extension"); + } + } + + List getServerNames() { + if (sniMap != null && !sniMap.isEmpty()) { + return Collections.unmodifiableList( + new ArrayList<>(sniMap.values())); + } + + return Collections.emptyList(); + } + + /* + * Is the extension recognized by the corresponding matcher? + * + * This method is used to check whether the server name indication can + * be recognized by the server name matchers. + * + * Per RFC 6066, if the server understood the ClientHello extension but + * does not recognize the server name, the server SHOULD take one of two + * actions: either abort the handshake by sending a fatal-level + * unrecognized_name(112) alert or continue the handshake. + * + * If there is an instance of SNIMatcher defined for a particular name + * type, it must be used to perform match operations on the server name. + */ + boolean isMatched(Collection matchers) { + if (sniMap != null && !sniMap.isEmpty()) { + for (SNIMatcher matcher : matchers) { + SNIServerName sniName = sniMap.get(matcher.getType()); + if (sniName != null && (!matcher.matches(sniName))) { + return false; + } + } + } + + return true; + } + + /* + * Is the extension is identical to a server name list? + * + * This method is used to check the server name indication during session + * resumption. + * + * Per RFC 6066, when the server is deciding whether or not to accept a + * request to resume a session, the contents of a server_name extension + * MAY be used in the lookup of the session in the session cache. The + * client SHOULD include the same server_name extension in the session + * resumption request as it did in the full handshake that established + * the session. A server that implements this extension MUST NOT accept + * the request to resume the session if the server_name extension contains + * a different name. Instead, it proceeds with a full handshake to + * establish a new session. When resuming a session, the server MUST NOT + * include a server_name extension in the server hello. + */ + boolean isIdentical(List other) { + if (other.size() == sniMap.size()) { + for(SNIServerName sniInOther : other) { + SNIServerName sniName = sniMap.get(sniInOther.getType()); + if (sniName == null || !sniInOther.equals(sniName)) { + return false; + } + } + + return true; + } + + return false; + } + + int length() { + return listLength == 0 ? 4 : 6 + listLength; + } + + void send(HandshakeOutStream s) throws IOException { + s.putInt16(type.id); + if (listLength == 0) { + s.putInt16(listLength); // in ServerHello, empty extension_data + } else { + s.putInt16(listLength + 2); // length of extension_data + s.putInt16(listLength); // length of ServerNameList + + for (SNIServerName sniName : sniMap.values()) { + s.putInt8(sniName.getType()); // server name type + s.putBytes16(sniName.getEncoded()); // server name value + } + } + } + + public String toString() { + StringBuffer buffer = new StringBuffer(); + for (SNIServerName sniName : sniMap.values()) { + buffer.append("[" + sniName + "]"); + } + + return "Extension " + type + ", server_name: " + buffer; + } + + private static class UnknownServerName extends SNIServerName { + UnknownServerName(int code, byte[] encoded) { + super(code, encoded); + } + } + +} diff --git a/jdk/src/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java b/jdk/src/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java new file mode 100644 index 00000000000..8fccf7cbf6d --- /dev/null +++ b/jdk/src/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; + +import javax.net.ssl.SSLProtocolException; + +/* + * [RFC5246] The client uses the "signature_algorithms" extension to + * indicate to the server which signature/hash algorithm pairs may be + * used in digital signatures. The "extension_data" field of this + * extension contains a "supported_signature_algorithms" value. + * + * enum { + * none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5), + * sha512(6), (255) + * } HashAlgorithm; + * + * enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) } + * SignatureAlgorithm; + * + * struct { + * HashAlgorithm hash; + * SignatureAlgorithm signature; + * } SignatureAndHashAlgorithm; + * + * SignatureAndHashAlgorithm + * supported_signature_algorithms<2..2^16-2>; + */ +final class SignatureAlgorithmsExtension extends HelloExtension { + + private Collection algorithms; + private int algorithmsLen; // length of supported_signature_algorithms + + SignatureAlgorithmsExtension( + Collection signAlgs) { + + super(ExtensionType.EXT_SIGNATURE_ALGORITHMS); + + algorithms = new ArrayList(signAlgs); + algorithmsLen = + SignatureAndHashAlgorithm.sizeInRecord() * algorithms.size(); + } + + SignatureAlgorithmsExtension(HandshakeInStream s, int len) + throws IOException { + super(ExtensionType.EXT_SIGNATURE_ALGORITHMS); + + algorithmsLen = s.getInt16(); + if (algorithmsLen == 0 || algorithmsLen + 2 != len) { + throw new SSLProtocolException("Invalid " + type + " extension"); + } + + algorithms = new ArrayList(); + int remains = algorithmsLen; + int sequence = 0; + while (remains > 1) { // needs at least two bytes + int hash = s.getInt8(); // hash algorithm + int signature = s.getInt8(); // signature algorithm + + SignatureAndHashAlgorithm algorithm = + SignatureAndHashAlgorithm.valueOf(hash, signature, ++sequence); + algorithms.add(algorithm); + remains -= 2; // one byte for hash, one byte for signature + } + + if (remains != 0) { + throw new SSLProtocolException("Invalid server_name extension"); + } + } + + Collection getSignAlgorithms() { + return algorithms; + } + + @Override + int length() { + return 6 + algorithmsLen; + } + + @Override + void send(HandshakeOutStream s) throws IOException { + s.putInt16(type.id); + s.putInt16(algorithmsLen + 2); + s.putInt16(algorithmsLen); + + for (SignatureAndHashAlgorithm algorithm : algorithms) { + s.putInt8(algorithm.getHashValue()); // HashAlgorithm + s.putInt8(algorithm.getSignatureValue()); // SignatureAlgorithm + } + } + + @Override + public String toString() { + StringBuffer buffer = new StringBuffer(); + boolean opened = false; + for (SignatureAndHashAlgorithm signAlg : algorithms) { + if (opened) { + buffer.append(", " + signAlg.getAlgorithmName()); + } else { + buffer.append(signAlg.getAlgorithmName()); + opened = true; + } + } + + return "Extension " + type + ", signature_algorithms: " + buffer; + } +} + diff --git a/jdk/src/share/classes/sun/security/ssl/SupportedEllipticCurvesExtension.java b/jdk/src/share/classes/sun/security/ssl/SupportedEllipticCurvesExtension.java new file mode 100644 index 00000000000..f9d01120970 --- /dev/null +++ b/jdk/src/share/classes/sun/security/ssl/SupportedEllipticCurvesExtension.java @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +import java.io.IOException; +import java.security.spec.ECParameterSpec; +import java.util.HashMap; +import java.util.Map; + +import javax.net.ssl.SSLProtocolException; + +final class SupportedEllipticCurvesExtension extends HelloExtension { + + // the extension value to send in the ClientHello message + static final SupportedEllipticCurvesExtension DEFAULT; + + private static final boolean fips; + + static { + int[] ids; + fips = SunJSSE.isFIPS(); + if (fips == false) { + ids = new int[] { + // NIST curves first + // prefer NIST P-256, rest in order of increasing key length + 23, 1, 3, 19, 21, 6, 7, 9, 10, 24, 11, 12, 25, 13, 14, + // non-NIST curves + 15, 16, 17, 2, 18, 4, 5, 20, 8, 22, + }; + } else { + ids = new int[] { + // same as above, but allow only NIST curves in FIPS mode + 23, 1, 3, 19, 21, 6, 7, 9, 10, 24, 11, 12, 25, 13, 14, + }; + } + DEFAULT = new SupportedEllipticCurvesExtension(ids); + } + + private final int[] curveIds; + + private SupportedEllipticCurvesExtension(int[] curveIds) { + super(ExtensionType.EXT_ELLIPTIC_CURVES); + this.curveIds = curveIds; + } + + SupportedEllipticCurvesExtension(HandshakeInStream s, int len) + throws IOException { + super(ExtensionType.EXT_ELLIPTIC_CURVES); + int k = s.getInt16(); + if (((len & 1) != 0) || (k + 2 != len)) { + throw new SSLProtocolException("Invalid " + type + " extension"); + } + curveIds = new int[k >> 1]; + for (int i = 0; i < curveIds.length; i++) { + curveIds[i] = s.getInt16(); + } + } + + boolean contains(int index) { + for (int curveId : curveIds) { + if (index == curveId) { + return true; + } + } + return false; + } + + // Return a reference to the internal curveIds array. + // The caller must NOT modify the contents. + int[] curveIds() { + return curveIds; + } + + int length() { + return 6 + (curveIds.length << 1); + } + + void send(HandshakeOutStream s) throws IOException { + s.putInt16(type.id); + int k = curveIds.length << 1; + s.putInt16(k + 2); + s.putInt16(k); + for (int curveId : curveIds) { + s.putInt16(curveId); + } + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("Extension " + type + ", curve names: {"); + boolean first = true; + for (int curveId : curveIds) { + if (first) { + first = false; + } else { + sb.append(", "); + } + // first check if it is a known named curve, then try other cases. + String oid = getCurveOid(curveId); + if (oid != null) { + ECParameterSpec spec = JsseJce.getECParameterSpec(oid); + // this toString() output will look nice for the current + // implementation of the ECParameterSpec class in the Sun + // provider, but may not look good for other implementations. + if (spec != null) { + sb.append(spec.toString().split(" ")[0]); + } else { + sb.append(oid); + } + } else if (curveId == ARBITRARY_PRIME) { + sb.append("arbitrary_explicit_prime_curves"); + } else if (curveId == ARBITRARY_CHAR2) { + sb.append("arbitrary_explicit_char2_curves"); + } else { + sb.append("unknown curve " + curveId); + } + } + sb.append("}"); + return sb.toString(); + } + + // Test whether we support the curve with the given index. + static boolean isSupported(int index) { + if ((index <= 0) || (index >= NAMED_CURVE_OID_TABLE.length)) { + return false; + } + if (fips == false) { + // in non-FIPS mode, we support all valid indices + return true; + } + return DEFAULT.contains(index); + } + + static int getCurveIndex(ECParameterSpec params) { + String oid = JsseJce.getNamedCurveOid(params); + if (oid == null) { + return -1; + } + Integer n = curveIndices.get(oid); + return (n == null) ? -1 : n; + } + + static String getCurveOid(int index) { + if ((index > 0) && (index < NAMED_CURVE_OID_TABLE.length)) { + return NAMED_CURVE_OID_TABLE[index]; + } + return null; + } + + private final static int ARBITRARY_PRIME = 0xff01; + private final static int ARBITRARY_CHAR2 = 0xff02; + + // See sun.security.ec.NamedCurve for the OIDs + private final static String[] NAMED_CURVE_OID_TABLE = new String[] { + null, // (0) unused + "1.3.132.0.1", // (1) sect163k1, NIST K-163 + "1.3.132.0.2", // (2) sect163r1 + "1.3.132.0.15", // (3) sect163r2, NIST B-163 + "1.3.132.0.24", // (4) sect193r1 + "1.3.132.0.25", // (5) sect193r2 + "1.3.132.0.26", // (6) sect233k1, NIST K-233 + "1.3.132.0.27", // (7) sect233r1, NIST B-233 + "1.3.132.0.3", // (8) sect239k1 + "1.3.132.0.16", // (9) sect283k1, NIST K-283 + "1.3.132.0.17", // (10) sect283r1, NIST B-283 + "1.3.132.0.36", // (11) sect409k1, NIST K-409 + "1.3.132.0.37", // (12) sect409r1, NIST B-409 + "1.3.132.0.38", // (13) sect571k1, NIST K-571 + "1.3.132.0.39", // (14) sect571r1, NIST B-571 + "1.3.132.0.9", // (15) secp160k1 + "1.3.132.0.8", // (16) secp160r1 + "1.3.132.0.30", // (17) secp160r2 + "1.3.132.0.31", // (18) secp192k1 + "1.2.840.10045.3.1.1", // (19) secp192r1, NIST P-192 + "1.3.132.0.32", // (20) secp224k1 + "1.3.132.0.33", // (21) secp224r1, NIST P-224 + "1.3.132.0.10", // (22) secp256k1 + "1.2.840.10045.3.1.7", // (23) secp256r1, NIST P-256 + "1.3.132.0.34", // (24) secp384r1, NIST P-384 + "1.3.132.0.35", // (25) secp521r1, NIST P-521 + }; + + private final static Map curveIndices; + + static { + curveIndices = new HashMap(); + for (int i = 1; i < NAMED_CURVE_OID_TABLE.length; i++) { + curveIndices.put(NAMED_CURVE_OID_TABLE[i], i); + } + } + +} diff --git a/jdk/src/share/classes/sun/security/ssl/SupportedEllipticPointFormatsExtension.java b/jdk/src/share/classes/sun/security/ssl/SupportedEllipticPointFormatsExtension.java new file mode 100644 index 00000000000..427a869cb3b --- /dev/null +++ b/jdk/src/share/classes/sun/security/ssl/SupportedEllipticPointFormatsExtension.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import javax.net.ssl.SSLProtocolException; + +final class SupportedEllipticPointFormatsExtension extends HelloExtension { + + final static int FMT_UNCOMPRESSED = 0; + final static int FMT_ANSIX962_COMPRESSED_PRIME = 1; + final static int FMT_ANSIX962_COMPRESSED_CHAR2 = 2; + + static final HelloExtension DEFAULT = + new SupportedEllipticPointFormatsExtension( + new byte[] {FMT_UNCOMPRESSED}); + + private final byte[] formats; + + private SupportedEllipticPointFormatsExtension(byte[] formats) { + super(ExtensionType.EXT_EC_POINT_FORMATS); + this.formats = formats; + } + + SupportedEllipticPointFormatsExtension(HandshakeInStream s, int len) + throws IOException { + super(ExtensionType.EXT_EC_POINT_FORMATS); + formats = s.getBytes8(); + // RFC 4492 says uncompressed points must always be supported. + // Check just to make sure. + boolean uncompressed = false; + for (int format : formats) { + if (format == FMT_UNCOMPRESSED) { + uncompressed = true; + break; + } + } + if (uncompressed == false) { + throw new SSLProtocolException + ("Peer does not support uncompressed points"); + } + } + + int length() { + return 5 + formats.length; + } + + void send(HandshakeOutStream s) throws IOException { + s.putInt16(type.id); + s.putInt16(formats.length + 1); + s.putBytes8(formats); + } + + private static String toString(byte format) { + int f = format & 0xff; + switch (f) { + case FMT_UNCOMPRESSED: + return "uncompressed"; + case FMT_ANSIX962_COMPRESSED_PRIME: + return "ansiX962_compressed_prime"; + case FMT_ANSIX962_COMPRESSED_CHAR2: + return "ansiX962_compressed_char2"; + default: + return "unknown-" + f; + } + } + + public String toString() { + List list = new ArrayList(); + for (byte format : formats) { + list.add(toString(format)); + } + return "Extension " + type + ", formats: " + list; + } +} diff --git a/jdk/src/share/classes/sun/security/ssl/UnknownExtension.java b/jdk/src/share/classes/sun/security/ssl/UnknownExtension.java new file mode 100644 index 00000000000..7b1585dcb20 --- /dev/null +++ b/jdk/src/share/classes/sun/security/ssl/UnknownExtension.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +import java.io.IOException; + +final class UnknownExtension extends HelloExtension { + + private final byte[] data; + + UnknownExtension(HandshakeInStream s, int len, ExtensionType type) + throws IOException { + super(type); + data = new byte[len]; + // s.read() does not handle 0-length arrays. + if (len != 0) { + s.read(data); + } + } + + int length() { + return 4 + data.length; + } + + void send(HandshakeOutStream s) throws IOException { + s.putInt16(type.id); + s.putBytes16(data); + } + + public String toString() { + return "Unsupported extension " + type + ", data: " + + Debug.toString(data); + } +} diff --git a/jdk/src/solaris/classes/sun/awt/X11/XChoicePeer.java b/jdk/src/solaris/classes/sun/awt/X11/XChoicePeer.java index 4f8a367366b..a9fc4969875 100644 --- a/jdk/src/solaris/classes/sun/awt/X11/XChoicePeer.java +++ b/jdk/src/solaris/classes/sun/awt/X11/XChoicePeer.java @@ -1108,17 +1108,3 @@ public class XChoicePeer extends XComponentPeer implements ChoicePeer, ToplevelS return true; } } - -/* - * The listener interface for receiving "interesting" for XFileDialogPeer - * choice events (opening, closing). - * The listener added by means of the method addXChoicePeerListener - * A opening choice event is generated when the invoking unfurledChoice.toFront() - * A closing choice event is generated at the time of the processing the mouse releasing - * and the Enter pressing. - * see 6240074 for more information - */ -interface XChoicePeerListener{ - public void unfurledChoiceOpening(ListHelper choiceHelper); - public void unfurledChoiceClosing(); -} diff --git a/jdk/src/solaris/classes/sun/awt/X11/XChoicePeerListener.java b/jdk/src/solaris/classes/sun/awt/X11/XChoicePeerListener.java new file mode 100644 index 00000000000..775b1aab0e8 --- /dev/null +++ b/jdk/src/solaris/classes/sun/awt/X11/XChoicePeerListener.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.awt.X11; + +/* + * The listener interface for receiving "interesting" for XFileDialogPeer + * choice events (opening, closing). + * The listener added by means of the method addXChoicePeerListener + * A opening choice event is generated when the invoking unfurledChoice.toFront() + * A closing choice event is generated at the time of the processing the mouse releasing + * and the Enter pressing. + * see 6240074 for more information + */ +interface XChoicePeerListener{ + public void unfurledChoiceOpening(ListHelper choiceHelper); + public void unfurledChoiceClosing(); +} diff --git a/jdk/src/solaris/classes/sun/font/DelegateStrike.java b/jdk/src/solaris/classes/sun/font/DelegateStrike.java new file mode 100644 index 00000000000..1e9ba8ccbc6 --- /dev/null +++ b/jdk/src/solaris/classes/sun/font/DelegateStrike.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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.font; + +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; +import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; + +/* Returned instead of a NativeStrike. + * It can intercept any request it wants, but mostly + * passes them on to its delegate strike. It is important that + * it override all the inherited FontStrike methods to delegate them + * appropriately. + */ + +class DelegateStrike extends NativeStrike { + + private FontStrike delegateStrike; + + DelegateStrike(NativeFont nativeFont, FontStrikeDesc desc, + FontStrike delegate) { + super(nativeFont, desc); + this.delegateStrike = delegate; + } + + /* We want the native font to be responsible for reporting the + * font metrics, even if it often delegates to another font. + * The code here isn't yet implementing exactly that. If the glyph + * transform was something native couldn't handle, there's no native + * context from which to obtain metrics. Need to revise this to obtain + * the metrics and transform them. But currently in such a case it + * gets the metrics from a different font - its glyph delegate font. + */ + StrikeMetrics getFontMetrics() { + if (strikeMetrics == null) { + if (pScalerContext != 0) { + strikeMetrics = super.getFontMetrics(); + } + if (strikeMetrics == null) { + strikeMetrics = delegateStrike.getFontMetrics(); + } + } + return strikeMetrics; + } + + void getGlyphImagePtrs(int[] glyphCodes, long[] images,int len) { + delegateStrike.getGlyphImagePtrs(glyphCodes, images, len); + } + + long getGlyphImagePtr(int glyphCode) { + return delegateStrike.getGlyphImagePtr(glyphCode); + } + + void getGlyphImageBounds(int glyphCode, + Point2D.Float pt, Rectangle result) { + delegateStrike.getGlyphImageBounds(glyphCode, pt, result); + } + + Point2D.Float getGlyphMetrics(int glyphCode) { + return delegateStrike.getGlyphMetrics(glyphCode); + } + + float getGlyphAdvance(int glyphCode) { + return delegateStrike.getGlyphAdvance(glyphCode); + } + + Point2D.Float getCharMetrics(char ch) { + return delegateStrike.getCharMetrics(ch); + } + + float getCodePointAdvance(int cp) { + if (cp < 0 || cp >= 0x10000) { + cp = 0xffff; + } + return delegateStrike.getGlyphAdvance(cp); + } + + Rectangle2D.Float getGlyphOutlineBounds(int glyphCode) { + return delegateStrike.getGlyphOutlineBounds(glyphCode); + } + + GeneralPath getGlyphOutline(int glyphCode, float x, float y) { + return delegateStrike.getGlyphOutline(glyphCode, x, y); + } + + GeneralPath getGlyphVectorOutline(int[] glyphs, float x, float y) { + return delegateStrike.getGlyphVectorOutline(glyphs, x, y); + } + +} diff --git a/jdk/src/solaris/classes/sun/font/NativeStrike.java b/jdk/src/solaris/classes/sun/font/NativeStrike.java index 777f31351f6..f325ddd90e8 100644 --- a/jdk/src/solaris/classes/sun/font/NativeStrike.java +++ b/jdk/src/solaris/classes/sun/font/NativeStrike.java @@ -32,7 +32,7 @@ import java.awt.Rectangle; import java.awt.geom.Rectangle2D; import java.awt.geom.NoninvertibleTransformException; - class NativeStrike extends PhysicalStrike { +class NativeStrike extends PhysicalStrike { NativeFont nativeFont; int numGlyphs; @@ -294,86 +294,3 @@ import java.awt.geom.NoninvertibleTransformException; } } - -/* Returned instead of a NativeStrike. - * It can intercept any request it wants, but mostly - * passes them on to its delegate strike. It is important that - * it override all the inherited FontStrike methods to delegate them - * appropriately. - */ - -class DelegateStrike extends NativeStrike { - - private FontStrike delegateStrike; - - DelegateStrike(NativeFont nativeFont, FontStrikeDesc desc, - FontStrike delegate) { - super(nativeFont, desc); - this.delegateStrike = delegate; - } - - /* We want the native font to be responsible for reporting the - * font metrics, even if it often delegates to another font. - * The code here isn't yet implementing exactly that. If the glyph - * transform was something native couldn't handle, there's no native - * context from which to obtain metrics. Need to revise this to obtain - * the metrics and transform them. But currently in such a case it - * gets the metrics from a different font - its glyph delegate font. - */ - StrikeMetrics getFontMetrics() { - if (strikeMetrics == null) { - if (pScalerContext != 0) { - strikeMetrics = super.getFontMetrics(); - } - if (strikeMetrics == null) { - strikeMetrics = delegateStrike.getFontMetrics(); - } - } - return strikeMetrics; - } - - void getGlyphImagePtrs(int[] glyphCodes, long[] images,int len) { - delegateStrike.getGlyphImagePtrs(glyphCodes, images, len); - } - - long getGlyphImagePtr(int glyphCode) { - return delegateStrike.getGlyphImagePtr(glyphCode); - } - - void getGlyphImageBounds(int glyphCode, - Point2D.Float pt, Rectangle result) { - delegateStrike.getGlyphImageBounds(glyphCode, pt, result); - } - - Point2D.Float getGlyphMetrics(int glyphCode) { - return delegateStrike.getGlyphMetrics(glyphCode); - } - - float getGlyphAdvance(int glyphCode) { - return delegateStrike.getGlyphAdvance(glyphCode); - } - - Point2D.Float getCharMetrics(char ch) { - return delegateStrike.getCharMetrics(ch); - } - - float getCodePointAdvance(int cp) { - if (cp < 0 || cp >= 0x10000) { - cp = 0xffff; - } - return delegateStrike.getGlyphAdvance(cp); - } - - Rectangle2D.Float getGlyphOutlineBounds(int glyphCode) { - return delegateStrike.getGlyphOutlineBounds(glyphCode); - } - - GeneralPath getGlyphOutline(int glyphCode, float x, float y) { - return delegateStrike.getGlyphOutline(glyphCode, x, y); - } - - GeneralPath getGlyphVectorOutline(int[] glyphs, float x, float y) { - return delegateStrike.getGlyphVectorOutline(glyphs, x, y); - } - -} diff --git a/jdk/src/solaris/classes/sun/java2d/jules/JulesAATileGenerator.java b/jdk/src/solaris/classes/sun/java2d/jules/JulesAATileGenerator.java index 12af979197a..809ef99b119 100644 --- a/jdk/src/solaris/classes/sun/java2d/jules/JulesAATileGenerator.java +++ b/jdk/src/solaris/classes/sun/java2d/jules/JulesAATileGenerator.java @@ -326,24 +326,3 @@ public class JulesAATileGenerator implements AATileGenerator { return tiledTrapArray[index]; } } - -class TileTrapContainer { - int tileAlpha; - GrowableIntArray traps; - - public TileTrapContainer(GrowableIntArray traps) { - this.traps = traps; - } - - public void setTileAlpha(int tileAlpha) { - this.tileAlpha = tileAlpha; - } - - public int getTileAlpha() { - return tileAlpha; - } - - public GrowableIntArray getTraps() { - return traps; - } -} diff --git a/jdk/src/solaris/classes/sun/java2d/jules/TileTrapContainer.java b/jdk/src/solaris/classes/sun/java2d/jules/TileTrapContainer.java new file mode 100644 index 00000000000..80dfbd4f577 --- /dev/null +++ b/jdk/src/solaris/classes/sun/java2d/jules/TileTrapContainer.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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.java2d.jules; + +import sun.java2d.xr.GrowableIntArray; + +class TileTrapContainer { + int tileAlpha; + GrowableIntArray traps; + + public TileTrapContainer(GrowableIntArray traps) { + this.traps = traps; + } + + public void setTileAlpha(int tileAlpha) { + this.tileAlpha = tileAlpha; + } + + public int getTileAlpha() { + return tileAlpha; + } + + public GrowableIntArray getTraps() { + return traps; + } +} From 1203231cf954fd4097419f72fb7c7544f8cd044b Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Mon, 29 Oct 2012 10:42:41 -0700 Subject: [PATCH 24/59] 8000997: Multiple locale sensitive services cannot be loaded Reviewed-by: okutsu --- .../provider/LocaleServiceProviderPool.java | 2 +- .../provider/SPILocaleProviderAdapter.java | 504 +++++++++++++++++- .../CurrencyNameProviderTest.java | 30 +- .../CurrencyNameProviderTest.sh | 2 +- .../util/PluggableLocale/GenericTest.java | 2 + .../java/util/PluggableLocale/barprovider.jar | Bin 12810 -> 13747 bytes .../CurrencyNameProviderImpl2.java | 63 +++ .../util/PluggableLocale/providersrc/Makefile | 1 + .../java.util.spi.CurrencyNameProvider | 1 + 9 files changed, 595 insertions(+), 10 deletions(-) create mode 100644 jdk/test/java/util/PluggableLocale/providersrc/CurrencyNameProviderImpl2.java diff --git a/jdk/src/share/classes/sun/util/locale/provider/LocaleServiceProviderPool.java b/jdk/src/share/classes/sun/util/locale/provider/LocaleServiceProviderPool.java index 71e6b425887..2683b7dd62b 100644 --- a/jdk/src/share/classes/sun/util/locale/provider/LocaleServiceProviderPool.java +++ b/jdk/src/share/classes/sun/util/locale/provider/LocaleServiceProviderPool.java @@ -356,7 +356,7 @@ public final class LocaleServiceProviderPool { * @param locale the input locale * @return the list of candidate locales for the given locale */ - private static List getLookupLocales(Locale locale) { + static List getLookupLocales(Locale locale) { // Note: We currently use the default implementation of // ResourceBundle.Control.getCandidateLocales. The result // returned by getCandidateLocales are already normalized diff --git a/jdk/src/share/classes/sun/util/locale/provider/SPILocaleProviderAdapter.java b/jdk/src/share/classes/sun/util/locale/provider/SPILocaleProviderAdapter.java index 0f123c5d51b..cb4f9aee7de 100644 --- a/jdk/src/share/classes/sun/util/locale/provider/SPILocaleProviderAdapter.java +++ b/jdk/src/share/classes/sun/util/locale/provider/SPILocaleProviderAdapter.java @@ -28,8 +28,11 @@ package sun.util.locale.provider; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; -import java.util.ServiceLoader; -import java.util.spi.LocaleServiceProvider; +import java.text.*; +import java.text.spi.*; +import java.util.*; +import java.util.concurrent.*; +import java.util.spi.*; /** * LocaleProviderAdapter implementation for the installed SPI implementations. @@ -54,11 +57,28 @@ public class SPILocaleProviderAdapter extends AuxLocaleProviderAdapter { @Override @SuppressWarnings("unchecked") public P run() { - P lsp = null; + P delegate = null; + for (LocaleServiceProvider provider : ServiceLoader.loadInstalled(c)) { - lsp = (P) provider; + if (delegate == null) { + try { + delegate = + (P) Class.forName(SPILocaleProviderAdapter.class.getCanonicalName() + + "$" + + c.getSimpleName() + + "Delegate") + .newInstance(); + } catch (ClassNotFoundException | + InstantiationException | + IllegalAccessException e) { + LocaleServiceProviderPool.config(SPILocaleProviderAdapter.class, e.toString()); + return null; } - return lsp; + } + + ((Delegate)delegate).addImpl(provider); + } + return delegate; } }); } catch (PrivilegedActionException e) { @@ -66,4 +86,478 @@ public class SPILocaleProviderAdapter extends AuxLocaleProviderAdapter { } return null; } + + /* + * Delegate interface. All the implementations have to have the class name + * following "Delegate" convention. + */ + interface Delegate

                      { + public void addImpl(P impl); + public P getImpl(Locale locale); +} + + /* + * Obtain the real SPI implementation, using locale fallback + */ + private static

                      P getImpl(Map map, Locale locale) { + for (Locale l : LocaleServiceProviderPool.getLookupLocales(locale)) { + P ret = map.get(l); + if (ret != null) { + return ret; + } + } + return null; + } + + /* + * Delegates for the actual SPI implementations. + */ + static class BreakIteratorProviderDelegate extends BreakIteratorProvider + implements Delegate { + private ConcurrentMap map = new ConcurrentHashMap<>(); + + @Override + public void addImpl(BreakIteratorProvider impl) { + for (Locale l : impl.getAvailableLocales()) { + map.put(l, impl); + } + } + + @Override + public BreakIteratorProvider getImpl(Locale locale) { + return SPILocaleProviderAdapter.getImpl(map, locale); + } + + @Override + public Locale[] getAvailableLocales() { + return map.keySet().toArray(new Locale[0]); + } + + @Override + public boolean isSupportedLocale(Locale locale) { + return map.containsKey(locale); + } + + @Override + public BreakIterator getWordInstance(Locale locale) { + BreakIteratorProvider bip = getImpl(locale); + assert bip != null; + return bip.getWordInstance(locale); + } + + @Override + public BreakIterator getLineInstance(Locale locale) { + BreakIteratorProvider bip = getImpl(locale); + assert bip != null; + return bip.getLineInstance(locale); + } + + @Override + public BreakIterator getCharacterInstance(Locale locale) { + BreakIteratorProvider bip = getImpl(locale); + assert bip != null; + return bip.getCharacterInstance(locale); + } + + @Override + public BreakIterator getSentenceInstance(Locale locale) { + BreakIteratorProvider bip = getImpl(locale); + assert bip != null; + return bip.getSentenceInstance(locale); + } + + } + + static class CollatorProviderDelegate extends CollatorProvider implements Delegate { + private ConcurrentMap map = new ConcurrentHashMap<>(); + + @Override + public void addImpl(CollatorProvider impl) { + for (Locale l : impl.getAvailableLocales()) { + map.put(l, impl); + } + } + + @Override + public CollatorProvider getImpl(Locale locale) { + return SPILocaleProviderAdapter.getImpl(map, locale); + } + + @Override + public Locale[] getAvailableLocales() { + return map.keySet().toArray(new Locale[0]); + } + + @Override + public boolean isSupportedLocale(Locale locale) { + return map.containsKey(locale); + } + + @Override + public Collator getInstance(Locale locale) { + CollatorProvider cp = getImpl(locale); + assert cp != null; + return cp.getInstance(locale); + } + } + + static class DateFormatProviderDelegate extends DateFormatProvider + implements Delegate { + private ConcurrentMap map = new ConcurrentHashMap<>(); + + @Override + public void addImpl(DateFormatProvider impl) { + for (Locale l : impl.getAvailableLocales()) { + map.put(l, impl); + } + } + + @Override + public DateFormatProvider getImpl(Locale locale) { + return SPILocaleProviderAdapter.getImpl(map, locale); + } + + @Override + public Locale[] getAvailableLocales() { + return map.keySet().toArray(new Locale[0]); + } + + @Override + public boolean isSupportedLocale(Locale locale) { + return map.containsKey(locale); + } + + @Override + public DateFormat getTimeInstance(int style, Locale locale) { + DateFormatProvider dfp = getImpl(locale); + assert dfp != null; + return dfp.getTimeInstance(style, locale); + } + + @Override + public DateFormat getDateInstance(int style, Locale locale) { + DateFormatProvider dfp = getImpl(locale); + assert dfp != null; + return dfp.getDateInstance(style, locale); + } + + @Override + public DateFormat getDateTimeInstance(int dateStyle, int timeStyle, Locale locale) { + DateFormatProvider dfp = getImpl(locale); + assert dfp != null; + return dfp.getDateTimeInstance(dateStyle, timeStyle, locale); + } + } + + static class DateFormatSymbolsProviderDelegate extends DateFormatSymbolsProvider + implements Delegate { + private ConcurrentMap map = new ConcurrentHashMap<>(); + + @Override + public void addImpl(DateFormatSymbolsProvider impl) { + for (Locale l : impl.getAvailableLocales()) { + map.put(l, impl); + } + } + + @Override + public DateFormatSymbolsProvider getImpl(Locale locale) { + return SPILocaleProviderAdapter.getImpl(map, locale); + } + + @Override + public Locale[] getAvailableLocales() { + return map.keySet().toArray(new Locale[0]); + } + + @Override + public boolean isSupportedLocale(Locale locale) { + return map.containsKey(locale); + } + + @Override + public DateFormatSymbols getInstance(Locale locale) { + DateFormatSymbolsProvider dfsp = getImpl(locale); + assert dfsp != null; + return dfsp.getInstance(locale); + } + } + + static class DecimalFormatSymbolsProviderDelegate extends DecimalFormatSymbolsProvider + implements Delegate { + private ConcurrentMap map = new ConcurrentHashMap<>(); + + @Override + public void addImpl(DecimalFormatSymbolsProvider impl) { + for (Locale l : impl.getAvailableLocales()) { + map.put(l, impl); + } + } + + @Override + public DecimalFormatSymbolsProvider getImpl(Locale locale) { + return SPILocaleProviderAdapter.getImpl(map, locale); + } + + @Override + public Locale[] getAvailableLocales() { + return map.keySet().toArray(new Locale[0]); + } + + @Override + public boolean isSupportedLocale(Locale locale) { + return map.containsKey(locale); + } + + @Override + public DecimalFormatSymbols getInstance(Locale locale) { + DecimalFormatSymbolsProvider dfsp = getImpl(locale); + assert dfsp != null; + return dfsp.getInstance(locale); + } + } + + static class NumberFormatProviderDelegate extends NumberFormatProvider + implements Delegate { + private ConcurrentMap map = new ConcurrentHashMap<>(); + + @Override + public void addImpl(NumberFormatProvider impl) { + for (Locale l : impl.getAvailableLocales()) { + map.put(l, impl); + } + } + + @Override + public NumberFormatProvider getImpl(Locale locale) { + return SPILocaleProviderAdapter.getImpl(map, locale); + } + + @Override + public Locale[] getAvailableLocales() { + return map.keySet().toArray(new Locale[0]); + } + + @Override + public boolean isSupportedLocale(Locale locale) { + return map.containsKey(locale); + } + + @Override + public NumberFormat getCurrencyInstance(Locale locale) { + NumberFormatProvider nfp = getImpl(locale); + assert nfp != null; + return nfp.getCurrencyInstance(locale); + } + + @Override + public NumberFormat getIntegerInstance(Locale locale) { + NumberFormatProvider nfp = getImpl(locale); + assert nfp != null; + return nfp.getIntegerInstance(locale); + } + + @Override + public NumberFormat getNumberInstance(Locale locale) { + NumberFormatProvider nfp = getImpl(locale); + assert nfp != null; + return nfp.getNumberInstance(locale); + } + + @Override + public NumberFormat getPercentInstance(Locale locale) { + NumberFormatProvider nfp = getImpl(locale); + assert nfp != null; + return nfp.getPercentInstance(locale); + } + } + + static class CalendarDataProviderDelegate extends CalendarDataProvider + implements Delegate { + private ConcurrentMap map = new ConcurrentHashMap<>(); + + @Override + public void addImpl(CalendarDataProvider impl) { + for (Locale l : impl.getAvailableLocales()) { + map.put(l, impl); + } + } + + @Override + public CalendarDataProvider getImpl(Locale locale) { + return SPILocaleProviderAdapter.getImpl(map, locale); + } + + @Override + public Locale[] getAvailableLocales() { + return map.keySet().toArray(new Locale[0]); + } + + @Override + public boolean isSupportedLocale(Locale locale) { + return map.containsKey(locale); + } + + @Override + public int getFirstDayOfWeek(Locale locale) { + CalendarDataProvider cdp = getImpl(locale); + assert cdp != null; + return cdp.getFirstDayOfWeek(locale); + } + + @Override + public int getMinimalDaysInFirstWeek(Locale locale) { + CalendarDataProvider cdp = getImpl(locale); + assert cdp != null; + return cdp.getMinimalDaysInFirstWeek(locale); + } + + @Override + public String getDisplayName(String calendarType, + int field, int value, + int style, Locale locale) { + CalendarDataProvider cdp = getImpl(locale); + assert cdp != null; + return cdp.getDisplayName(calendarType, field, value, style, locale); + } + + @Override + public Map getDisplayNames(String calendarType, + int field, int style, + Locale locale) { + CalendarDataProvider cdp = getImpl(locale); + assert cdp != null; + return cdp.getDisplayNames(calendarType, field, style, locale); + } + } + + static class CurrencyNameProviderDelegate extends CurrencyNameProvider + implements Delegate { + private ConcurrentMap map = new ConcurrentHashMap<>(); + + @Override + public void addImpl(CurrencyNameProvider impl) { + for (Locale l : impl.getAvailableLocales()) { + map.put(l, impl); + } + } + + @Override + public CurrencyNameProvider getImpl(Locale locale) { + return SPILocaleProviderAdapter.getImpl(map, locale); + } + + @Override + public Locale[] getAvailableLocales() { + return map.keySet().toArray(new Locale[0]); + } + + @Override + public boolean isSupportedLocale(Locale locale) { + return map.containsKey(locale); + } + + @Override + public String getSymbol(String currencyCode, Locale locale) { + CurrencyNameProvider cnp = getImpl(locale); + assert cnp != null; + return cnp.getSymbol(currencyCode, locale); + } + + @Override + public String getDisplayName(String currencyCode, Locale locale) { + CurrencyNameProvider cnp = getImpl(locale); + assert cnp != null; + return cnp.getDisplayName(currencyCode, locale); + } + } + + static class LocaleNameProviderDelegate extends LocaleNameProvider + implements Delegate { + private ConcurrentMap map = new ConcurrentHashMap<>(); + + @Override + public void addImpl(LocaleNameProvider impl) { + for (Locale l : impl.getAvailableLocales()) { + map.put(l, impl); + } + } + + @Override + public LocaleNameProvider getImpl(Locale locale) { + return SPILocaleProviderAdapter.getImpl(map, locale); + } + + @Override + public Locale[] getAvailableLocales() { + return map.keySet().toArray(new Locale[0]); + } + + @Override + public boolean isSupportedLocale(Locale locale) { + return map.containsKey(locale); + } + + @Override + public String getDisplayLanguage(String languageCode, Locale locale) { + LocaleNameProvider lnp = getImpl(locale); + assert lnp != null; + return lnp.getDisplayLanguage(languageCode, locale); + } + + @Override + public String getDisplayScript(String scriptCode, Locale locale) { + LocaleNameProvider lnp = getImpl(locale); + assert lnp != null; + return lnp.getDisplayScript(scriptCode, locale); + } + + @Override + public String getDisplayCountry(String countryCode, Locale locale) { + LocaleNameProvider lnp = getImpl(locale); + assert lnp != null; + return lnp.getDisplayCountry(countryCode, locale); + } + + @Override + public String getDisplayVariant(String variant, Locale locale) { + LocaleNameProvider lnp = getImpl(locale); + assert lnp != null; + return lnp.getDisplayVariant(variant, locale); + } + } + + static class TimeZoneNameProviderDelegate extends TimeZoneNameProvider + implements Delegate { + private ConcurrentMap map = new ConcurrentHashMap<>(); + + @Override + public void addImpl(TimeZoneNameProvider impl) { + for (Locale l : impl.getAvailableLocales()) { + map.put(l, impl); + } + } + + @Override + public TimeZoneNameProvider getImpl(Locale locale) { + return SPILocaleProviderAdapter.getImpl(map, locale); + } + + @Override + public Locale[] getAvailableLocales() { + return map.keySet().toArray(new Locale[0]); + } + + @Override + public boolean isSupportedLocale(Locale locale) { + return map.containsKey(locale); + } + + @Override + public String getDisplayName(String ID, boolean daylight, int style, Locale locale) { + TimeZoneNameProvider tznp = getImpl(locale); + assert tznp != null; + return tznp.getDisplayName(ID, daylight, style, locale); + } + } } diff --git a/jdk/test/java/util/PluggableLocale/CurrencyNameProviderTest.java b/jdk/test/java/util/PluggableLocale/CurrencyNameProviderTest.java index 7c9f631258b..ebffc3f4f3c 100644 --- a/jdk/test/java/util/PluggableLocale/CurrencyNameProviderTest.java +++ b/jdk/test/java/util/PluggableLocale/CurrencyNameProviderTest.java @@ -48,10 +48,13 @@ public class CurrencyNameProviderTest extends ProviderTest { void test1() { com.bar.CurrencyNameProviderImpl cnp = new com.bar.CurrencyNameProviderImpl(); + com.bar.CurrencyNameProviderImpl2 cnp2 = new com.bar.CurrencyNameProviderImpl2(); Locale[] availloc = Locale.getAvailableLocales(); Locale[] testloc = availloc.clone(); List jreimplloc = Arrays.asList(LocaleProviderAdapter.forJRE().getCurrencyNameProvider().getAvailableLocales()); - List providerloc = Arrays.asList(cnp.getAvailableLocales()); + List providerloc = new ArrayList(); + providerloc.addAll(Arrays.asList(cnp.getAvailableLocales())); + providerloc.addAll(Arrays.asList(cnp2.getAvailableLocales())); for (Locale target: availloc) { // pure JRE implementation @@ -79,8 +82,13 @@ public class CurrencyNameProviderTest extends ProviderTest { String providerscurrency = null; String providersname = null; if (providerloc.contains(target)) { + if (cnp.isSupportedLocale(target)) { providerscurrency = cnp.getSymbol(c.getCurrencyCode(), target); providersname = cnp.getDisplayName(c.getCurrencyCode(), target); + } else { + providerscurrency = cnp2.getSymbol(c.getCurrencyCode(), target); + providersname = cnp2.getDisplayName(c.getCurrencyCode(), target); + } } // JRE's name @@ -109,18 +117,22 @@ public class CurrencyNameProviderTest extends ProviderTest { final String pattern = "###,###\u00A4"; final String YEN_IN_OSAKA = "100,000\u5186\u3084\u3002"; final String YEN_IN_KYOTO = "100,000\u5186\u3069\u3059\u3002"; + final String YEN_IN_TOKYO= "100,000JPY-tokyo"; final Locale OSAKA = new Locale("ja", "JP", "osaka"); final Locale KYOTO = new Locale("ja", "JP", "kyoto"); + final Locale TOKYO = new Locale("ja", "JP", "tokyo"); Integer i = new Integer(100000); String formatted; DecimalFormat df; void test2() { + Locale defloc = Locale.getDefault(); + try { df = new DecimalFormat(pattern, DecimalFormatSymbols.getInstance(OSAKA)); System.out.println(formatted = df.format(i)); if(!formatted.equals(YEN_IN_OSAKA)) { - throw new RuntimeException("formatted zone names mismatch. " + + throw new RuntimeException("formatted currency names mismatch. " + "Should match with " + YEN_IN_OSAKA); } @@ -130,13 +142,25 @@ public class CurrencyNameProviderTest extends ProviderTest { df = new DecimalFormat(pattern, DecimalFormatSymbols.getInstance()); System.out.println(formatted = df.format(i)); if(!formatted.equals(YEN_IN_KYOTO)) { - throw new RuntimeException("formatted zone names mismatch. " + + throw new RuntimeException("formatted currency names mismatch. " + "Should match with " + YEN_IN_KYOTO); } df.parse(YEN_IN_KYOTO); + + Locale.setDefault(TOKYO); + df = new DecimalFormat(pattern, DecimalFormatSymbols.getInstance()); + System.out.println(formatted = df.format(i)); + if(!formatted.equals(YEN_IN_TOKYO)) { + throw new RuntimeException("formatted currency names mismatch. " + + "Should match with " + YEN_IN_TOKYO); + } + + df.parse(YEN_IN_TOKYO); } catch (ParseException pe) { throw new RuntimeException("parse error occured" + pe); + } finally { + Locale.setDefault(defloc); } } } diff --git a/jdk/test/java/util/PluggableLocale/CurrencyNameProviderTest.sh b/jdk/test/java/util/PluggableLocale/CurrencyNameProviderTest.sh index a0a9d582eae..f9abbe09071 100644 --- a/jdk/test/java/util/PluggableLocale/CurrencyNameProviderTest.sh +++ b/jdk/test/java/util/PluggableLocale/CurrencyNameProviderTest.sh @@ -23,6 +23,6 @@ #!/bin/sh # # @test -# @bug 4052440 +# @bug 4052440 8000997 # @summary CurrencyNameProvider tests # @run shell ExecTest.sh bar CurrencyNameProviderTest true diff --git a/jdk/test/java/util/PluggableLocale/GenericTest.java b/jdk/test/java/util/PluggableLocale/GenericTest.java index 3987f986bea..288d7a3ab04 100644 --- a/jdk/test/java/util/PluggableLocale/GenericTest.java +++ b/jdk/test/java/util/PluggableLocale/GenericTest.java @@ -38,6 +38,7 @@ public class GenericTest { com.foo.DecimalFormatSymbolsProviderImpl decimalFSP = new com.foo.DecimalFormatSymbolsProviderImpl(); com.foo.NumberFormatProviderImpl numberFP = new com.foo.NumberFormatProviderImpl(); com.bar.CurrencyNameProviderImpl currencyNP = new com.bar.CurrencyNameProviderImpl(); + com.bar.CurrencyNameProviderImpl2 currencyNP2 = new com.bar.CurrencyNameProviderImpl2(); com.bar.LocaleNameProviderImpl localeNP = new com.bar.LocaleNameProviderImpl(); com.bar.TimeZoneNameProviderImpl tzNP = new com.bar.TimeZoneNameProviderImpl(); com.bar.CalendarDataProviderImpl calDataP = new com.bar.CalendarDataProviderImpl(); @@ -68,6 +69,7 @@ public class GenericTest { expected.addAll(Arrays.asList(decimalFSP.getAvailableLocales())); expected.addAll(Arrays.asList(numberFP.getAvailableLocales())); expected.addAll(Arrays.asList(currencyNP.getAvailableLocales())); + expected.addAll(Arrays.asList(currencyNP2.getAvailableLocales())); expected.addAll(Arrays.asList(localeNP.getAvailableLocales())); expected.addAll(Arrays.asList(tzNP.getAvailableLocales())); expected.addAll(Arrays.asList(calDataP.getAvailableLocales())); diff --git a/jdk/test/java/util/PluggableLocale/barprovider.jar b/jdk/test/java/util/PluggableLocale/barprovider.jar index b5247a09262b7ad030f74b0cb32aca424065e4ca..901b2b2b7f6264a4f8fe6b7e4af75f573897e55e 100644 GIT binary patch delta 1600 zcmY*Z2~ZPf6kb9I7_M-HCL|;n8m`_I*cU<@*fze%eTL zKu=E(I20au!titLCGeHNFhpJgP)o}OMg_`J?xppU&JvL;P$Z-Y^xy@oxa`0Il#R%V z8519sn%X1{4K(w@+*$;4#;e7&=V+W~Y&+ISiMAdNU=xF-Wu1>~FaLh%o~rRrS=W|U z{~yD2q|$j+ZuR(W87Ax4s4TtojmJQXs-#P?Ygdc*sW#f03Ebt)gxEDv23v6*hcg9Q zF{U4J<|e~K$%(f0MN)pYgNgsA?xLIAlZwNquxz{N2wu>QtQ=c9I>c0cROam};GUJu zS!eL>`gHe9`#j%9YqX40v-XHbnVfHw>W$g^d)$NYmM>1rR3p_6JsA}j4!q^=4s!0$ zo=TXiX}|B7Tkc&!O{1LKUL;KqW;!0Y*~v4ltiTt&npij7PZ2lflwUYjC&HE^1^!XJ z+*=O|KNd)+x%J1N_w3C3ZPUxPlAhv(a_>g#e)&DK34X1!{O66X9gmPnWMjlD z&r6v~AUedP%JRD96a4(YDeQn7Ft&uIOqxsXG_ZcU_d47=f(HV|1$}&zfsbnq!P332w!aCr@vw6!f}xpE1ZU z%#T(R9b&J3*i)@zV$3@;SW}dL!Q3rn_n7h-`T^0eyzJTur?2{bOFG7P7T1r~8)(06 zt#zF!EqGiLP7<0(V!8F+M(?`0t_s52z@zg4wBi&i?G$B$W8Djef1)U~EV+{%rlbrs ze|B*zk2dWbTK;--FTD{LHc~e8N3CURMnhchHC{!t!l5xRxpbRXoZ+3iyA^|(4Q`8` ziyv}k9{64Hb!&18BDPG_l*!f$GpdC(Z%SD&2W9$I{yI_4p`zBOTdwLF`#r3bJf6Xq z$k9sRDTYdO6wdy2aZ-eKU=3R}(?X1hpsB2wK~QnB)woh z5IL5aE}1sGq}C-UaEg}>BYSOrh3Hd?i)rca~?9IQC#jJ^(iX+jXI_E5W z=6V+D`kDIQ{VfSr-e?HG-o;3L$68uVyGLBsr*{v}?mV`GsXH@_Tsj0|LVWgqNF-#? zy;^R-M8_t$J0?xj7+5dq*Qm;);vh65CnNxnR%jUjG?_ucSnwB& zK4{D|fL}~v5)j!Ikl6-|ST-dv30gm?F4OFofs_3|?qJ#*g;=m*e zB=|3r2v@XX5fCM0$ZP@fS$NnK51E1~U>=JL)9VoJvk$qvIkqJIFQNKbhUv^ zKuprWFt#82bTEQL0gWBZ!TW5@hpwChcU4;>nqU$~lkdeLAZi&lTpX?=aPcb-Y1IOFLAC@+6 zFb`bg`XRG%O8nydy!JP5n!UA7brvsHo2IC7)vB&pwPy0;#k-67p2x0j_7M;8X6J|q zY1*90z`#%s#E?*9hX&i^L%MsRZZe$QX(}@LxLz%o@2+nFrknKb!SoS*eK7q^-xy5m z7zBdp1}Lp*D9!YkYqBq&+TM|UtW zFx+8bU{C})2mwrmfr^#k3iqB2FWCT8cowKo3!w_gvJnF+l$g9vQe<+x5yY}QBWWfV zNwDxS8407IMf>HZnE= z`zq5|+PX@Wfgw3RS3fO3KPj5_Dds(oBlllPBt#O`dDY!3Xk*05BAuXoJiF0O|$^-2eap diff --git a/jdk/test/java/util/PluggableLocale/providersrc/CurrencyNameProviderImpl2.java b/jdk/test/java/util/PluggableLocale/providersrc/CurrencyNameProviderImpl2.java new file mode 100644 index 00000000000..5ed7222f95e --- /dev/null +++ b/jdk/test/java/util/PluggableLocale/providersrc/CurrencyNameProviderImpl2.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.bar; + +import java.util.*; +import java.util.spi.*; + +import com.foobar.Utils; + +public class CurrencyNameProviderImpl2 extends CurrencyNameProvider { + static Locale[] avail = {new Locale("ja", "JP", "tokyo")}; + public Locale[] getAvailableLocales() { + return avail; + } + + @Override + public String getSymbol(String c, Locale locale) { + if (!Utils.supportsLocale(Arrays.asList(avail), locale)) { + throw new IllegalArgumentException("locale is not supported: "+locale); + } + + if (c.equals("JPY") && Utils.supportsLocale(avail[0], locale)) { + return "JPY-tokyo"; + } + return null; + } + + @Override + public String getDisplayName(String c, Locale locale) { + if (!Utils.supportsLocale(Arrays.asList(avail), locale)) { + throw new IllegalArgumentException("locale is not supported: "+locale); + } + + if (c.equals("JPY") && Utils.supportsLocale(avail[0], locale)) { + return "JPY-tokyo"; + } + return null; + } +} diff --git a/jdk/test/java/util/PluggableLocale/providersrc/Makefile b/jdk/test/java/util/PluggableLocale/providersrc/Makefile index d69cecd149d..3c550992691 100644 --- a/jdk/test/java/util/PluggableLocale/providersrc/Makefile +++ b/jdk/test/java/util/PluggableLocale/providersrc/Makefile @@ -35,6 +35,7 @@ FOOFILES_JAVA = \ BARFILES_JAVA = \ CurrencyNameProviderImpl.java \ + CurrencyNameProviderImpl2.java \ TimeZoneNameProviderImpl.java \ LocaleNameProviderImpl.java \ CalendarDataProviderImpl.java \ diff --git a/jdk/test/java/util/PluggableLocale/providersrc/java.util.spi.CurrencyNameProvider b/jdk/test/java/util/PluggableLocale/providersrc/java.util.spi.CurrencyNameProvider index 938d6b090c1..9817ed386e2 100644 --- a/jdk/test/java/util/PluggableLocale/providersrc/java.util.spi.CurrencyNameProvider +++ b/jdk/test/java/util/PluggableLocale/providersrc/java.util.spi.CurrencyNameProvider @@ -5,3 +5,4 @@ # implementation class # com.bar.CurrencyNameProviderImpl +com.bar.CurrencyNameProviderImpl2 From e184d5cc4ec66640366d2d30d8dfaba74a1003a7 Mon Sep 17 00:00:00 2001 From: Roman Kennke Date: Mon, 29 Oct 2012 11:08:48 -0700 Subject: [PATCH 25/59] 8000780: make Zero build and run with JDK8 Reviewed-by: coleenp, dholmes, twisti --- hotspot/make/Makefile | 16 + .../zero/vm/cppInterpreterGenerator_zero.hpp | 13 +- .../src/cpu/zero/vm/cppInterpreter_zero.cpp | 567 +----------------- .../src/cpu/zero/vm/cppInterpreter_zero.hpp | 2 - hotspot/src/cpu/zero/vm/frame_zero.cpp | 7 +- hotspot/src/cpu/zero/vm/frame_zero.inline.hpp | 2 + hotspot/src/cpu/zero/vm/icBuffer_zero.cpp | 5 +- .../src/cpu/zero/vm/methodHandles_zero.cpp | 165 ++++- .../src/cpu/zero/vm/methodHandles_zero.hpp | 10 +- hotspot/src/cpu/zero/vm/register_zero.hpp | 3 + hotspot/src/cpu/zero/vm/relocInfo_zero.cpp | 4 + .../src/cpu/zero/vm/sharedRuntime_zero.cpp | 31 +- hotspot/src/share/vm/asm/codeBuffer.cpp | 2 +- .../vm/interpreter/abstractInterpreter.hpp | 1 + .../vm/interpreter/bytecodeInterpreter.cpp | 69 ++- .../vm/interpreter/bytecodeInterpreter.hpp | 5 +- .../share/vm/interpreter/cppInterpreter.cpp | 6 +- .../src/share/vm/interpreter/interpreter.cpp | 8 + .../vm/interpreter/templateInterpreter.cpp | 6 +- hotspot/src/share/vm/runtime/vmStructs.cpp | 2 +- hotspot/src/share/vm/utilities/macros.hpp | 16 + 21 files changed, 323 insertions(+), 617 deletions(-) diff --git a/hotspot/make/Makefile b/hotspot/make/Makefile index a0b7ba7687c..fe5a6b684d6 100644 --- a/hotspot/make/Makefile +++ b/hotspot/make/Makefile @@ -453,14 +453,30 @@ ifneq ($(OSNAME),windows) ifeq ($(JVM_VARIANT_ZEROSHARK), true) $(EXPORT_JRE_LIB_ARCH_DIR)/%.$(LIBRARY_SUFFIX): $(SHARK_DIR)/%.$(LIBRARY_SUFFIX) $(install-file) + $(EXPORT_JRE_LIB_ARCH_DIR)/%.debuginfo): $(SHARK_DIR)/%.debuginfo + $(install-file) + $(EXPORT_JRE_LIB_ARCH_DIR)/%.diz: $(SHARK_DIR)/%.diz + $(install-file) $(EXPORT_SERVER_DIR)/%.$(LIBRARY_SUFFIX): $(SHARK_DIR)/%.$(LIBRARY_SUFFIX) $(install-file) + $(EXPORT_SERVER_DIR)/%.debuginfo: $(SHARK_DIR)/%.debuginfo + $(install-file) + $(EXPORT_SERVER_DIR)/%.diz: $(SHARK_DIR)/%.diz + $(install-file) endif ifeq ($(JVM_VARIANT_ZERO), true) $(EXPORT_JRE_LIB_ARCH_DIR)/%.$(LIBRARY_SUFFIX): $(ZERO_DIR)/%.$(LIBRARY_SUFFIX) $(install-file) + $(EXPORT_JRE_LIB_ARCH_DIR)/%.debuginfo: $(ZERO_DIR)/%.debuginfo + $(install-file) + $(EXPORT_JRE_LIB_ARCH_DIR)/%.diz: $(ZERO_DIR)/%.diz + $(install-file) $(EXPORT_SERVER_DIR)/%.$(LIBRARY_SUFFIX): $(ZERO_DIR)/%.$(LIBRARY_SUFFIX) $(install-file) + $(EXPORT_SERVER_DIR)/%.debuginfo: $(ZERO_DIR)/%.debuginfo + $(install-file) + $(EXPORT_SERVER_DIR)/%.diz: $(ZERO_DIR)/%.diz + $(install-file) endif ifeq ($(JVM_VARIANT_MINIMAL1), true) $(EXPORT_JRE_LIB_ARCH_DIR)/%.$(LIBRARY_SUFFIX): $(MINIMAL1_DIR)/%.$(LIBRARY_SUFFIX) diff --git a/hotspot/src/cpu/zero/vm/cppInterpreterGenerator_zero.hpp b/hotspot/src/cpu/zero/vm/cppInterpreterGenerator_zero.hpp index ff61306c760..6b2cacf5ae2 100644 --- a/hotspot/src/cpu/zero/vm/cppInterpreterGenerator_zero.hpp +++ b/hotspot/src/cpu/zero/vm/cppInterpreterGenerator_zero.hpp @@ -31,12 +31,17 @@ return _masm; } - protected: - address generate_entry(address entry_point) { - ZeroEntry *entry = (ZeroEntry *) assembler()->pc(); - assembler()->advance(sizeof(ZeroEntry)); + public: + static address generate_entry_impl(MacroAssembler* masm, address entry_point) { + ZeroEntry *entry = (ZeroEntry *) masm->pc(); + masm->advance(sizeof(ZeroEntry)); entry->set_entry_point(entry_point); return (address) entry; } + protected: + address generate_entry(address entry_point) { + return generate_entry_impl(assembler(), entry_point); + } + #endif // CPU_ZERO_VM_CPPINTERPRETERGENERATOR_ZERO_HPP diff --git a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp index 1b2da5a5d15..ee855a9efbc 100644 --- a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp +++ b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp @@ -180,25 +180,6 @@ void CppInterpreter::main_loop(int recurse, TRAPS) { method, istate->osr_entry(), istate->osr_buf(), THREAD); return; } - else if (istate->msg() == BytecodeInterpreter::call_method_handle) { - oop method_handle = istate->callee(); - - // Trim back the stack to put the parameters at the top - stack->set_sp(istate->stack() + 1); - - // Make the call - process_method_handle(method_handle, THREAD); - fixup_after_potential_safepoint(); - - // Convert the result - istate->set_stack(stack->sp() - 1); - - // Restore the stack - stack->set_sp(istate->stack_limit() + 1); - - // Resume the interpreter - istate->set_msg(BytecodeInterpreter::method_resume); - } else { ShouldNotReachHere(); } @@ -535,35 +516,35 @@ int CppInterpreter::accessor_entry(Method* method, intptr_t UNUSED, TRAPS) { if (entry->is_volatile()) { switch (entry->flag_state()) { case ctos: - SET_LOCALS_INT(object->char_field_acquire(entry->f2()), 0); + SET_LOCALS_INT(object->char_field_acquire(entry->f2_as_index()), 0); break; case btos: - SET_LOCALS_INT(object->byte_field_acquire(entry->f2()), 0); + SET_LOCALS_INT(object->byte_field_acquire(entry->f2_as_index()), 0); break; case stos: - SET_LOCALS_INT(object->short_field_acquire(entry->f2()), 0); + SET_LOCALS_INT(object->short_field_acquire(entry->f2_as_index()), 0); break; case itos: - SET_LOCALS_INT(object->int_field_acquire(entry->f2()), 0); + SET_LOCALS_INT(object->int_field_acquire(entry->f2_as_index()), 0); break; case ltos: - SET_LOCALS_LONG(object->long_field_acquire(entry->f2()), 0); + SET_LOCALS_LONG(object->long_field_acquire(entry->f2_as_index()), 0); break; case ftos: - SET_LOCALS_FLOAT(object->float_field_acquire(entry->f2()), 0); + SET_LOCALS_FLOAT(object->float_field_acquire(entry->f2_as_index()), 0); break; case dtos: - SET_LOCALS_DOUBLE(object->double_field_acquire(entry->f2()), 0); + SET_LOCALS_DOUBLE(object->double_field_acquire(entry->f2_as_index()), 0); break; case atos: - SET_LOCALS_OBJECT(object->obj_field_acquire(entry->f2()), 0); + SET_LOCALS_OBJECT(object->obj_field_acquire(entry->f2_as_index()), 0); break; default: @@ -573,35 +554,35 @@ int CppInterpreter::accessor_entry(Method* method, intptr_t UNUSED, TRAPS) { else { switch (entry->flag_state()) { case ctos: - SET_LOCALS_INT(object->char_field(entry->f2()), 0); + SET_LOCALS_INT(object->char_field(entry->f2_as_index()), 0); break; case btos: - SET_LOCALS_INT(object->byte_field(entry->f2()), 0); + SET_LOCALS_INT(object->byte_field(entry->f2_as_index()), 0); break; case stos: - SET_LOCALS_INT(object->short_field(entry->f2()), 0); + SET_LOCALS_INT(object->short_field(entry->f2_as_index()), 0); break; case itos: - SET_LOCALS_INT(object->int_field(entry->f2()), 0); + SET_LOCALS_INT(object->int_field(entry->f2_as_index()), 0); break; case ltos: - SET_LOCALS_LONG(object->long_field(entry->f2()), 0); + SET_LOCALS_LONG(object->long_field(entry->f2_as_index()), 0); break; case ftos: - SET_LOCALS_FLOAT(object->float_field(entry->f2()), 0); + SET_LOCALS_FLOAT(object->float_field(entry->f2_as_index()), 0); break; case dtos: - SET_LOCALS_DOUBLE(object->double_field(entry->f2()), 0); + SET_LOCALS_DOUBLE(object->double_field(entry->f2_as_index()), 0); break; case atos: - SET_LOCALS_OBJECT(object->obj_field(entry->f2()), 0); + SET_LOCALS_OBJECT(object->obj_field(entry->f2_as_index()), 0); break; default: @@ -629,516 +610,6 @@ int CppInterpreter::empty_entry(Method* method, intptr_t UNUSED, TRAPS) { return 0; } -int CppInterpreter::method_handle_entry(Method* method, - intptr_t UNUSED, TRAPS) { - JavaThread *thread = (JavaThread *) THREAD; - ZeroStack *stack = thread->zero_stack(); - int argument_slots = method->size_of_parameters(); - int result_slots = type2size[result_type_of(method)]; - intptr_t *vmslots = stack->sp(); - intptr_t *unwind_sp = vmslots + argument_slots; - - // Find the MethodType - address p = (address) method; - for (jint* pc = method->method_type_offsets_chain(); (*pc) != -1; pc++) { - p = *(address*)(p + (*pc)); - } - oop method_type = (oop) p; - - // The MethodHandle is in the slot after the arguments - int num_vmslots = argument_slots - 1; - oop method_handle = VMSLOTS_OBJECT(num_vmslots); - - // InvokeGeneric requires some extra shuffling - oop mhtype = java_lang_invoke_MethodHandle::type(method_handle); - bool is_exact = mhtype == method_type; - if (!is_exact) { - if (true || // FIXME - method->intrinsic_id() == vmIntrinsics::_invokeExact) { - CALL_VM_NOCHECK_NOFIX( - SharedRuntime::throw_WrongMethodTypeException( - thread, method_type, mhtype)); - // NB all oops trashed! - assert(HAS_PENDING_EXCEPTION, "should do"); - stack->set_sp(unwind_sp); - return 0; - } - assert(method->intrinsic_id() == vmIntrinsics::_invokeGeneric, "should be"); - - // Load up an adapter from the calling type - // NB the x86 code for this (in methodHandles_x86.cpp, search for - // "genericInvoker") is really really odd. I'm hoping it's trying - // to accomodate odd VM/class library combinations I can ignore. - oop adapter = NULL; //FIXME: load the adapter from the CP cache - IF (adapter == NULL) { - CALL_VM_NOCHECK_NOFIX( - SharedRuntime::throw_WrongMethodTypeException( - thread, method_type, mhtype)); - // NB all oops trashed! - assert(HAS_PENDING_EXCEPTION, "should do"); - stack->set_sp(unwind_sp); - return 0; - } - - // Adapters are shared among form-families of method-type. The - // type being called is passed as a trusted first argument so that - // the adapter knows the actual types of its arguments and return - // values. - insert_vmslots(num_vmslots + 1, 1, THREAD); - if (HAS_PENDING_EXCEPTION) { - // NB all oops trashed! - stack->set_sp(unwind_sp); - return 0; - } - - vmslots = stack->sp(); - num_vmslots++; - SET_VMSLOTS_OBJECT(method_type, num_vmslots); - - method_handle = adapter; - } - - // Start processing - process_method_handle(method_handle, THREAD); - if (HAS_PENDING_EXCEPTION) - result_slots = 0; - - // If this is an invokeExact then the eventual callee will not - // have unwound the method handle argument so we have to do it. - // If a result is being returned the it will be above the method - // handle argument we're unwinding. - if (is_exact) { - intptr_t result[2]; - for (int i = 0; i < result_slots; i++) - result[i] = stack->pop(); - stack->pop(); - for (int i = result_slots - 1; i >= 0; i--) - stack->push(result[i]); - } - - // Check - assert(stack->sp() == unwind_sp - result_slots, "should be"); - - // No deoptimized frames on the stack - return 0; -} - -void CppInterpreter::process_method_handle(oop method_handle, TRAPS) { - JavaThread *thread = (JavaThread *) THREAD; - ZeroStack *stack = thread->zero_stack(); - intptr_t *vmslots = stack->sp(); - - bool direct_to_method = false; - BasicType src_rtype = T_ILLEGAL; - BasicType dst_rtype = T_ILLEGAL; - - MethodHandleEntry *entry = - java_lang_invoke_MethodHandle::vmentry(method_handle); - MethodHandles::EntryKind entry_kind = - (MethodHandles::EntryKind) (((intptr_t) entry) & 0xffffffff); - - Method* method = NULL; - switch (entry_kind) { - case MethodHandles::_invokestatic_mh: - direct_to_method = true; - break; - - case MethodHandles::_invokespecial_mh: - case MethodHandles::_invokevirtual_mh: - case MethodHandles::_invokeinterface_mh: - { - oop receiver = - VMSLOTS_OBJECT( - java_lang_invoke_MethodHandle::vmslots(method_handle) - 1); - if (receiver == NULL) { - stack->set_sp(calculate_unwind_sp(stack, method_handle)); - CALL_VM_NOCHECK_NOFIX( - throw_exception( - thread, vmSymbols::java_lang_NullPointerException())); - // NB all oops trashed! - assert(HAS_PENDING_EXCEPTION, "should do"); - return; - } - if (entry_kind != MethodHandles::_invokespecial_mh) { - intptr_t index = java_lang_invoke_DirectMethodHandle::vmindex(method_handle); - InstanceKlass* rcvrKlass = - (InstanceKlass *) receiver->klass(); - if (entry_kind == MethodHandles::_invokevirtual_mh) { - method = (Method*) rcvrKlass->start_of_vtable()[index]; - } - else { - oop iclass = java_lang_invoke_MethodHandle::next_target(method_handle); - itableOffsetEntry* ki = - (itableOffsetEntry *) rcvrKlass->start_of_itable(); - int i, length = rcvrKlass->itable_length(); - for (i = 0; i < length; i++, ki++ ) { - if (ki->interface_klass() == iclass) - break; - } - if (i == length) { - stack->set_sp(calculate_unwind_sp(stack, method_handle)); - CALL_VM_NOCHECK_NOFIX( - throw_exception( - thread, vmSymbols::java_lang_IncompatibleClassChangeError())); - // NB all oops trashed! - assert(HAS_PENDING_EXCEPTION, "should do"); - return; - } - itableMethodEntry* im = ki->first_method_entry(receiver->klass()); - method = im[index].method(); - if (method == NULL) { - stack->set_sp(calculate_unwind_sp(stack, method_handle)); - CALL_VM_NOCHECK_NOFIX( - throw_exception( - thread, vmSymbols::java_lang_AbstractMethodError())); - // NB all oops trashed! - assert(HAS_PENDING_EXCEPTION, "should do"); - return; - } - } - } - } - direct_to_method = true; - break; - - case MethodHandles::_bound_ref_direct_mh: - case MethodHandles::_bound_int_direct_mh: - case MethodHandles::_bound_long_direct_mh: - direct_to_method = true; - // fall through - case MethodHandles::_bound_ref_mh: - case MethodHandles::_bound_int_mh: - case MethodHandles::_bound_long_mh: - { - BasicType arg_type = T_ILLEGAL; - int arg_mask = -1; - int arg_slots = -1; - MethodHandles::get_ek_bound_mh_info( - entry_kind, arg_type, arg_mask, arg_slots); - int arg_slot = - java_lang_invoke_BoundMethodHandle::vmargslot(method_handle); - - // Create the new slot(s) - intptr_t *unwind_sp = calculate_unwind_sp(stack, method_handle); - insert_vmslots(arg_slot, arg_slots, THREAD); - if (HAS_PENDING_EXCEPTION) { - // all oops trashed - stack->set_sp(unwind_sp); - return; - } - vmslots = stack->sp(); - - // Store bound argument into new stack slot - oop arg = java_lang_invoke_BoundMethodHandle::argument(method_handle); - if (arg_type == T_OBJECT) { - assert(arg_slots == 1, "should be"); - SET_VMSLOTS_OBJECT(arg, arg_slot); - } - else { - jvalue arg_value; - arg_type = java_lang_boxing_object::get_value(arg, &arg_value); - switch (arg_type) { - case T_BOOLEAN: - SET_VMSLOTS_INT(arg_value.z, arg_slot); - break; - case T_CHAR: - SET_VMSLOTS_INT(arg_value.c, arg_slot); - break; - case T_BYTE: - SET_VMSLOTS_INT(arg_value.b, arg_slot); - break; - case T_SHORT: - SET_VMSLOTS_INT(arg_value.s, arg_slot); - break; - case T_INT: - SET_VMSLOTS_INT(arg_value.i, arg_slot); - break; - case T_FLOAT: - SET_VMSLOTS_FLOAT(arg_value.f, arg_slot); - break; - case T_LONG: - SET_VMSLOTS_LONG(arg_value.j, arg_slot + 1); - break; - case T_DOUBLE: - SET_VMSLOTS_DOUBLE(arg_value.d, arg_slot + 1); - break; - default: - tty->print_cr("unhandled type %s", type2name(arg_type)); - ShouldNotReachHere(); - } - } - } - break; - - case MethodHandles::_adapter_retype_only: - case MethodHandles::_adapter_retype_raw: - src_rtype = result_type_of_handle( - java_lang_invoke_MethodHandle::next_target(method_handle)); - dst_rtype = result_type_of_handle(method_handle); - break; - - case MethodHandles::_adapter_check_cast: - { - int arg_slot = - java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle); - oop arg = VMSLOTS_OBJECT(arg_slot); - if (arg != NULL) { - Klass* objKlassOop = arg->klass(); - Klass* klassOf = java_lang_Class::as_Klass( - java_lang_invoke_AdapterMethodHandle::argument(method_handle)); - - if (objKlassOop != klassOf && - !objKlassOop->is_subtype_of(klassOf)) { - ResourceMark rm(THREAD); - const char* objName = Klass::cast(objKlassOop)->external_name(); - const char* klassName = Klass::cast(klassOf)->external_name(); - char* message = SharedRuntime::generate_class_cast_message( - objName, klassName); - - stack->set_sp(calculate_unwind_sp(stack, method_handle)); - CALL_VM_NOCHECK_NOFIX( - throw_exception( - thread, vmSymbols::java_lang_ClassCastException(), message)); - // NB all oops trashed! - assert(HAS_PENDING_EXCEPTION, "should do"); - return; - } - } - } - break; - - case MethodHandles::_adapter_dup_args: - { - int arg_slot = - java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle); - int conv = - java_lang_invoke_AdapterMethodHandle::conversion(method_handle); - int num_slots = -MethodHandles::adapter_conversion_stack_move(conv); - assert(num_slots > 0, "should be"); - - // Create the new slot(s) - intptr_t *unwind_sp = calculate_unwind_sp(stack, method_handle); - stack->overflow_check(num_slots, THREAD); - if (HAS_PENDING_EXCEPTION) { - // all oops trashed - stack->set_sp(unwind_sp); - return; - } - - // Duplicate the arguments - for (int i = num_slots - 1; i >= 0; i--) - stack->push(*VMSLOTS_SLOT(arg_slot + i)); - - vmslots = stack->sp(); // unused, but let the compiler figure that out - } - break; - - case MethodHandles::_adapter_drop_args: - { - int arg_slot = - java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle); - int conv = - java_lang_invoke_AdapterMethodHandle::conversion(method_handle); - int num_slots = MethodHandles::adapter_conversion_stack_move(conv); - assert(num_slots > 0, "should be"); - - remove_vmslots(arg_slot, num_slots, THREAD); // doesn't trap - vmslots = stack->sp(); // unused, but let the compiler figure that out - } - break; - - case MethodHandles::_adapter_opt_swap_1: - case MethodHandles::_adapter_opt_swap_2: - case MethodHandles::_adapter_opt_rot_1_up: - case MethodHandles::_adapter_opt_rot_1_down: - case MethodHandles::_adapter_opt_rot_2_up: - case MethodHandles::_adapter_opt_rot_2_down: - { - int arg1 = - java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle); - int conv = - java_lang_invoke_AdapterMethodHandle::conversion(method_handle); - int arg2 = MethodHandles::adapter_conversion_vminfo(conv); - - int swap_bytes = 0, rotate = 0; - MethodHandles::get_ek_adapter_opt_swap_rot_info( - entry_kind, swap_bytes, rotate); - int swap_slots = swap_bytes >> LogBytesPerWord; - - intptr_t tmp; - switch (rotate) { - case 0: // swap - for (int i = 0; i < swap_slots; i++) { - tmp = *VMSLOTS_SLOT(arg1 + i); - SET_VMSLOTS_SLOT(VMSLOTS_SLOT(arg2 + i), arg1 + i); - SET_VMSLOTS_SLOT(&tmp, arg2 + i); - } - break; - - case 1: // up - assert(arg1 - swap_slots > arg2, "should be"); - - tmp = *VMSLOTS_SLOT(arg1); - for (int i = arg1 - swap_slots; i >= arg2; i--) - SET_VMSLOTS_SLOT(VMSLOTS_SLOT(i), i + swap_slots); - SET_VMSLOTS_SLOT(&tmp, arg2); - - break; - - case -1: // down - assert(arg2 - swap_slots > arg1, "should be"); - - tmp = *VMSLOTS_SLOT(arg1); - for (int i = arg1 + swap_slots; i <= arg2; i++) - SET_VMSLOTS_SLOT(VMSLOTS_SLOT(i), i - swap_slots); - SET_VMSLOTS_SLOT(&tmp, arg2); - break; - - default: - ShouldNotReachHere(); - } - } - break; - - case MethodHandles::_adapter_opt_i2l: - { - int arg_slot = - java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle); - int arg = VMSLOTS_INT(arg_slot); - intptr_t *unwind_sp = calculate_unwind_sp(stack, method_handle); - insert_vmslots(arg_slot, 1, THREAD); - if (HAS_PENDING_EXCEPTION) { - // all oops trashed - stack->set_sp(unwind_sp); - return; - } - vmslots = stack->sp(); - arg_slot++; - SET_VMSLOTS_LONG(arg, arg_slot); - } - break; - - case MethodHandles::_adapter_opt_unboxi: - case MethodHandles::_adapter_opt_unboxl: - { - int arg_slot = - java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle); - oop arg = VMSLOTS_OBJECT(arg_slot); - jvalue arg_value; - if (arg == NULL) { - // queue a nullpointer exception for the caller - stack->set_sp(calculate_unwind_sp(stack, method_handle)); - CALL_VM_NOCHECK_NOFIX( - throw_exception( - thread, vmSymbols::java_lang_NullPointerException())); - // NB all oops trashed! - assert(HAS_PENDING_EXCEPTION, "should do"); - return; - } - BasicType arg_type = java_lang_boxing_object::get_value(arg, &arg_value); - if (arg_type == T_LONG || arg_type == T_DOUBLE) { - intptr_t *unwind_sp = calculate_unwind_sp(stack, method_handle); - insert_vmslots(arg_slot, 1, THREAD); - if (HAS_PENDING_EXCEPTION) { - // all oops trashed - stack->set_sp(unwind_sp); - return; - } - vmslots = stack->sp(); - arg_slot++; - } - switch (arg_type) { - case T_BOOLEAN: - SET_VMSLOTS_INT(arg_value.z, arg_slot); - break; - case T_CHAR: - SET_VMSLOTS_INT(arg_value.c, arg_slot); - break; - case T_BYTE: - SET_VMSLOTS_INT(arg_value.b, arg_slot); - break; - case T_SHORT: - SET_VMSLOTS_INT(arg_value.s, arg_slot); - break; - case T_INT: - SET_VMSLOTS_INT(arg_value.i, arg_slot); - break; - case T_FLOAT: - SET_VMSLOTS_FLOAT(arg_value.f, arg_slot); - break; - case T_LONG: - SET_VMSLOTS_LONG(arg_value.j, arg_slot); - break; - case T_DOUBLE: - SET_VMSLOTS_DOUBLE(arg_value.d, arg_slot); - break; - default: - tty->print_cr("unhandled type %s", type2name(arg_type)); - ShouldNotReachHere(); - } - } - break; - - default: - tty->print_cr("unhandled entry_kind %s", - MethodHandles::entry_name(entry_kind)); - ShouldNotReachHere(); - } - - // Continue along the chain - if (direct_to_method) { - if (method == NULL) { - method = - (Method*) java_lang_invoke_MethodHandle::vmtarget(method_handle); - } - address entry_point = method->from_interpreted_entry(); - Interpreter::invoke_method(method, entry_point, THREAD); - } - else { - process_method_handle( - java_lang_invoke_MethodHandle::next_target(method_handle), THREAD); - } - // NB all oops now trashed - - // Adapt the result type, if necessary - if (src_rtype != dst_rtype && !HAS_PENDING_EXCEPTION) { - switch (dst_rtype) { - case T_VOID: - for (int i = 0; i < type2size[src_rtype]; i++) - stack->pop(); - return; - - case T_INT: - switch (src_rtype) { - case T_VOID: - stack->overflow_check(1, CHECK); - stack->push(0); - return; - - case T_BOOLEAN: - case T_CHAR: - case T_BYTE: - case T_SHORT: - return; - } - // INT results sometimes need narrowing - case T_BOOLEAN: - case T_CHAR: - case T_BYTE: - case T_SHORT: - switch (src_rtype) { - case T_INT: - return; - } - } - - tty->print_cr("unhandled conversion:"); - tty->print_cr("src_rtype = %s", type2name(src_rtype)); - tty->print_cr("dst_rtype = %s", type2name(dst_rtype)); - ShouldNotReachHere(); - } -} - // The new slots will be inserted before slot insert_before. // Slots < insert_before will have the same slot number after the insert. // Slots >= insert_before will become old_slot + num_slots. @@ -1380,10 +851,6 @@ address AbstractInterpreterGenerator::generate_method_entry( entry_point = ((InterpreterGenerator*) this)->generate_abstract_entry(); break; - case Interpreter::method_handle: - entry_point = ((InterpreterGenerator*) this)->generate_method_handle_entry(); - break; - case Interpreter::java_lang_math_sin: case Interpreter::java_lang_math_cos: case Interpreter::java_lang_math_tan: @@ -1391,6 +858,8 @@ address AbstractInterpreterGenerator::generate_method_entry( case Interpreter::java_lang_math_log: case Interpreter::java_lang_math_log10: case Interpreter::java_lang_math_sqrt: + case Interpreter::java_lang_math_pow: + case Interpreter::java_lang_math_exp: entry_point = ((InterpreterGenerator*) this)->generate_math_entry(kind); break; diff --git a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.hpp b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.hpp index 2faae7169ab..3a6bd52f2cb 100644 --- a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.hpp +++ b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.hpp @@ -36,7 +36,6 @@ static int native_entry(Method* method, intptr_t UNUSED, TRAPS); static int accessor_entry(Method* method, intptr_t UNUSED, TRAPS); static int empty_entry(Method* method, intptr_t UNUSED, TRAPS); - static int method_handle_entry(Method* method, intptr_t UNUSED, TRAPS); public: // Main loop of normal_entry @@ -44,7 +43,6 @@ private: // Helpers for method_handle_entry - static void process_method_handle(oop method_handle, TRAPS); static void insert_vmslots(int insert_before, int num_slots, TRAPS); static void remove_vmslots(int first_slot, int num_slots, TRAPS); static BasicType result_type_of_handle(oop method_handle); diff --git a/hotspot/src/cpu/zero/vm/frame_zero.cpp b/hotspot/src/cpu/zero/vm/frame_zero.cpp index 6ce4b23bc6b..8643af5953f 100644 --- a/hotspot/src/cpu/zero/vm/frame_zero.cpp +++ b/hotspot/src/cpu/zero/vm/frame_zero.cpp @@ -351,7 +351,7 @@ void SharkFrame::identify_word(int frame_index, switch (offset) { case pc_off: strncpy(fieldbuf, "pc", buflen); - if (method()->is_oop()) { + if (method()->is_method()) { nmethod *code = method()->code(); if (code && code->pc_desc_at(pc())) { SimpleScopeDesc ssd(code, pc()); @@ -367,7 +367,7 @@ void SharkFrame::identify_word(int frame_index, case method_off: strncpy(fieldbuf, "method", buflen); - if (method()->is_oop()) { + if (method()->is_method()) { method()->name_and_sig_as_C_string(valuebuf, buflen); } return; @@ -378,7 +378,7 @@ void SharkFrame::identify_word(int frame_index, } // Variable part - if (method()->is_oop()) { + if (method()->is_method()) { identify_vp_word(frame_index, addr_of_word(offset), addr_of_word(header_words + 1), unextended_sp() + method()->max_stack(), @@ -430,4 +430,3 @@ intptr_t *frame::initial_deoptimization_info() { // unused... but returns fp() to minimize changes introduced by 7087445 return fp(); } - diff --git a/hotspot/src/cpu/zero/vm/frame_zero.inline.hpp b/hotspot/src/cpu/zero/vm/frame_zero.inline.hpp index e41ec13798a..2bc703ae032 100644 --- a/hotspot/src/cpu/zero/vm/frame_zero.inline.hpp +++ b/hotspot/src/cpu/zero/vm/frame_zero.inline.hpp @@ -36,6 +36,8 @@ inline frame::frame() { _deopt_state = unknown; } +inline address frame::sender_pc() const { ShouldNotCallThis(); } + inline frame::frame(ZeroFrame* zf, intptr_t* sp) { _zeroframe = zf; _sp = sp; diff --git a/hotspot/src/cpu/zero/vm/icBuffer_zero.cpp b/hotspot/src/cpu/zero/vm/icBuffer_zero.cpp index af2f8bec5c1..95d0e115a66 100644 --- a/hotspot/src/cpu/zero/vm/icBuffer_zero.cpp +++ b/hotspot/src/cpu/zero/vm/icBuffer_zero.cpp @@ -40,7 +40,7 @@ int InlineCacheBuffer::ic_stub_code_size() { } void InlineCacheBuffer::assemble_ic_buffer_code(address code_begin, - Metadata* cached_oop, + void* cached_oop, address entry_point) { // NB ic_stub_code_size() must return the size of the code we generate ShouldNotCallThis(); @@ -51,7 +51,6 @@ address InlineCacheBuffer::ic_buffer_entry_point(address code_begin) { ShouldNotCallThis(); } -Metadata* InlineCacheBuffer::ic_buffer_cached_oop(address code_begin) { - // NB ic_stub_code_size() must return the size of the code we generate +void* InlineCacheBuffer::ic_buffer_cached_value(address code_begin) { ShouldNotCallThis(); } diff --git a/hotspot/src/cpu/zero/vm/methodHandles_zero.cpp b/hotspot/src/cpu/zero/vm/methodHandles_zero.cpp index 35f4b11f5d3..ea1bc0eedc1 100644 --- a/hotspot/src/cpu/zero/vm/methodHandles_zero.cpp +++ b/hotspot/src/cpu/zero/vm/methodHandles_zero.cpp @@ -24,26 +24,159 @@ */ #include "precompiled.hpp" +#include "interpreter/interpreterGenerator.hpp" #include "interpreter/interpreter.hpp" #include "memory/allocation.inline.hpp" #include "prims/methodHandles.hpp" -int MethodHandles::adapter_conversion_ops_supported_mask() { - return ((1<zero_stack(); + InterpreterFrame *frame = thread->top_zero_frame()->as_interpreter_frame(); + interpreterState istate = frame->interpreter_state(); + + // Trim back the stack to put the parameters at the top + stack->set_sp(istate->stack() + 1); + + Interpreter::invoke_method(method, method->from_interpreted_entry(), THREAD); + + // Convert the result + istate->set_stack(stack->sp() - 1); + } -void MethodHandles::generate_method_handle_stub(MacroAssembler* masm, - MethodHandles::EntryKind ek) { - init_entry(ek, (MethodHandleEntry *) ek); +oop MethodHandles::popFromStack(TRAPS) { + + JavaThread *thread = (JavaThread *) THREAD; + InterpreterFrame *frame = thread->top_zero_frame()->as_interpreter_frame(); + interpreterState istate = frame->interpreter_state(); + intptr_t* topOfStack = istate->stack(); + + oop top = STACK_OBJECT(-1); + MORE_STACK(-1); + istate->set_stack(topOfStack); + + return top; + +} + +int MethodHandles::method_handle_entry_invokeBasic(Method* method, intptr_t UNUSED, TRAPS) { + + JavaThread *thread = (JavaThread *) THREAD; + InterpreterFrame *frame = thread->top_zero_frame()->as_interpreter_frame(); + interpreterState istate = frame->interpreter_state(); + intptr_t* topOfStack = istate->stack(); + + // 'this' is a MethodHandle. We resolve the target method by accessing this.form.vmentry.vmtarget. + int numArgs = method->size_of_parameters(); + oop lform1 = java_lang_invoke_MethodHandle::form(STACK_OBJECT(-numArgs)); // this.form + oop vmEntry1 = java_lang_invoke_LambdaForm::vmentry(lform1); + Method* vmtarget = (Method*) java_lang_invoke_MemberName::vmtarget(vmEntry1); + + invoke_target(vmtarget, THREAD); + + // No deoptimized frames on the stack + return 0; +} + +int MethodHandles::method_handle_entry_linkToStaticOrSpecial(Method* method, intptr_t UNUSED, TRAPS) { + + // Pop appendix argument from stack. This is a MemberName which we resolve to the + // target method. + oop vmentry = popFromStack(THREAD); + + Method* vmtarget = (Method*) java_lang_invoke_MemberName::vmtarget(vmentry); + + invoke_target(vmtarget, THREAD); + + return 0; +} + +int MethodHandles::method_handle_entry_linkToInterface(Method* method, intptr_t UNUSED, TRAPS) { + JavaThread *thread = (JavaThread *) THREAD; + InterpreterFrame *frame = thread->top_zero_frame()->as_interpreter_frame(); + interpreterState istate = frame->interpreter_state(); + + // Pop appendix argument from stack. This is a MemberName which we resolve to the + // target method. + oop vmentry = popFromStack(THREAD); + intptr_t* topOfStack = istate->stack(); + + // Resolve target method by looking up in the receiver object's itable. + Klass* clazz = java_lang_Class::as_Klass(java_lang_invoke_MemberName::clazz(vmentry)); + intptr_t vmindex = java_lang_invoke_MemberName::vmindex(vmentry); + Method* target = (Method*) java_lang_invoke_MemberName::vmtarget(vmentry); + + int numArgs = target->size_of_parameters(); + oop recv = STACK_OBJECT(-numArgs); + + InstanceKlass* klass_part = InstanceKlass::cast(recv->klass()); + itableOffsetEntry* ki = (itableOffsetEntry*) klass_part->start_of_itable(); + int i; + for ( i = 0 ; i < klass_part->itable_length() ; i++, ki++ ) { + if (ki->interface_klass() == clazz) break; + } + + itableMethodEntry* im = ki->first_method_entry(recv->klass()); + Method* vmtarget = im[vmindex].method(); + + invoke_target(vmtarget, THREAD); + + return 0; +} + +int MethodHandles::method_handle_entry_linkToVirtual(Method* method, intptr_t UNUSED, TRAPS) { + JavaThread *thread = (JavaThread *) THREAD; + + InterpreterFrame *frame = thread->top_zero_frame()->as_interpreter_frame(); + interpreterState istate = frame->interpreter_state(); + + // Pop appendix argument from stack. This is a MemberName which we resolve to the + // target method. + oop vmentry = popFromStack(THREAD); + intptr_t* topOfStack = istate->stack(); + + // Resolve target method by looking up in the receiver object's vtable. + intptr_t vmindex = java_lang_invoke_MemberName::vmindex(vmentry); + Method* target = (Method*) java_lang_invoke_MemberName::vmtarget(vmentry); + int numArgs = target->size_of_parameters(); + oop recv = STACK_OBJECT(-numArgs); + Klass* clazz = recv->klass(); + Klass* klass_part = InstanceKlass::cast(clazz); + klassVtable* vtable = klass_part->vtable(); + Method* vmtarget = vtable->method_at(vmindex); + + invoke_target(vmtarget, THREAD); + + return 0; +} + +int MethodHandles::method_handle_entry_invalid(Method* method, intptr_t UNUSED, TRAPS) { + ShouldNotReachHere(); + return 0; +} + +address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* masm, + vmIntrinsics::ID iid) { + switch (iid) { + case vmIntrinsics::_invokeGeneric: + case vmIntrinsics::_compiledLambdaForm: + // Perhaps surprisingly, the symbolic references visible to Java are not directly used. + // They are linked to Java-generated adapters via MethodHandleNatives.linkMethod. + // They all allow an appendix argument. + return InterpreterGenerator::generate_entry_impl(masm, (address) MethodHandles::method_handle_entry_invalid); + case vmIntrinsics::_invokeBasic: + return InterpreterGenerator::generate_entry_impl(masm, (address) MethodHandles::method_handle_entry_invokeBasic); + case vmIntrinsics::_linkToStatic: + case vmIntrinsics::_linkToSpecial: + return InterpreterGenerator::generate_entry_impl(masm, (address) MethodHandles::method_handle_entry_linkToStaticOrSpecial); + case vmIntrinsics::_linkToInterface: + return InterpreterGenerator::generate_entry_impl(masm, (address) MethodHandles::method_handle_entry_linkToInterface); + case vmIntrinsics::_linkToVirtual: + return InterpreterGenerator::generate_entry_impl(masm, (address) MethodHandles::method_handle_entry_linkToVirtual); + default: + ShouldNotReachHere(); + return NULL; + } } diff --git a/hotspot/src/cpu/zero/vm/methodHandles_zero.hpp b/hotspot/src/cpu/zero/vm/methodHandles_zero.hpp index a71fce34f12..f4eec005c4d 100644 --- a/hotspot/src/cpu/zero/vm/methodHandles_zero.hpp +++ b/hotspot/src/cpu/zero/vm/methodHandles_zero.hpp @@ -26,6 +26,14 @@ // Adapters enum /* platform_dependent_constants */ { - adapter_code_size = 0 + adapter_code_size = sizeof(ZeroEntry) * (Interpreter::method_handle_invoke_LAST - Interpreter::method_handle_invoke_FIRST + 1) }; +private: + static oop popFromStack(TRAPS); + static void invoke_target(Method* method, TRAPS); + static int method_handle_entry_invokeBasic(Method* method, intptr_t UNUSED, TRAPS); + static int method_handle_entry_linkToStaticOrSpecial(Method* method, intptr_t UNUSED, TRAPS); + static int method_handle_entry_linkToVirtual(Method* method, intptr_t UNUSED, TRAPS); + static int method_handle_entry_linkToInterface(Method* method, intptr_t UNUSED, TRAPS); + static int method_handle_entry_invalid(Method* method, intptr_t UNUSED, TRAPS); diff --git a/hotspot/src/cpu/zero/vm/register_zero.hpp b/hotspot/src/cpu/zero/vm/register_zero.hpp index 0bcc7638248..1ce7141adaf 100644 --- a/hotspot/src/cpu/zero/vm/register_zero.hpp +++ b/hotspot/src/cpu/zero/vm/register_zero.hpp @@ -114,5 +114,8 @@ class ConcreteRegisterImpl : public AbstractRegisterImpl { }; CONSTANT_REGISTER_DECLARATION(Register, noreg, (-1)); +#ifndef DONT_USE_REGISTER_DEFINES +#define noreg ((Register)(noreg_RegisterEnumValue)) +#endif #endif // CPU_ZERO_VM_REGISTER_ZERO_HPP diff --git a/hotspot/src/cpu/zero/vm/relocInfo_zero.cpp b/hotspot/src/cpu/zero/vm/relocInfo_zero.cpp index 13f095e4746..ed7ee7bca6a 100644 --- a/hotspot/src/cpu/zero/vm/relocInfo_zero.cpp +++ b/hotspot/src/cpu/zero/vm/relocInfo_zero.cpp @@ -77,3 +77,7 @@ void poll_return_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dst) { ShouldNotCallThis(); } + +void metadata_Relocation::pd_fix_value(address x) { + ShouldNotCallThis(); +} diff --git a/hotspot/src/cpu/zero/vm/sharedRuntime_zero.cpp b/hotspot/src/cpu/zero/vm/sharedRuntime_zero.cpp index 3cb8cd7e46a..123d71ec044 100644 --- a/hotspot/src/cpu/zero/vm/sharedRuntime_zero.cpp +++ b/hotspot/src/cpu/zero/vm/sharedRuntime_zero.cpp @@ -35,6 +35,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/vframeArray.hpp" #include "vmreg_zero.inline.hpp" + #ifdef COMPILER1 #include "c1/c1_Runtime1.hpp" #endif @@ -47,6 +48,12 @@ #endif + +static address zero_null_code_stub() { + address start = ShouldNotCallThisStub(); + return start; +} + int SharedRuntime::java_calling_convention(const BasicType *sig_bt, VMRegPair *regs, int total_args_passed, @@ -63,16 +70,14 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters( AdapterFingerPrint *fingerprint) { return AdapterHandlerLibrary::new_entry( fingerprint, - ShouldNotCallThisStub(), - ShouldNotCallThisStub(), - ShouldNotCallThisStub()); + CAST_FROM_FN_PTR(address,zero_null_code_stub), + CAST_FROM_FN_PTR(address,zero_null_code_stub), + CAST_FROM_FN_PTR(address,zero_null_code_stub)); } nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, methodHandle method, int compile_id, - int total_args_passed, - int max_arg, BasicType *sig_bt, VMRegPair *regs, BasicType ret_type) { @@ -96,19 +101,20 @@ uint SharedRuntime::out_preserve_stack_slots() { ShouldNotCallThis(); } +JRT_LEAF(void, zero_stub()) + ShouldNotCallThis(); +JRT_END + static RuntimeStub* generate_empty_runtime_stub(const char* name) { - CodeBuffer buffer(name, 0, 0); - return RuntimeStub::new_runtime_stub(name, &buffer, 0, 0, NULL, false); + return CAST_FROM_FN_PTR(RuntimeStub*,zero_stub); } static SafepointBlob* generate_empty_safepoint_blob() { - CodeBuffer buffer("handler_blob", 0, 0); - return SafepointBlob::create(&buffer, NULL, 0); + return CAST_FROM_FN_PTR(SafepointBlob*,zero_stub); } static DeoptimizationBlob* generate_empty_deopt_blob() { - CodeBuffer buffer("handler_blob", 0, 0); - return DeoptimizationBlob::create(&buffer, NULL, 0, 0, 0, 0); + return CAST_FROM_FN_PTR(DeoptimizationBlob*,zero_stub); } @@ -116,7 +122,7 @@ void SharedRuntime::generate_deopt_blob() { _deopt_blob = generate_empty_deopt_blob(); } -SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, bool cause_return) { +SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_type) { return generate_empty_safepoint_blob(); } @@ -124,6 +130,7 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha return generate_empty_runtime_stub("resolve_blob"); } + int SharedRuntime::c_calling_convention(const BasicType *sig_bt, VMRegPair *regs, int total_args_passed) { diff --git a/hotspot/src/share/vm/asm/codeBuffer.cpp b/hotspot/src/share/vm/asm/codeBuffer.cpp index bb1ae18fcb5..a3fc112f54f 100644 --- a/hotspot/src/share/vm/asm/codeBuffer.cpp +++ b/hotspot/src/share/vm/asm/codeBuffer.cpp @@ -758,7 +758,7 @@ void CodeBuffer::relocate_code_to(CodeBuffer* dest) const { } } - if (dest->blob() == NULL) { + if (dest->blob() == NULL && dest_filled != NULL) { // Destination is a final resting place, not just another buffer. // Normalize uninitialized bytes in the final padding. Copy::fill_to_bytes(dest_filled, dest_end - dest_filled, diff --git a/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp b/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp index b0870c0f1e2..4dc2ef451c2 100644 --- a/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp +++ b/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp @@ -320,6 +320,7 @@ class AbstractInterpreterGenerator: public StackObj { void bang_stack_shadow_pages(bool native_call); void generate_all(); + void initialize_method_handle_entries(); public: AbstractInterpreterGenerator(StubQueue* _code); diff --git a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp index 6c18761dba2..a9d6cc9a981 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp @@ -235,10 +235,6 @@ #endif #endif -// JavaStack Implementation -#define MORE_STACK(count) \ - (topOfStack -= ((count) * Interpreter::stackElementWords)) - #define UPDATE_PC(opsize) {pc += opsize; } /* @@ -575,7 +571,7 @@ BytecodeInterpreter::run(interpreterState istate) { /* 0xE0 */ &&opc_default, &&opc_default, &&opc_default, &&opc_default, /* 0xE4 */ &&opc_default, &&opc_fast_aldc, &&opc_fast_aldc_w, &&opc_return_register_finalizer, -/* 0xE8 */ &&opc_default, &&opc_default, &&opc_default, &&opc_default, +/* 0xE8 */ &&opc_invokehandle,&&opc_default, &&opc_default, &&opc_default, /* 0xEC */ &&opc_default, &&opc_default, &&opc_default, &&opc_default, /* 0xF0 */ &&opc_default, &&opc_default, &&opc_default, &&opc_default, @@ -1773,7 +1769,7 @@ run: oop obj; if ((Bytecodes::Code)opcode == Bytecodes::_getstatic) { - Klass* k = (Klass*) cache->f1(); + Klass* k = cache->f1_as_klass(); obj = k->java_mirror(); MORE_STACK(1); // Assume single slot push } else { @@ -1885,7 +1881,7 @@ run: --count; } if ((Bytecodes::Code)opcode == Bytecodes::_putstatic) { - Klass* k = (Klass*) cache->f1(); + Klass* k = cache->f1_as_klass(); obj = k->java_mirror(); } else { --count; @@ -2190,6 +2186,7 @@ run: } CASE(_invokedynamic): { + if (!EnableInvokeDynamic) { // We should not encounter this bytecode if !EnableInvokeDynamic. // The verifier will stop it. However, if we get past the verifier, @@ -2199,30 +2196,68 @@ run: ShouldNotReachHere(); } - int index = Bytes::get_native_u4(pc+1); + u4 index = Bytes::get_native_u4(pc+1); + ConstantPoolCacheEntry* cache = cp->constant_pool()->invokedynamic_cp_cache_entry_at(index); // We are resolved if the resolved_references field contains a non-null object (CallSite, etc.) // This kind of CP cache entry does not need to match the flags byte, because // there is a 1-1 relation between bytecode type and CP entry type. - ConstantPool* constants = METHOD->constants(); - oop result = constants->resolved_references()->obj_at(index); - if (result == NULL) { + if (! cache->is_resolved((Bytecodes::Code) opcode)) { CALL_VM(InterpreterRuntime::resolve_invokedynamic(THREAD), handle_exception); - result = THREAD->vm_result(); + cache = cp->constant_pool()->invokedynamic_cp_cache_entry_at(index); } - VERIFY_OOP(result); - oop method_handle = java_lang_invoke_CallSite::target(result); - CHECK_NULL(method_handle); + Method* method = cache->f1_as_method(); + VERIFY_OOP(method); - istate->set_msg(call_method_handle); - istate->set_callee((Method*) method_handle); + if (cache->has_appendix()) { + ConstantPool* constants = METHOD->constants(); + SET_STACK_OBJECT(cache->appendix_if_resolved(constants), 0); + MORE_STACK(1); + } + + istate->set_msg(call_method); + istate->set_callee(method); + istate->set_callee_entry_point(method->from_interpreted_entry()); istate->set_bcp_advance(5); UPDATE_PC_AND_RETURN(0); // I'll be back... } + CASE(_invokehandle): { + + if (!EnableInvokeDynamic) { + ShouldNotReachHere(); + } + + u2 index = Bytes::get_native_u2(pc+1); + ConstantPoolCacheEntry* cache = cp->entry_at(index); + + if (! cache->is_resolved((Bytecodes::Code) opcode)) { + CALL_VM(InterpreterRuntime::resolve_invokehandle(THREAD), + handle_exception); + cache = cp->entry_at(index); + } + + Method* method = cache->f1_as_method(); + + VERIFY_OOP(method); + + if (cache->has_appendix()) { + ConstantPool* constants = METHOD->constants(); + SET_STACK_OBJECT(cache->appendix_if_resolved(constants), 0); + MORE_STACK(1); + } + + istate->set_msg(call_method); + istate->set_callee(method); + istate->set_callee_entry_point(method->from_interpreted_entry()); + istate->set_bcp_advance(3); + + UPDATE_PC_AND_RETURN(0); // I'll be back... + } + CASE(_invokeinterface): { u2 index = Bytes::get_native_u2(pc+1); diff --git a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.hpp b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.hpp index c1614cdf8e5..d528034d3f0 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.hpp +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.hpp @@ -50,6 +50,10 @@ #ifdef CC_INTERP +// JavaStack Implementation +#define MORE_STACK(count) \ + (topOfStack -= ((count) * Interpreter::stackElementWords)) + // CVM definitions find hotspot equivalents... union VMJavaVal64 { @@ -107,7 +111,6 @@ public: rethrow_exception, // unwinding and throwing exception // requests to frame manager from C++ interpreter call_method, // request for new frame from interpreter, manager responds with method_entry - call_method_handle, // like the above, except the callee is a method handle return_from_method, // request from interpreter to unwind, manager responds with method_continue more_monitors, // need a new monitor throwing_exception, // unwind stack and rethrow diff --git a/hotspot/src/share/vm/interpreter/cppInterpreter.cpp b/hotspot/src/share/vm/interpreter/cppInterpreter.cpp index 9a6669519f6..0007aa8be25 100644 --- a/hotspot/src/share/vm/interpreter/cppInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/cppInterpreter.cpp @@ -117,7 +117,6 @@ void CppInterpreterGenerator::generate_all() { method_entry(empty); method_entry(accessor); method_entry(abstract); - method_entry(method_handle); method_entry(java_lang_math_sin ); method_entry(java_lang_math_cos ); method_entry(java_lang_math_tan ); @@ -125,7 +124,12 @@ void CppInterpreterGenerator::generate_all() { method_entry(java_lang_math_sqrt ); method_entry(java_lang_math_log ); method_entry(java_lang_math_log10 ); + method_entry(java_lang_math_pow ); + method_entry(java_lang_math_exp ); method_entry(java_lang_ref_reference_get); + + initialize_method_handle_entries(); + Interpreter::_native_entry_begin = Interpreter::code()->code_end(); method_entry(native); method_entry(native_synchronized); diff --git a/hotspot/src/share/vm/interpreter/interpreter.cpp b/hotspot/src/share/vm/interpreter/interpreter.cpp index dad8f9ec751..4513eebb79c 100644 --- a/hotspot/src/share/vm/interpreter/interpreter.cpp +++ b/hotspot/src/share/vm/interpreter/interpreter.cpp @@ -464,3 +464,11 @@ void AbstractInterpreterGenerator::bang_stack_shadow_pages(bool native_call) { } } } + +void AbstractInterpreterGenerator::initialize_method_handle_entries() { + // method handle entry kinds are generated later in MethodHandlesAdapterGenerator::generate: + for (int i = Interpreter::method_handle_invoke_FIRST; i <= Interpreter::method_handle_invoke_LAST; i++) { + Interpreter::MethodKind kind = (Interpreter::MethodKind) i; + Interpreter::_entry_table[kind] = Interpreter::_entry_table[Interpreter::abstract]; + } +} diff --git a/hotspot/src/share/vm/interpreter/templateInterpreter.cpp b/hotspot/src/share/vm/interpreter/templateInterpreter.cpp index beb99fa15e4..53e50b1c7fe 100644 --- a/hotspot/src/share/vm/interpreter/templateInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/templateInterpreter.cpp @@ -373,11 +373,7 @@ void TemplateInterpreterGenerator::generate_all() { method_entry(java_lang_math_pow ) method_entry(java_lang_ref_reference_get) - // method handle entry kinds are generated later in MethodHandlesAdapterGenerator::generate: - for (int i = Interpreter::method_handle_invoke_FIRST; i <= Interpreter::method_handle_invoke_LAST; i++) { - Interpreter::MethodKind kind = (Interpreter::MethodKind) i; - Interpreter::_entry_table[kind] = Interpreter::_entry_table[Interpreter::abstract]; - } + initialize_method_handle_entries(); // all native method kinds (must be one contiguous block) Interpreter::_native_entry_begin = Interpreter::code()->code_end(); diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index 9159ad945af..367f3f8e009 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -2474,7 +2474,7 @@ typedef BinaryTreeDictionary MetablockTreeDictionary; /* frame */ \ /**********************/ \ \ - X86_ONLY(declare_constant(frame::entry_frame_call_wrapper_offset)) \ + NOT_ZERO(X86_ONLY(declare_constant(frame::entry_frame_call_wrapper_offset))) \ declare_constant(frame::pc_return_offset) \ \ /*************/ \ diff --git a/hotspot/src/share/vm/utilities/macros.hpp b/hotspot/src/share/vm/utilities/macros.hpp index e0e853c3c13..64e331d90b0 100644 --- a/hotspot/src/share/vm/utilities/macros.hpp +++ b/hotspot/src/share/vm/utilities/macros.hpp @@ -282,6 +282,22 @@ #define NOT_WIN64(code) code #endif +#if defined(ZERO) +#define ZERO_ONLY(code) code +#define NOT_ZERO(code) +#else +#define ZERO_ONLY(code) +#define NOT_ZERO(code) code +#endif + +#if defined(SHARK) +#define SHARK_ONLY(code) code +#define NOT_SHARK(code) +#else +#define SHARK_ONLY(code) +#define NOT_SHARK(code) code +#endif + #if defined(IA32) || defined(AMD64) #define X86 #define X86_ONLY(code) code From cb6de3855439cf7956b1da0967b5520be39c01be Mon Sep 17 00:00:00 2001 From: Serguei Spitsyn Date: Mon, 29 Oct 2012 11:35:20 -0700 Subject: [PATCH 26/59] 6533010: SPEC: A few broken links in jvmti.html Fix the incorrect links in jvmti.html reported by the LinkCheck tool Reviewed-by: jjh, dholmes --- hotspot/src/share/vm/prims/jvmti.xml | 47 ++++++++++++--------- hotspot/src/share/vm/prims/jvmtiEnvBase.hpp | 2 +- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/hotspot/src/share/vm/prims/jvmti.xml b/hotspot/src/share/vm/prims/jvmti.xml index 512e3cb0033..517083f20e3 100644 --- a/hotspot/src/share/vm/prims/jvmti.xml +++ b/hotspot/src/share/vm/prims/jvmti.xml @@ -1,7 +1,7 @@