diff --git a/make/java/java/FILES_java.gmk b/make/java/java/FILES_java.gmk
index f9fdea5cf069d74c50e08d8ea907879eb4679fc8..acbc8a7323098b3ff61ef5d088b3623337f5a4f7 100644
--- a/make/java/java/FILES_java.gmk
+++ b/make/java/java/FILES_java.gmk
@@ -413,6 +413,7 @@ JAVA_JAVA_java = \
java/io/FilePermission.java \
java/io/Serializable.java \
java/io/Externalizable.java \
+ java/io/SerialCallbackContext.java \
java/io/Bits.java \
java/io/ObjectInput.java \
java/io/ObjectInputStream.java \
diff --git a/make/java/jli/Makefile b/make/java/jli/Makefile
index 40ddc17e358d13546e3cb19b1c4aa03a88a42d41..9c1b9bc7c835cb02b629a94ef3b3a3c6dec54e75 100644
--- a/make/java/jli/Makefile
+++ b/make/java/jli/Makefile
@@ -148,14 +148,9 @@ include $(BUILDDIR)/common/Library.gmk
#
ifeq ($(PLATFORM), windows)
-STATIC_LIBRARY_DIR = $(OBJDIR)/static
-STATIC_LIBRARY_NAME = $(LIBPREFIX)$(LIBRARY).lib
-STATIC_LIBRARY = $(STATIC_LIBRARY_DIR)/$(STATIC_LIBRARY_NAME)
+STATIC_LIBRARY = $(OBJDIR)/static/$(LIBPREFIX)$(LIBRARY).lib
-$(STATIC_LIBRARY_DIR): $(OBJDIR)
- @$(MKDIR) $(STATIC_LIBRARY_DIR)
-
-$(STATIC_LIBRARY): $(STATIC_LIBRARY_DIR)
+$(STATIC_LIBRARY): $(FILES_o)
@$(prep-target)
$(LIBEXE) -nologo -out:$@ $(FILES_o)
diff --git a/make/java/nio/FILES_java.gmk b/make/java/nio/FILES_java.gmk
index e49d5267a4761ffce938d64aaedb157615ce3a4c..5a00e3172f3c8c0a080f0ae53f39637bf37803a3 100644
--- a/make/java/nio/FILES_java.gmk
+++ b/make/java/nio/FILES_java.gmk
@@ -33,7 +33,6 @@ FILES_src = \
java/nio/channels/AsynchronousByteChannel.java \
java/nio/channels/AsynchronousChannel.java \
java/nio/channels/AsynchronousChannelGroup.java \
- java/nio/channels/AsynchronousDatagramChannel.java \
java/nio/channels/AsynchronousFileChannel.java \
java/nio/channels/AsynchronousServerSocketChannel.java \
java/nio/channels/AsynchronousSocketChannel.java \
@@ -207,7 +206,6 @@ FILES_src = \
sun/nio/ch/SelChImpl.java \
sun/nio/ch/ServerSocketAdaptor.java \
sun/nio/ch/ServerSocketChannelImpl.java \
- sun/nio/ch/SimpleAsynchronousDatagramChannelImpl.java \
sun/nio/ch/SinkChannelImpl.java \
sun/nio/ch/SocketAdaptor.java \
sun/nio/ch/SocketChannelImpl.java \
diff --git a/make/javax/sound/jsoundds/Makefile b/make/javax/sound/jsoundds/Makefile
index 178212437c7085dcb0af9d4592895edc56e8881d..e38a98535efc7f1caff976ffcbecb8c4d1a0be38 100644
--- a/make/javax/sound/jsoundds/Makefile
+++ b/make/javax/sound/jsoundds/Makefile
@@ -53,7 +53,7 @@ FILES_export = \
#
# Extra cc/linker flags.
#
-LDLIBS += dsound.lib winmm.lib user32.lib
+LDLIBS += dsound.lib winmm.lib user32.lib ole32.lib
CPPFLAGS += \
-DUSE_DAUDIO=TRUE \
-I$(SHARE_SRC)/native/com/sun/media/sound \
diff --git a/make/netbeans/jmx/build.properties b/make/netbeans/jmx/build.properties
index fc36497359e8f100b719c0dfa6f59bc48b88a966..e998e58a17f7355fbe1e1b4b589e95af2f7188d3 100644
--- a/make/netbeans/jmx/build.properties
+++ b/make/netbeans/jmx/build.properties
@@ -48,8 +48,8 @@ jar.jmx.name = jmx.jar
jar.jmx.sealed = true
jar.jmx.spec.title = JSR 003, 160, 255 - JMX API
jar.jmx.spec.version = ${project.spec.version}
-jar.jmx.spec.vendor = Sun Microsystems, Inc.
-jar.jmx.impl.title = JSR 003, 160, 255 - OpenJDK 7 JMX API
+jar.jmx.spec.vendor = Oracle Corporation
+jar.jmx.impl.title = JSR 003, 160, 255 - OpenJDK 7 JMX API
jar.jmx.impl.vendor = Project OpenJDK
javadoc.options=-J-Xmx256m
diff --git a/make/sun/javazic/tzdata/VERSION b/make/sun/javazic/tzdata/VERSION
index 804986c10b7cb8cd00462509770a988cdcf416cc..5d158c9e6db90ba0601e1d5eb0a91af6938573e8 100644
--- a/make/sun/javazic/tzdata/VERSION
+++ b/make/sun/javazic/tzdata/VERSION
@@ -21,4 +21,4 @@
# or visit www.oracle.com if you need additional information or have any
# questions.
#
-tzdata2010l
+tzdata2010o
diff --git a/make/sun/javazic/tzdata/asia b/make/sun/javazic/tzdata/asia
index bc69266fa95ffb974007b11b43bc5f000ff85911..d4d8ab1115e28f7c3d6a4403381dba036c8ee25e 100644
--- a/make/sun/javazic/tzdata/asia
+++ b/make/sun/javazic/tzdata/asia
@@ -569,8 +569,8 @@ Rule HK 1953 only - Nov 1 3:30 0 -
Rule HK 1954 1964 - Mar Sun>=18 3:30 1:00 S
Rule HK 1954 only - Oct 31 3:30 0 -
Rule HK 1955 1964 - Nov Sun>=1 3:30 0 -
-Rule HK 1965 1977 - Apr Sun>=16 3:30 1:00 S
-Rule HK 1965 1977 - Oct Sun>=16 3:30 0 -
+Rule HK 1965 1976 - Apr Sun>=16 3:30 1:00 S
+Rule HK 1965 1976 - Oct Sun>=16 3:30 0 -
Rule HK 1973 only - Dec 30 3:30 1:00 S
Rule HK 1979 only - May Sun>=8 3:30 1:00 S
Rule HK 1979 only - Oct Sun>=16 3:30 0 -
diff --git a/make/sun/javazic/tzdata/australasia b/make/sun/javazic/tzdata/australasia
index b406c592761bec4b2ee61da91a5947736747504d..35ab9cfc9b8e48c037bd2e08eaca09f08606d126 100644
--- a/make/sun/javazic/tzdata/australasia
+++ b/make/sun/javazic/tzdata/australasia
@@ -306,13 +306,26 @@ Zone Indian/Cocos 6:27:40 - LMT 1900
# http://www.timeanddate.com/news/time/fiji-dst-ends-march-2010.html
#
+# From Alexander Krivenyshev (2010-10-24):
+# According to Radio Fiji and Fiji Times online, Fiji will end DST 3
+# weeks earlier than expected - on March 6, 2011, not March 27, 2011...
+# Here is confirmation from Government of the Republic of the Fiji Islands,
+# Ministry of Information (fiji.gov.fj) web site:
+#
+# http://www.fiji.gov.fj/index.php?option=com_content&view=article&id=2608:daylight-savings&catid=71:press-releases&Itemid=155
+#
+# or
+#
+# http://www.worldtimezone.com/dst_news/dst_news_fiji04.html
+#
+
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
Rule Fiji 1998 1999 - Nov Sun>=1 2:00 1:00 S
Rule Fiji 1999 2000 - Feb lastSun 3:00 0 -
Rule Fiji 2009 only - Nov 29 2:00 1:00 S
Rule Fiji 2010 only - Mar lastSun 3:00 0 -
Rule Fiji 2010 only - Oct 24 2:00 1:00 S
-Rule Fiji 2011 only - Mar lastSun 3:00 0 -
+Rule Fiji 2011 only - Mar Sun>=1 3:00 0 -
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Pacific/Fiji 11:53:40 - LMT 1915 Oct 26 # Suva
12:00 Fiji FJ%sT # Fiji Time
@@ -509,11 +522,21 @@ Zone Pacific/Pago_Pago 12:37:12 - LMT 1879 Jul 5
# http://www.parliament.gov.ws/documents/acts/Daylight%20Saving%20Act%20%202009%20%28English%29%20-%20Final%207-7-091.pdf
#
+# From Raymond Hughes (2010-10-07):
+# Please see
+#
+# http://www.mcil.gov.ws
+# ,
+# the Ministry of Commerce, Industry and Labour (sideframe) "Last Sunday
+# September 2010 (26/09/10) - adjust clocks forward from 12:00 midnight
+# to 01:00am and First Sunday April 2011 (03/04/11) - adjust clocks
+# backwards from 1:00am to 12:00am"
+
Zone Pacific/Apia 12:33:04 - LMT 1879 Jul 5
-11:26:56 - LMT 1911
-11:30 - SAMT 1950 # Samoa Time
-11:00 - WST 2010 Sep 26
- -11:00 1:00 WSDT 2011 Apr 3
+ -11:00 1:00 WSDT 2011 Apr 3 1:00
-11:00 - WST
# Solomon Is
diff --git a/make/sun/javazic/tzdata/zone.tab b/make/sun/javazic/tzdata/zone.tab
index b63bd11ffc4bbd7dc2753f0f41a16a8704819af0..c1b3e0707eb62fdb1df064852f859586fa754160 100644
--- a/make/sun/javazic/tzdata/zone.tab
+++ b/make/sun/javazic/tzdata/zone.tab
@@ -63,7 +63,7 @@ AQ -6448-06406 Antarctica/Palmer Palmer Station, Anvers Island
AQ -6736+06253 Antarctica/Mawson Mawson Station, Holme Bay
AQ -6835+07758 Antarctica/Davis Davis Station, Vestfold Hills
AQ -6617+11031 Antarctica/Casey Casey Station, Bailey Peninsula
-AQ -7824+10654 Antarctica/Vostok Vostok Station, S Magnetic Pole
+AQ -7824+10654 Antarctica/Vostok Vostok Station, Lake Vostok
AQ -6640+14001 Antarctica/DumontDUrville Dumont-d'Urville Station, Terre Adelie
AQ -690022+0393524 Antarctica/Syowa Syowa Station, E Ongul I
AQ -5430+15857 Antarctica/Macquarie Macquarie Island Station, Macquarie Island
diff --git a/src/share/bin/java.c b/src/share/bin/java.c
index 4c61fb7c8534f788cf05d49ada742b9014c69843..01eeb2a0547ab076b0db300e7e2eed29c301f54f 100644
--- a/src/share/bin/java.c
+++ b/src/share/bin/java.c
@@ -355,7 +355,6 @@ JavaMain(void * _args)
JavaVM *vm = 0;
JNIEnv *env = 0;
- jstring mainClassName;
jclass mainClass;
jmethodID mainID;
jobjectArray mainArgs;
diff --git a/src/share/bin/parse_manifest.c b/src/share/bin/parse_manifest.c
index 2c916d87cb5c33226f93c8088f5baadd279f9880..61b8bdb6b6942e55e32f7eafd3fd3fb6363367ba 100644
--- a/src/share/bin/parse_manifest.c
+++ b/src/share/bin/parse_manifest.c
@@ -72,7 +72,7 @@ inflate_file(int fd, zentry *entry, int *size_out)
if (entry->how == STORED) {
*(char *)((size_t)in + entry->csize) = '\0';
if (size_out) {
- *size_out = entry->csize;
+ *size_out = (int)entry->csize;
}
return (in);
} else if (entry->how == DEFLATED) {
@@ -103,7 +103,7 @@ inflate_file(int fd, zentry *entry, int *size_out)
return (NULL);
}
if (size_out) {
- *size_out = entry->isize;
+ *size_out = (int)entry->isize;
}
return (out);
} else
@@ -317,7 +317,7 @@ find_file(int fd, zentry *entry, const char *file_name)
* manifest. If so, build the entry record from the data found in
* the header located and return success.
*/
- if (CENNAM(p) == JLI_StrLen(file_name) &&
+ if ((size_t)CENNAM(p) == JLI_StrLen(file_name) &&
memcmp((p + CENHDR), file_name, JLI_StrLen(file_name)) == 0) {
if (lseek(fd, base_offset + CENOFF(p), SEEK_SET) < (off_t)0) {
free(buffer);
@@ -606,8 +606,5 @@ JLI_ManifestIterate(const char *jarfile, attribute_closure ac, void *user_data)
}
free(mp);
close(fd);
- if (rc == 0)
- return (0);
- else
- return (-2);
+ return (rc == 0) ? 0 : -2;
}
diff --git a/src/share/bin/wildcard.c b/src/share/bin/wildcard.c
index 3abcd18a97c7168c7ca8283ed7ff5f2d0c582ae1..0d834e635b5c5cf70d9c003e3cefb96b463f22f3 100644
--- a/src/share/bin/wildcard.c
+++ b/src/share/bin/wildcard.c
@@ -290,12 +290,12 @@ FileList_join(FileList fl, char sep)
char *path;
char *p;
for (i = 0, size = 1; i < fl->size; i++)
- size += JLI_StrLen(fl->files[i]) + 1;
+ size += (int)JLI_StrLen(fl->files[i]) + 1;
path = JLI_MemAlloc(size);
for (i = 0, p = path; i < fl->size; i++) {
- int len = JLI_StrLen(fl->files[i]);
+ int len = (int)JLI_StrLen(fl->files[i]);
if (i > 0) *p++ = sep;
memcpy(p, fl->files[i], len);
p += len;
@@ -309,7 +309,7 @@ static FileList
FileList_split(const char *path, char sep)
{
const char *p, *q;
- int len = JLI_StrLen(path);
+ int len = (int)JLI_StrLen(path);
int count;
FileList fl;
for (count = 1, p = path; p < path + len; p++)
@@ -330,7 +330,7 @@ FileList_split(const char *path, char sep)
static int
isJarFileName(const char *filename)
{
- int len = JLI_StrLen(filename);
+ int len = (int)JLI_StrLen(filename);
return (len >= 4) &&
(filename[len - 4] == '.') &&
(equal(filename + len - 3, "jar") ||
@@ -342,8 +342,8 @@ isJarFileName(const char *filename)
static char *
wildcardConcat(const char *wildcard, const char *basename)
{
- int wildlen = JLI_StrLen(wildcard);
- int baselen = JLI_StrLen(basename);
+ int wildlen = (int)JLI_StrLen(wildcard);
+ int baselen = (int)JLI_StrLen(basename);
char *filename = (char *) JLI_MemAlloc(wildlen + baselen);
/* Replace the trailing '*' with basename */
memcpy(filename, wildcard, wildlen-1);
@@ -369,7 +369,7 @@ wildcardFileList(const char *wildcard)
static int
isWildcard(const char *filename)
{
- int len = JLI_StrLen(filename);
+ int len = (int)JLI_StrLen(filename);
return (len > 0) &&
(filename[len - 1] == '*') &&
(len == 1 || IS_FILE_SEPARATOR(filename[len - 2])) &&
diff --git a/src/share/classes/com/sun/crypto/provider/AESCrypt.java b/src/share/classes/com/sun/crypto/provider/AESCrypt.java
index 9bf9c42ae38b30528219c69234e22ce047ec70a6..0940817376b6a11e253295c305aa97d38b5c1a2a 100644
--- a/src/share/classes/com/sun/crypto/provider/AESCrypt.java
+++ b/src/share/classes/com/sun/crypto/provider/AESCrypt.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 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
@@ -253,7 +253,8 @@ final class AESCrypt extends SymmetricCipher implements AESConstants
for (j = 0; j < 8; j++) {
if (AA[i][j] != 0) {
AA[i][j] = (byte)
- alog[(255 + log[AA[i][j] & 0xFF] - log[pivot & 0xFF]) % 255];
+ alog[(255 + log[AA[i][j] & 0xFF] - log[pivot & 0xFF])
+ % 255];
}
}
for (t = 0; t < 4; t++) {
diff --git a/src/share/classes/com/sun/crypto/provider/ARCFOURCipher.java b/src/share/classes/com/sun/crypto/provider/ARCFOURCipher.java
index a474e8c00a77f55eb969af2cd503dd37abb57237..f5b99c1ae51b904b23c904026aa203b95ecf17ed 100644
--- a/src/share/classes/com/sun/crypto/provider/ARCFOURCipher.java
+++ b/src/share/classes/com/sun/crypto/provider/ARCFOURCipher.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -92,7 +92,8 @@ public final class ARCFOURCipher extends CipherSpi {
}
// core crypt code. OFB style, so works for both encryption and decryption
- private void crypt(byte[] in, int inOfs, int inLen, byte[] out, int outOfs) {
+ private void crypt(byte[] in, int inOfs, int inLen, byte[] out,
+ int outOfs) {
if (is < 0) {
// doFinal() was called, need to reset the cipher to initial state
init(lastKey);
diff --git a/src/share/classes/com/sun/crypto/provider/DESedeCipher.java b/src/share/classes/com/sun/crypto/provider/DESedeCipher.java
index 0d75742bd2702d2c3e3b346846911cd51c592580..135ed24d3eed5f9e497e5cf095fa09907e003c28 100644
--- a/src/share/classes/com/sun/crypto/provider/DESedeCipher.java
+++ b/src/share/classes/com/sun/crypto/provider/DESedeCipher.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -31,8 +31,8 @@ import javax.crypto.*;
import javax.crypto.spec.*;
/**
- * This class implements the DESede algorithm (DES-EDE, tripleDES) in its various
- * modes (ECB, CFB, OFB,
+ * This class implements the DESede algorithm (DES-EDE, tripleDES) in
+ * its various modes (ECB, CFB, OFB,
* CBC, PCBC) and padding schemes
* (PKCS5Padding, NoPadding,
* ISO10126Padding).
diff --git a/src/share/classes/com/sun/crypto/provider/DHPrivateKey.java b/src/share/classes/com/sun/crypto/provider/DHPrivateKey.java
index f83ae597b52ea68c7839653d94eeac74fefa379a..4af003d68ae791e3c26298b7a556bb925c0cbb7f 100644
--- a/src/share/classes/com/sun/crypto/provider/DHPrivateKey.java
+++ b/src/share/classes/com/sun/crypto/provider/DHPrivateKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -190,7 +190,8 @@ javax.crypto.interfaces.DHPrivateKey, Serializable {
ike.initCause(e);
throw ike;
} catch (IOException e) {
- InvalidKeyException ike = new InvalidKeyException("Error parsing key encoding: " + e.getMessage());
+ InvalidKeyException ike = new InvalidKeyException(
+ "Error parsing key encoding: " + e.getMessage());
ike.initCause(e);
throw ike;
}
@@ -300,7 +301,8 @@ javax.crypto.interfaces.DHPrivateKey, Serializable {
DerInputStream in = new DerInputStream(this.key);
this.x = in.getBigInteger();
} catch (IOException e) {
- InvalidKeyException ike = new InvalidKeyException("Error parsing key encoding: " + e.getMessage());
+ InvalidKeyException ike = new InvalidKeyException(
+ "Error parsing key encoding: " + e.getMessage());
ike.initCause(e);
throw ike;
}
diff --git a/src/share/classes/com/sun/crypto/provider/DHPublicKey.java b/src/share/classes/com/sun/crypto/provider/DHPublicKey.java
index 9318fbd8caf59919ecc412d3a2f684b810c267d4..46bf6024dd446f3652ff700a81cfea236e72b790 100644
--- a/src/share/classes/com/sun/crypto/provider/DHPublicKey.java
+++ b/src/share/classes/com/sun/crypto/provider/DHPublicKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -180,7 +180,8 @@ javax.crypto.interfaces.DHPublicKey, Serializable {
throw new InvalidKeyException("Private-value length too big");
} catch (IOException e) {
- throw new InvalidKeyException("Error parsing key encoding: " + e.toString());
+ throw new InvalidKeyException(
+ "Error parsing key encoding: " + e.toString());
}
}
@@ -281,7 +282,8 @@ javax.crypto.interfaces.DHPublicKey, Serializable {
DerInputStream in = new DerInputStream(this.key);
this.y = in.getBigInteger();
} catch (IOException e) {
- throw new InvalidKeyException("Error parsing key encoding: " + e.toString());
+ throw new InvalidKeyException(
+ "Error parsing key encoding: " + e.toString());
}
}
diff --git a/src/share/classes/com/sun/crypto/provider/JceKeyStore.java b/src/share/classes/com/sun/crypto/provider/JceKeyStore.java
index 5d54688069914ee0cbca6bd7208f386c44cdc31a..1f37e18579661251f15454cb9036a4af64aff0f1 100644
--- a/src/share/classes/com/sun/crypto/provider/JceKeyStore.java
+++ b/src/share/classes/com/sun/crypto/provider/JceKeyStore.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 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
@@ -764,7 +764,8 @@ public final class JceKeyStore extends KeyStoreSpi {
cf = (CertificateFactory)cfs.get(certType);
} else {
// create new certificate factory
- cf = CertificateFactory.getInstance(certType);
+ cf = CertificateFactory.getInstance(
+ certType);
// store the certificate factory so we can
// reuse it later
cfs.put(certType, cf);
@@ -863,8 +864,9 @@ public final class JceKeyStore extends KeyStoreSpi {
dis.readFully(actual);
for (int i = 0; i < computed.length; i++) {
if (computed[i] != actual[i]) {
- throw new IOException("Keystore was tampered with, or "
- + "password was incorrect");
+ throw new IOException(
+ "Keystore was tampered with, or "
+ + "password was incorrect");
}
}
}
diff --git a/src/share/classes/com/sun/crypto/provider/OAEPParameters.java b/src/share/classes/com/sun/crypto/provider/OAEPParameters.java
index 65a85e753315ed68b10c598d457c11c2ecc865c8..07d613babe8b757f1759e5c23f3c092ef0238b58 100644
--- a/src/share/classes/com/sun/crypto/provider/OAEPParameters.java
+++ b/src/share/classes/com/sun/crypto/provider/OAEPParameters.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -139,7 +139,8 @@ public final class OAEPParameters extends AlgorithmParametersSpi {
if (!val.getOID().equals((Object) OID_MGF1)) {
throw new IOException("Only MGF1 mgf is supported");
}
- AlgorithmId params = AlgorithmId.parse(new DerValue(val.getEncodedParams()));
+ AlgorithmId params = AlgorithmId.parse(
+ new DerValue(val.getEncodedParams()));
String mgfDigestName = convertToStandardName(params.getName());
if (mgfDigestName.equals("SHA-1")) {
mgfSpec = MGF1ParameterSpec.SHA1;
@@ -150,7 +151,8 @@ public final class OAEPParameters extends AlgorithmParametersSpi {
} else if (mgfDigestName.equals("SHA-512")) {
mgfSpec = MGF1ParameterSpec.SHA512;
} else {
- throw new IOException("Unrecognized message digest algorithm");
+ throw new IOException(
+ "Unrecognized message digest algorithm");
}
} else if (data.isContextSpecific((byte) 0x02)) {
// pSource algid
diff --git a/src/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java b/src/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java
index c5c0d844912f832de73bb0483fecc4a45060a282..7f74609c002aeb0720e7d23a4ce6190a0ecfe536 100644
--- a/src/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java
+++ b/src/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -121,8 +121,8 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey {
this.key = deriveKey(prf, passwdBytes, salt, iterCount, keyLength);
}
- private static byte[] deriveKey(final Mac prf, final byte[] password, byte[] salt,
- int iterCount, int keyLengthInBit) {
+ private static byte[] deriveKey(final Mac prf, final byte[] password,
+ byte[] salt, int iterCount, int keyLengthInBit) {
int keyLength = keyLengthInBit/8;
byte[] key = new byte[keyLength];
try {
@@ -155,8 +155,9 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey {
if (this == obj) return true;
if (this.getClass() != obj.getClass()) return false;
SecretKey sk = (SecretKey)obj;
- return prf.getAlgorithm().equalsIgnoreCase(sk.getAlgorithm()) &&
- Arrays.equals(password, sk.getEncoded());
+ return prf.getAlgorithm().equalsIgnoreCase(
+ sk.getAlgorithm()) &&
+ Arrays.equals(password, sk.getEncoded());
}
};
prf.init(macKey);
diff --git a/src/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java b/src/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java
index fce352f1d3c651a58ca24762fca9c3d2585e88eb..e091e90e2c116835e891e9c3150ffe74172658ef 100644
--- a/src/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java
+++ b/src/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -206,7 +206,8 @@ final class PKCS12PBECipherCore {
(algo.equalsIgnoreCase("RC2")?"RC2_40":algo), "SunJCE");
} catch (GeneralSecurityException gse) {
// should never happen
- throw new RuntimeException("SunJCE provider is not configured properly");
+ throw new RuntimeException(
+ "SunJCE provider is not configured properly");
}
try {
params.init(pbeSpec);
@@ -316,7 +317,8 @@ final class PKCS12PBECipherCore {
try {
paramSpec = params.getParameterSpec(PBEParameterSpec.class);
} catch (InvalidParameterSpecException ipse) {
- throw new InvalidAlgorithmParameterException("requires PBE parameters");
+ throw new InvalidAlgorithmParameterException(
+ "requires PBE parameters");
}
}
implInit(opmode, key, paramSpec, random);
diff --git a/src/share/classes/com/sun/crypto/provider/SunJCE.java b/src/share/classes/com/sun/crypto/provider/SunJCE.java
index df68b11aaebfbbb1e254e9d84c15c6c8a13918b9..4b53f84fedc0fc63cc1ee933503afb3b3e2551a5 100644
--- a/src/share/classes/com/sun/crypto/provider/SunJCE.java
+++ b/src/share/classes/com/sun/crypto/provider/SunJCE.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -423,15 +423,31 @@ public final class SunJCE extends Provider {
/*
* SSL/TLS mechanisms
+ *
+ * These are strictly internal implementations and may
+ * be changed at any time. These names were chosen
+ * because PKCS11/SunPKCS11 does not yet have TLS1.2
+ * mechanisms, and it will cause calls to come here.
*/
put("KeyGenerator.SunTlsPrf",
- "com.sun.crypto.provider.TlsPrfGenerator");
- put("KeyGenerator.SunTlsRsaPremasterSecret",
- "com.sun.crypto.provider.TlsRsaPremasterSecretGenerator");
+ "com.sun.crypto.provider.TlsPrfGenerator$V10");
+ put("KeyGenerator.SunTls12Prf",
+ "com.sun.crypto.provider.TlsPrfGenerator$V12");
+
put("KeyGenerator.SunTlsMasterSecret",
- "com.sun.crypto.provider.TlsMasterSecretGenerator");
+ "com.sun.crypto.provider.TlsMasterSecretGenerator");
+ put("Alg.Alias.KeyGenerator.SunTls12MasterSecret",
+ "SunTlsMasterSecret");
+
put("KeyGenerator.SunTlsKeyMaterial",
- "com.sun.crypto.provider.TlsKeyMaterialGenerator");
+ "com.sun.crypto.provider.TlsKeyMaterialGenerator");
+ put("Alg.Alias.KeyGenerator.SunTls12KeyMaterial",
+ "SunTlsKeyMaterial");
+
+ put("KeyGenerator.SunTlsRsaPremasterSecret",
+ "com.sun.crypto.provider.TlsRsaPremasterSecretGenerator");
+ put("Alg.Alias.KeyGenerator.SunTls12RsaPremasterSecret",
+ "SunTlsRsaPremasterSecret");
return null;
}
diff --git a/src/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java b/src/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java
index 91a8d3b5a99230eb3e248c5a5236e92e67ed0202..8e4f6a15d8e5f7dfd1cc07bc8319c60128bf3834 100644
--- a/src/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java
+++ b/src/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -65,12 +65,14 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {
}
this.spec = (TlsKeyMaterialParameterSpec)params;
if ("RAW".equals(spec.getMasterSecret().getFormat()) == false) {
- throw new InvalidAlgorithmParameterException("Key format must be RAW");
+ throw new InvalidAlgorithmParameterException(
+ "Key format must be RAW");
}
- protocolVersion = (spec.getMajorVersion() << 8) | spec.getMinorVersion();
- if ((protocolVersion < 0x0300) || (protocolVersion > 0x0302)) {
- throw new InvalidAlgorithmParameterException
- ("Only SSL 3.0, TLS 1.0, and TLS 1.1 supported");
+ protocolVersion = (spec.getMajorVersion() << 8)
+ | spec.getMinorVersion();
+ if ((protocolVersion < 0x0300) || (protocolVersion > 0x0303)) {
+ throw new InvalidAlgorithmParameterException(
+ "Only SSL 3.0, TLS 1.0/1.1/1.2 supported");
}
}
@@ -80,8 +82,8 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {
protected SecretKey engineGenerateKey() {
if (spec == null) {
- throw new IllegalStateException
- ("TlsKeyMaterialGenerator must be initialized");
+ throw new IllegalStateException(
+ "TlsKeyMaterialGenerator must be initialized");
}
try {
return engineGenerateKey0();
@@ -99,8 +101,8 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {
SecretKey clientMacKey = null;
SecretKey serverMacKey = null;
SecretKey clientCipherKey = null;
- IvParameterSpec clientIv = null;
SecretKey serverCipherKey = null;
+ IvParameterSpec clientIv = null;
IvParameterSpec serverIv = null;
int macLength = spec.getMacKeyLength();
@@ -109,21 +111,33 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {
int keyLength = spec.getCipherKeyLength();
int ivLength = spec.getIvLength();
- int keyBlockLen = macLength + keyLength + (isExportable ? 0 : ivLength);
+ int keyBlockLen = macLength + keyLength
+ + (isExportable ? 0 : ivLength);
keyBlockLen <<= 1;
byte[] keyBlock = new byte[keyBlockLen];
- MessageDigest md5 = MessageDigest.getInstance("MD5");
- MessageDigest sha = MessageDigest.getInstance("SHA1");
+ // These may be used again later for exportable suite calculations.
+ MessageDigest md5 = null;
+ MessageDigest sha = null;
// generate key block
- if (protocolVersion >= 0x0301) {
- // TLS
+ if (protocolVersion >= 0x0303) {
+ // TLS 1.2
+ byte[] seed = concat(serverRandom, clientRandom);
+ keyBlock = doTLS12PRF(masterSecret, LABEL_KEY_EXPANSION, seed,
+ keyBlockLen, spec.getPRFHashAlg(),
+ spec.getPRFHashLength(), spec.getPRFBlockSize());
+ } else if (protocolVersion >= 0x0301) {
+ // TLS 1.0/1.1
+ md5 = MessageDigest.getInstance("MD5");
+ sha = MessageDigest.getInstance("SHA1");
byte[] seed = concat(serverRandom, clientRandom);
- keyBlock = doPRF(masterSecret, LABEL_KEY_EXPANSION, seed,
+ keyBlock = doTLS10PRF(masterSecret, LABEL_KEY_EXPANSION, seed,
keyBlockLen, md5, sha);
} else {
// SSL
+ md5 = MessageDigest.getInstance("MD5");
+ sha = MessageDigest.getInstance("SHA1");
keyBlock = new byte[keyBlockLen];
byte[] tmp = new byte[20];
@@ -169,6 +183,7 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {
String alg = spec.getCipherAlgorithm();
+ // cipher keys
byte[] clientKeyBytes = new byte[keyLength];
System.arraycopy(keyBlock, ofs, clientKeyBytes, 0, keyLength);
ofs += keyLength;
@@ -182,6 +197,7 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {
clientCipherKey = new SecretKeySpec(clientKeyBytes, alg);
serverCipherKey = new SecretKeySpec(serverKeyBytes, alg);
+ // IV keys if needed.
if (ivLength != 0) {
tmp = new byte[ivLength];
@@ -194,21 +210,28 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {
serverIv = new IvParameterSpec(tmp);
}
} else {
+ // if exportable suites, calculate the alternate
// cipher key expansion and IV generation
- if (protocolVersion >= 0x0301) {
+ if (protocolVersion >= 0x0302) {
+ // TLS 1.1+
+ throw new RuntimeException(
+ "Internal Error: TLS 1.1+ should not be negotiating" +
+ "exportable ciphersuites");
+ } else if (protocolVersion == 0x0301) {
+ // TLS 1.0
byte[] seed = concat(clientRandom, serverRandom);
- tmp = doPRF(clientKeyBytes, LABEL_CLIENT_WRITE_KEY, seed,
+ tmp = doTLS10PRF(clientKeyBytes, LABEL_CLIENT_WRITE_KEY, seed,
expandedKeyLength, md5, sha);
clientCipherKey = new SecretKeySpec(tmp, alg);
- tmp = doPRF(serverKeyBytes, LABEL_SERVER_WRITE_KEY, seed,
+ tmp = doTLS10PRF(serverKeyBytes, LABEL_SERVER_WRITE_KEY, seed,
expandedKeyLength, md5, sha);
serverCipherKey = new SecretKeySpec(tmp, alg);
if (ivLength != 0) {
tmp = new byte[ivLength];
- byte[] block = doPRF(null, LABEL_IV_BLOCK, seed,
+ byte[] block = doTLS10PRF(null, LABEL_IV_BLOCK, seed,
ivLength << 1, md5, sha);
System.arraycopy(block, 0, tmp, 0, ivLength);
clientIv = new IvParameterSpec(tmp);
@@ -216,6 +239,7 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {
serverIv = new IvParameterSpec(tmp);
}
} else {
+ // SSLv3
tmp = new byte[expandedKeyLength];
md5.update(clientKeyBytes);
diff --git a/src/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java b/src/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java
index 9a6fb80180268d0f79b27195d4e423cfbffcd5c1..1d5e97aefbf26d1b5a730c8799bd7a5b68c927c4 100644
--- a/src/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java
+++ b/src/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -64,12 +64,14 @@ public final class TlsMasterSecretGenerator extends KeyGeneratorSpi {
}
this.spec = (TlsMasterSecretParameterSpec)params;
if ("RAW".equals(spec.getPremasterSecret().getFormat()) == false) {
- throw new InvalidAlgorithmParameterException("Key format must be RAW");
+ throw new InvalidAlgorithmParameterException(
+ "Key format must be RAW");
}
- protocolVersion = (spec.getMajorVersion() << 8) | spec.getMinorVersion();
- if ((protocolVersion < 0x0300) || (protocolVersion > 0x0302)) {
- throw new InvalidAlgorithmParameterException
- ("Only SSL 3.0, TLS 1.0, and TLS 1.1 supported");
+ protocolVersion = (spec.getMajorVersion() << 8)
+ | spec.getMinorVersion();
+ if ((protocolVersion < 0x0300) || (protocolVersion > 0x0303)) {
+ throw new InvalidAlgorithmParameterException(
+ "Only SSL 3.0, TLS 1.0/1.1/1.2 supported");
}
}
@@ -79,8 +81,8 @@ public final class TlsMasterSecretGenerator extends KeyGeneratorSpi {
protected SecretKey engineGenerateKey() {
if (spec == null) {
- throw new IllegalStateException
- ("TlsMasterSecretGenerator must be initialized");
+ throw new IllegalStateException(
+ "TlsMasterSecretGenerator must be initialized");
}
SecretKey premasterKey = spec.getPremasterSecret();
byte[] premaster = premasterKey.getEncoded();
@@ -103,7 +105,11 @@ public final class TlsMasterSecretGenerator extends KeyGeneratorSpi {
if (protocolVersion >= 0x0301) {
byte[] seed = concat(clientRandom, serverRandom);
- master = doPRF(premaster, LABEL_MASTER_SECRET, seed, 48);
+ master = ((protocolVersion >= 0x0303) ?
+ doTLS12PRF(premaster, LABEL_MASTER_SECRET, seed, 48,
+ spec.getPRFHashAlg(), spec.getPRFHashLength(),
+ spec.getPRFBlockSize()) :
+ doTLS10PRF(premaster, LABEL_MASTER_SECRET, seed, 48));
} else {
master = new byte[48];
MessageDigest md5 = MessageDigest.getInstance("MD5");
@@ -124,7 +130,8 @@ public final class TlsMasterSecretGenerator extends KeyGeneratorSpi {
}
- return new TlsMasterSecretKey(master, premasterMajor, premasterMinor);
+ return new TlsMasterSecretKey(master, premasterMajor,
+ premasterMinor);
} catch (NoSuchAlgorithmException e) {
throw new ProviderException(e);
} catch (DigestException e) {
diff --git a/src/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java b/src/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java
index f73045e6eb26a357f7df9a261a404422d350dae7..137ba255c339928bf0a15c34efb04ae2a92ce9f6 100644
--- a/src/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java
+++ b/src/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -37,11 +37,15 @@ import sun.security.internal.spec.TlsPrfParameterSpec;
/**
* KeyGenerator implementation for the TLS PRF function.
+ *
+ * This class duplicates the HMAC functionality (RFC 2104) with + * performance optimizations (e.g. XOR'ing keys with padding doesn't + * need to be redone for each HMAC operation). * * @author Andreas Sterbenz * @since 1.6 */ -public final class TlsPrfGenerator extends KeyGeneratorSpi { +abstract class TlsPrfGenerator extends KeyGeneratorSpi { // magic constants and utility functions, also used by other files // in this package @@ -69,8 +73,10 @@ public final class TlsPrfGenerator extends KeyGeneratorSpi { * TLS HMAC "inner" and "outer" padding. This isn't a function * of the digest algorithm. */ - private static final byte[] HMAC_ipad = genPad((byte)0x36, 64); - private static final byte[] HMAC_opad = genPad((byte)0x5c, 64); + private static final byte[] HMAC_ipad64 = genPad((byte)0x36, 64); + private static final byte[] HMAC_ipad128 = genPad((byte)0x36, 128); + private static final byte[] HMAC_opad64 = genPad((byte)0x5c, 64); + private static final byte[] HMAC_opad128 = genPad((byte)0x5c, 128); // SSL3 magic mix constants ("A", "BB", "CCC", ...) final static byte[][] SSL3_CONST = genConst(); @@ -123,8 +129,8 @@ public final class TlsPrfGenerator extends KeyGeneratorSpi { this.spec = (TlsPrfParameterSpec)params; SecretKey key = spec.getSecret(); if ((key != null) && ("RAW".equals(key.getFormat()) == false)) { - throw new InvalidAlgorithmParameterException - ("Key encoding format must be RAW"); + throw new InvalidAlgorithmParameterException( + "Key encoding format must be RAW"); } } @@ -132,17 +138,21 @@ public final class TlsPrfGenerator extends KeyGeneratorSpi { throw new InvalidParameterException(MSG); } - protected SecretKey engineGenerateKey() { + SecretKey engineGenerateKey0(boolean tls12) { if (spec == null) { - throw new IllegalStateException - ("TlsPrfGenerator must be initialized"); + throw new IllegalStateException( + "TlsPrfGenerator must be initialized"); } SecretKey key = spec.getSecret(); byte[] secret = (key == null) ? null : key.getEncoded(); try { byte[] labelBytes = spec.getLabel().getBytes("UTF8"); int n = spec.getOutputLength(); - byte[] prfBytes = doPRF(secret, labelBytes, spec.getSeed(), n); + byte[] prfBytes = (tls12 ? + doTLS12PRF(secret, labelBytes, spec.getSeed(), n, + spec.getPRFHashAlg(), spec.getPRFHashLength(), + spec.getPRFBlockSize()) : + doTLS10PRF(secret, labelBytes, spec.getSeed(), n)); return new SecretKeySpec(prfBytes, "TlsPrf"); } catch (GeneralSecurityException e) { throw new ProviderException("Could not generate PRF", e); @@ -151,16 +161,67 @@ public final class TlsPrfGenerator extends KeyGeneratorSpi { } } - static final byte[] doPRF(byte[] secret, byte[] labelBytes, byte[] seed, - int outputLength) throws NoSuchAlgorithmException, DigestException { + static byte[] doTLS12PRF(byte[] secret, byte[] labelBytes, + byte[] seed, int outputLength, + String prfHash, int prfHashLength, int prfBlockSize) + throws NoSuchAlgorithmException, DigestException { + if (prfHash == null) { + throw new NoSuchAlgorithmException("Unspecified PRF algorithm"); + } + MessageDigest prfMD = MessageDigest.getInstance(prfHash); + return doTLS12PRF(secret, labelBytes, seed, outputLength, + prfMD, prfHashLength, prfBlockSize); + } + + static byte[] doTLS12PRF(byte[] secret, byte[] labelBytes, + byte[] seed, int outputLength, + MessageDigest mdPRF, int mdPRFLen, int mdPRFBlockSize) + throws DigestException { + + if (secret == null) { + secret = B0; + } + + // If we have a long secret, digest it first. + if (secret.length > mdPRFBlockSize) { + secret = mdPRF.digest(secret); + } + + byte[] output = new byte[outputLength]; + byte [] ipad; + byte [] opad; + + switch (mdPRFBlockSize) { + case 64: + ipad = HMAC_ipad64.clone(); + opad = HMAC_opad64.clone(); + break; + case 128: + ipad = HMAC_ipad128.clone(); + opad = HMAC_opad128.clone(); + break; + default: + throw new DigestException("Unexpected block size."); + } + + // P_HASH(Secret, label + seed) + expand(mdPRF, mdPRFLen, secret, 0, secret.length, labelBytes, + seed, output, ipad, opad); + + return output; + } + + static byte[] doTLS10PRF(byte[] secret, byte[] labelBytes, + byte[] seed, int outputLength) throws NoSuchAlgorithmException, + DigestException { MessageDigest md5 = MessageDigest.getInstance("MD5"); MessageDigest sha = MessageDigest.getInstance("SHA1"); - return doPRF(secret, labelBytes, seed, outputLength, md5, sha); + return doTLS10PRF(secret, labelBytes, seed, outputLength, md5, sha); } - static final byte[] doPRF(byte[] secret, byte[] labelBytes, byte[] seed, - int outputLength, MessageDigest md5, MessageDigest sha) - throws DigestException { + static byte[] doTLS10PRF(byte[] secret, byte[] labelBytes, + byte[] seed, int outputLength, MessageDigest md5, + MessageDigest sha) throws DigestException { /* * Split the secret into two halves S1 and S2 of same length. * S1 is taken from the first half of the secret, S2 from the @@ -183,10 +244,12 @@ public final class TlsPrfGenerator extends KeyGeneratorSpi { byte[] output = new byte[outputLength]; // P_MD5(S1, label + seed) - expand(md5, 16, secret, 0, seclen, labelBytes, seed, output); + expand(md5, 16, secret, 0, seclen, labelBytes, seed, output, + HMAC_ipad64.clone(), HMAC_opad64.clone()); // P_SHA-1(S2, label + seed) - expand(sha, 20, secret, off, seclen, labelBytes, seed, output); + expand(sha, 20, secret, off, seclen, labelBytes, seed, output, + HMAC_ipad64.clone(), HMAC_opad64.clone()); return output; } @@ -201,16 +264,13 @@ public final class TlsPrfGenerator extends KeyGeneratorSpi { * @param seed the seed * @param output the output array */ - private static final void expand(MessageDigest digest, int hmacSize, + private static void expand(MessageDigest digest, int hmacSize, byte[] secret, int secOff, int secLen, byte[] label, byte[] seed, - byte[] output) throws DigestException { + byte[] output, byte[] pad1, byte[] pad2) throws DigestException { /* * modify the padding used, by XORing the key into our copy of that * padding. That's to avoid doing that for each HMAC computation. */ - byte[] pad1 = HMAC_ipad.clone(); - byte[] pad2 = HMAC_opad.clone(); - for (int i = 0; i < secLen; i++) { pad1[i] ^= secret[i + secOff]; pad2[i] ^= secret[i + secOff]; @@ -275,7 +335,34 @@ public final class TlsPrfGenerator extends KeyGeneratorSpi { } remaining -= k; } + } + /** + * A KeyGenerator implementation that supports TLS 1.2. + *
+ * TLS 1.2 uses a different hash algorithm than 1.0/1.1 for the PRF
+ * calculations. As of 2010, there is no PKCS11-level support for TLS
+ * 1.2 PRF calculations, and no known OS's have an internal variant
+ * we could use. Therefore for TLS 1.2, we are updating JSSE to request
+ * a different provider algorithm: "SunTls12Prf". If we reused the
+ * name "SunTlsPrf", the PKCS11 provider would need be updated to
+ * fail correctly when presented with the wrong version number
+ * (via Provider.Service.supportsParameters()), and add the
+ * appropriate supportsParamters() checks into KeyGenerators (not
+ * currently there).
+ */
+ static public class V12 extends TlsPrfGenerator {
+ protected SecretKey engineGenerateKey() {
+ return engineGenerateKey0(true);
+ }
}
+ /**
+ * A KeyGenerator implementation that supports TLS 1.0/1.1.
+ */
+ static public class V10 extends TlsPrfGenerator {
+ protected SecretKey engineGenerateKey() {
+ return engineGenerateKey0(false);
+ }
+ }
}
diff --git a/src/share/classes/com/sun/crypto/provider/TlsRsaPremasterSecretGenerator.java b/src/share/classes/com/sun/crypto/provider/TlsRsaPremasterSecretGenerator.java
index 9402a1bb2930ddc249762a9a2495522586d5acad..1820ee8cbc384edb48929505bf5090452cae8837 100644
--- a/src/share/classes/com/sun/crypto/provider/TlsRsaPremasterSecretGenerator.java
+++ b/src/share/classes/com/sun/crypto/provider/TlsRsaPremasterSecretGenerator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -69,8 +69,8 @@ public final class TlsRsaPremasterSecretGenerator extends KeyGeneratorSpi {
protected SecretKey engineGenerateKey() {
if (spec == null) {
- throw new IllegalStateException
- ("TlsRsaPremasterSecretGenerator must be initialized");
+ throw new IllegalStateException(
+ "TlsRsaPremasterSecretGenerator must be initialized");
}
if (random == null) {
random = new SecureRandom();
diff --git a/src/share/classes/com/sun/jmx/defaults/ServiceName.java b/src/share/classes/com/sun/jmx/defaults/ServiceName.java
index aa0a46fe2acba9549242df54c2db22b11c5b86f4..8f742dff0f8601fbb1cd71ae792bece1371c9fae 100644
--- a/src/share/classes/com/sun/jmx/defaults/ServiceName.java
+++ b/src/share/classes/com/sun/jmx/defaults/ServiceName.java
@@ -76,9 +76,9 @@ public class ServiceName {
/**
* The vendor of the JMX specification implemented by this product.
*
- * The value is Sun Microsystems.
+ * The value is Oracle Corporation.
*/
- public static final String JMX_SPEC_VENDOR = "Sun Microsystems";
+ public static final String JMX_SPEC_VENDOR = "Oracle Corporation";
/**
* The name of this product implementing the JMX specification.
@@ -91,7 +91,7 @@ public class ServiceName {
* The name of the vendor of this product implementing the
* JMX specification.
*
- * The value is Sun Microsystems.
+ * The value is Oracle Corporation.
*/
- public static final String JMX_IMPL_VENDOR = "Sun Microsystems";
+ public static final String JMX_IMPL_VENDOR = "Oracle Corporation";
}
diff --git a/src/share/classes/com/sun/jmx/snmp/ServiceName.java b/src/share/classes/com/sun/jmx/snmp/ServiceName.java
index 0301389aa563e70f062a5f5d81e40f94f340f618..edf77073ee8d3db97568135bf5af604956bc4f56 100644
--- a/src/share/classes/com/sun/jmx/snmp/ServiceName.java
+++ b/src/share/classes/com/sun/jmx/snmp/ServiceName.java
@@ -27,7 +27,7 @@ package com.sun.jmx.snmp;
/**
* Used for storing default values used by SNMP Runtime services.
- *
This API is a Sun Microsystems internal API and is subject + *
This API is an Oracle Corporation internal API and is subject * to change without notice.
*/ public class ServiceName { @@ -144,16 +144,16 @@ public class ServiceName { /** * The vendor of the JMX specification implemented by this product. *Sun Microsystems.
+ * The value is Oracle Corporation.
*/
- public static final String JMX_SPEC_VENDOR = "Sun Microsystems";
+ public static final String JMX_SPEC_VENDOR = "Oracle Corporation";
/**
* The name of the vendor of this product implementing the JMX specification.
* Sun Microsystems.
+ * The value is Oracle Corporation.
*/
- public static final String JMX_IMPL_VENDOR = "Sun Microsystems";
+ public static final String JMX_IMPL_VENDOR = "Oracle Corporation";
/**
* The build number of the current product version, of the form rXX.
diff --git a/src/share/classes/com/sun/management/package.html b/src/share/classes/com/sun/management/package.html
index b4c66900c22ed3c94b52c32a0c4c7bf2993af4da..c26d4309da6bfb666866c37a44c059113fb09ad5 100644
--- a/src/share/classes/com/sun/management/package.html
+++ b/src/share/classes/com/sun/management/package.html
@@ -30,7 +30,7 @@ questions.
-This package contains Sun Microsystem's platform extension to
+This package contains Oracle Corporation's platform extension to
the implementation of the
java.lang.management API and also defines the management
diff --git a/src/share/classes/java/awt/BasicStroke.java b/src/share/classes/java/awt/BasicStroke.java
index 46a7e2299c471fbe7a1b2310a2de8dd7c8577372..bcf84331149f533db2a637410f0fbb183c18c5db 100644
--- a/src/share/classes/java/awt/BasicStroke.java
+++ b/src/share/classes/java/awt/BasicStroke.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -25,6 +25,8 @@
package java.awt;
+import java.beans.ConstructorProperties;
+
/**
* The BasicStroke class defines a basic set of rendering
* attributes for the outlines of graphics primitives, which are rendered
@@ -183,6 +185,7 @@ public class BasicStroke implements Stroke {
* dash is zero
* @throws IllegalArgumentException if dash lengths are all zero.
*/
+ @ConstructorProperties({ "lineWidth", "endCap", "lineJoin", "miterLimit", "dashArray", "dashPhase" })
public BasicStroke(float width, int cap, int join, float miterlimit,
float dash[], float dash_phase) {
if (width < 0.0f) {
diff --git a/src/share/classes/java/awt/GradientPaint.java b/src/share/classes/java/awt/GradientPaint.java
index 684501a8cc6950c934a10a78c7ba1399f90cef32..badca3170d14d72572384088337f53c834a79b92 100644
--- a/src/share/classes/java/awt/GradientPaint.java
+++ b/src/share/classes/java/awt/GradientPaint.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -29,6 +29,7 @@ import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.AffineTransform;
import java.awt.image.ColorModel;
+import java.beans.ConstructorProperties;
/**
* The GradientPaint class provides a way to fill
@@ -166,6 +167,7 @@ public class GradientPaint implements Paint {
* @throws NullPointerException if either one of colors or points
* is null
*/
+ @ConstructorProperties({ "point1", "color1", "point2", "color2", "cyclic" })
public GradientPaint(Point2D pt1,
Color color1,
Point2D pt2,
diff --git a/src/share/classes/java/awt/GridBagConstraints.java b/src/share/classes/java/awt/GridBagConstraints.java
index 445d937c185812e0356fb67b6971a769f8f776a0..9460c43500a56c0d284ee24686b18451181c2224 100644
--- a/src/share/classes/java/awt/GridBagConstraints.java
+++ b/src/share/classes/java/awt/GridBagConstraints.java
@@ -126,7 +126,7 @@ public class GridBagConstraints implements Cloneable, java.io.Serializable {
/**
* Place the component centered along the edge of its display area
* associated with the start of a page for the current
- * ComponentOrienation. Equal to NORTH for horizontal
+ * {@code ComponentOrientation}. Equal to NORTH for horizontal
* orientations.
*/
public static final int PAGE_START = 19;
@@ -134,7 +134,7 @@ public class GridBagConstraints implements Cloneable, java.io.Serializable {
/**
* Place the component centered along the edge of its display area
* associated with the end of a page for the current
- * ComponentOrienation. Equal to SOUTH for horizontal
+ * {@code ComponentOrientation}. Equal to SOUTH for horizontal
* orientations.
*/
public static final int PAGE_END = 20;
@@ -142,7 +142,7 @@ public class GridBagConstraints implements Cloneable, java.io.Serializable {
/**
* Place the component centered along the edge of its display area where
* lines of text would normally begin for the current
- * ComponentOrienation. Equal to WEST for horizontal,
+ * {@code ComponentOrientation}. Equal to WEST for horizontal,
* left-to-right orientations and EAST for horizontal, right-to-left
* orientations.
*/
@@ -151,7 +151,7 @@ public class GridBagConstraints implements Cloneable, java.io.Serializable {
/**
* Place the component centered along the edge of its display area where
* lines of text would normally end for the current
- * ComponentOrienation. Equal to EAST for horizontal,
+ * {@code ComponentOrientation}. Equal to EAST for horizontal,
* left-to-right orientations and WEST for horizontal, right-to-left
* orientations.
*/
@@ -160,7 +160,7 @@ public class GridBagConstraints implements Cloneable, java.io.Serializable {
/**
* Place the component in the corner of its display area where
* the first line of text on a page would normally begin for the current
- * ComponentOrienation. Equal to NORTHWEST for horizontal,
+ * {@code ComponentOrientation}. Equal to NORTHWEST for horizontal,
* left-to-right orientations and NORTHEAST for horizontal, right-to-left
* orientations.
*/
@@ -169,7 +169,7 @@ public class GridBagConstraints implements Cloneable, java.io.Serializable {
/**
* Place the component in the corner of its display area where
* the first line of text on a page would normally end for the current
- * ComponentOrienation. Equal to NORTHEAST for horizontal,
+ * {@code ComponentOrientation}. Equal to NORTHEAST for horizontal,
* left-to-right orientations and NORTHWEST for horizontal, right-to-left
* orientations.
*/
@@ -178,7 +178,7 @@ public class GridBagConstraints implements Cloneable, java.io.Serializable {
/**
* Place the component in the corner of its display area where
* the last line of text on a page would normally start for the current
- * ComponentOrienation. Equal to SOUTHWEST for horizontal,
+ * {@code ComponentOrientation}. Equal to SOUTHWEST for horizontal,
* left-to-right orientations and SOUTHEAST for horizontal, right-to-left
* orientations.
*/
@@ -187,7 +187,7 @@ public class GridBagConstraints implements Cloneable, java.io.Serializable {
/**
* Place the component in the corner of its display area where
* the last line of text on a page would normally end for the current
- * ComponentOrienation. Equal to SOUTHEAST for horizontal,
+ * {@code ComponentOrientation}. Equal to SOUTHEAST for horizontal,
* left-to-right orientations and SOUTHWEST for horizontal, right-to-left
* orientations.
*/
@@ -437,7 +437,7 @@ public class GridBagConstraints implements Cloneable, java.io.Serializable {
* LINE_START, LINE_END,
* FIRST_LINE_START, FIRST_LINE_END,
* LAST_LINE_START and LAST_LINE_END. The
- * baseline relvative values are:
+ * baseline relative values are:
* BASELINE, BASELINE_LEADING,
* BASELINE_TRAILING,
* ABOVE_BASELINE, ABOVE_BASELINE_LEADING,
diff --git a/src/share/classes/java/awt/LinearGradientPaint.java b/src/share/classes/java/awt/LinearGradientPaint.java
index c7d9a74da1261aa9dbd93da9bf498ab0682493ce..8d5d727540bffa9eb5da5a9f6b04f9bda1d267b3 100644
--- a/src/share/classes/java/awt/LinearGradientPaint.java
+++ b/src/share/classes/java/awt/LinearGradientPaint.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 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
@@ -26,10 +26,10 @@
package java.awt;
import java.awt.geom.AffineTransform;
-import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.ColorModel;
+import java.beans.ConstructorProperties;
/**
* The {@code LinearGradientPaint} class provides a way to fill
@@ -271,6 +271,7 @@ public final class LinearGradientPaint extends MultipleGradientPaint {
* or a {@code fractions} value is less than 0.0 or greater than 1.0,
* or the {@code fractions} are not provided in strictly increasing order
*/
+ @ConstructorProperties({ "startPoint", "endPoint", "fractions", "colors", "cycleMethod", "colorSpace", "transform" })
public LinearGradientPaint(Point2D start, Point2D end,
float[] fractions, Color[] colors,
CycleMethod cycleMethod,
diff --git a/src/share/classes/java/awt/RadialGradientPaint.java b/src/share/classes/java/awt/RadialGradientPaint.java
index 12d76aadeb06c58d4b503b8b9256e21dc2c8fd20..d87a3253d46e5ee158c6b86b705de57c9a69901c 100644
--- a/src/share/classes/java/awt/RadialGradientPaint.java
+++ b/src/share/classes/java/awt/RadialGradientPaint.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 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
@@ -29,6 +29,7 @@ import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.ColorModel;
+import java.beans.ConstructorProperties;
/**
* The {@code RadialGradientPaint} class provides a way to fill a shape with
@@ -428,6 +429,7 @@ public final class RadialGradientPaint extends MultipleGradientPaint {
* or a {@code fractions} value is less than 0.0 or greater than 1.0,
* or the {@code fractions} are not provided in strictly increasing order
*/
+ @ConstructorProperties({ "centerPoint", "radius", "focusPoint", "fractions", "colors", "cycleMethod", "colorSpace", "transform" })
public RadialGradientPaint(Point2D center,
float radius,
Point2D focus,
diff --git a/src/share/classes/java/awt/Scrollbar.java b/src/share/classes/java/awt/Scrollbar.java
index 56835aa9dd4326ea49a6604ac758e3a848ceb3d3..d43414305b56c9c95189b94db58ede9a915516d1 100644
--- a/src/share/classes/java/awt/Scrollbar.java
+++ b/src/share/classes/java/awt/Scrollbar.java
@@ -213,7 +213,8 @@ public class Scrollbar extends Component implements Adjustable, Accessible {
* The size of the Scrollbar's bubble.
* When a scroll bar is used to select a range of values,
* the visibleAmount represents the size of this range.
- * This is visually indicated by the size of the bubble.
+ * Depending on platform, this may be visually indicated
+ * by the size of the bubble.
*
* @serial
* @see #getVisibleAmount
@@ -637,6 +638,8 @@ public class Scrollbar extends Component implements Adjustable, Accessible {
* bubble (also called a thumb or scroll box), usually gives a
* visual representation of the relationship of the visible
* amount to the range of the scroll bar.
+ * Note that depending on platform, the value of the visible amount property
+ * may not be visually indicated by the size of the bubble.
* * The scroll bar's bubble may not be displayed when it is not * moveable (e.g. when it takes up the entire length of the @@ -670,6 +673,8 @@ public class Scrollbar extends Component implements Adjustable, Accessible { * bubble (also called a thumb or scroll box), usually gives a * visual representation of the relationship of the visible * amount to the range of the scroll bar. + * Note that depending on platform, the value of the visible amount property + * may not be visually indicated by the size of the bubble. *
* The scroll bar's bubble may not be displayed when it is not
* moveable (e.g. when it takes up the entire length of the
diff --git a/src/share/classes/java/awt/Toolkit.java b/src/share/classes/java/awt/Toolkit.java
index dd1ad7fb938dda10f380ad37bebaa920e7b9ee71..90319977f3d03be15c4bf1ec0671961e956dc05c 100644
--- a/src/share/classes/java/awt/Toolkit.java
+++ b/src/share/classes/java/awt/Toolkit.java
@@ -1831,7 +1831,11 @@ public abstract class Toolkit {
desktopProperties.put(name, newValue);
}
- desktopPropsSupport.firePropertyChange(name, oldValue, newValue);
+ // Don't fire change event if old and new values are null.
+ // It helps to avoid recursive resending of WM_THEMECHANGED
+ if (oldValue != null || newValue != null) {
+ desktopPropsSupport.firePropertyChange(name, oldValue, newValue);
+ }
}
/**
diff --git a/src/share/classes/java/awt/geom/AffineTransform.java b/src/share/classes/java/awt/geom/AffineTransform.java
index 5e4dafc9dd72ad01189d0a1f04b25d8532e399bb..a3b8134fe1fcbaa247fb059a5dcef16d1e0fe0d6 100644
--- a/src/share/classes/java/awt/geom/AffineTransform.java
+++ b/src/share/classes/java/awt/geom/AffineTransform.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -26,6 +26,7 @@
package java.awt.geom;
import java.awt.Shape;
+import java.beans.ConstructorProperties;
/**
* The An asynchronous datagram channel is created by invoking one of the {@link
- * #open open} methods defined by this class. It is not possible to create a channel
- * for an arbitrary, pre-existing datagram socket. A newly-created asynchronous
- * datagram channel is open but not connected. It need not be connected in order
- * for the {@link #send send} and {@link #receive receive} methods to be used.
- * A datagram channel may be connected, by invoking its {@link #connect connect}
- * method, in order to avoid the overhead of the security checks that are otherwise
- * performed as part of every send and receive operation when a security manager
- * is set. The channel must be connected in order to use the {@link #read read}
- * and {@link #write write} methods, since those methods do not accept or return
- * socket addresses. Once connected, an asynchronous datagram channel remains
- * connected until it is disconnected or closed.
- *
- * Socket options are configured using the {@link #setOption(SocketOption,Object)
- * setOption} method. An asynchronous datagram channel to an Internet Protocol
- * (IP) socket supports the following options:
- * Asynchronous datagram channels allow more than one read/receive and
- * write/send to be oustanding at any given time.
- *
- * Usage Example:
- * The new channel is created by invoking the {@link
- * java.nio.channels.spi.AsynchronousChannelProvider#openAsynchronousDatagramChannel
- * openAsynchronousDatagramChannel} method on the {@link
- * java.nio.channels.spi.AsynchronousChannelProvider} object that created
- * the given group (or the default provider where {@code group} is {@code
- * null}).
- *
- * The {@code family} parameter is used to specify the {@link ProtocolFamily}.
- * If the datagram channel is to be used for Internet Protocol {@link
- * MulticastChannel multicasting} then this parameter should correspond to
- * the address type of the multicast groups that this channel will join.
- *
- * @param family
- * The protocol family, or {@code null} to use the default protocol
- * family
- * @param group
- * The group to which the newly constructed channel should be bound,
- * or {@code null} for the default group
- *
- * @return A new asynchronous datagram channel
- *
- * @throws UnsupportedOperationException
- * If the specified protocol family is not supported. For example,
- * suppose the parameter is specified as {@link
- * java.net.StandardProtocolFamily#INET6 INET6} but IPv6 is not
- * enabled on the platform.
- * @throws ShutdownChannelGroupException
- * The specified group is shutdown
- * @throws IOException
- * If an I/O error occurs
- */
- public static AsynchronousDatagramChannel open(ProtocolFamily family,
- AsynchronousChannelGroup group)
- throws IOException
- {
- AsynchronousChannelProvider provider = (group == null) ?
- AsynchronousChannelProvider.provider() : group.provider();
- return provider.openAsynchronousDatagramChannel(family, group);
- }
-
- /**
- * Opens an asynchronous datagram channel.
- *
- * This method returns an asynchronous datagram channel that is
- * bound to the default group. This method is equivalent to evaluating
- * the expression:
- * Where the channel is connected to an Internet Protocol socket address
- * then the return value from this method is of type {@link
- * java.net.InetSocketAddress}.
- *
- * @return The remote address; {@code null} if the channel's socket is not
- * connected
- *
- * @throws ClosedChannelException
- * If the channel is closed
- * @throws IOException
- * If an I/O error occurs
- */
- public abstract SocketAddress getRemoteAddress() throws IOException;
-
- /**
- * Connects this channel's socket.
- *
- * The channel's socket is configured so that it only receives
- * datagrams from, and sends datagrams to, the given remote peer
- * address. Once connected, datagrams may not be received from or sent to
- * any other address. A datagram socket remains connected until it is
- * explicitly disconnected or until it is closed.
- *
- * This method performs exactly the same security checks as the {@link
- * java.net.DatagramSocket#connect connect} method of the {@link
- * java.net.DatagramSocket} class. That is, if a security manager has been
- * installed then this method verifies that its {@link
- * java.lang.SecurityManager#checkAccept checkAccept} and {@link
- * java.lang.SecurityManager#checkConnect checkConnect} methods permit
- * datagrams to be received from and sent to, respectively, the given
- * remote address.
- *
- * This method may be invoked at any time. Whether it has any effect
- * on outstanding read or write operations is implementation specific and
- * therefore not specified.
- *
- * @param remote
- * The remote address to which this channel is to be connected
- *
- * @return This datagram channel
- *
- * @throws ClosedChannelException
- * If this channel is closed
- *
- * @throws SecurityException
- * If a security manager has been installed
- * and it does not permit access to the given remote address
- *
- * @throws IOException
- * If some other I/O error occurs
- */
- public abstract AsynchronousDatagramChannel connect(SocketAddress remote)
- throws IOException;
-
- /**
- * Disconnects this channel's socket.
- *
- * The channel's socket is configured so that it can receive datagrams
- * from, and sends datagrams to, any remote address so long as the security
- * manager, if installed, permits it.
- *
- * This method may be invoked at any time. Whether it has any effect
- * on outstanding read or write operations is implementation specific and
- * therefore not specified.
- *
- * @return This datagram channel
- *
- * @throws IOException
- * If some other I/O error occurs
- */
- public abstract AsynchronousDatagramChannel disconnect() throws IOException;
-
- /**
- * Receives a datagram via this channel.
- *
- * This method initiates the receiving of a datagram into the given
- * buffer. The {@code handler} parameter is a completion handler that is
- * invoked when the receive operation completes (or fails). The result
- * passed to the completion handler is the datagram's source address.
- *
- * The datagram is transferred into the given byte buffer starting at
- * its current position, as if by a regular {@link AsynchronousByteChannel#read
- * read} operation. If there are fewer bytes remaining in the buffer
- * than are required to hold the datagram then the remainder of the datagram
- * is silently discarded.
- *
- * If a timeout is specified and the timeout elapses before the operation
- * completes then the operation completes with the exception {@link
- * InterruptedByTimeoutException}. When a timeout elapses then the state of
- * the {@link ByteBuffer} is not defined. The buffers should be discarded or
- * at least care must be taken to ensure that the buffer is not accessed
- * while the channel remains open.
- *
- * When a security manager has been installed and the channel is not
- * connected, then it verifies that the source's address and port number are
- * permitted by the security manager's {@link SecurityManager#checkAccept
- * checkAccept} method. The permission check is performed with privileges that
- * are restricted by the calling context of this method. If the permission
- * check fails then the operation completes with a {@link SecurityException}.
- * The overhead of this security check can be avoided by first connecting the
- * socket via the {@link #connect connect} method.
- *
- * @param dst
- * The buffer into which the datagram is to be transferred
- * @param timeout
- * The timeout, or {@code 0L} for no timeout
- * @param unit
- * The time unit of the {@code timeout} argument
- * @param attachment
- * The object to attach to the I/O operation; can be {@code null}
- * @param handler
- * The handler for consuming the result
- *
- * @throws IllegalArgumentException
- * If the timeout is negative or the buffer is read-only
- * @throws ShutdownChannelGroupException
- * If the channel group has terminated
- */
- public abstract void receive(ByteBuffer dst,
- long timeout,
- TimeUnit unit,
- A attachment,
- CompletionHandler This method initiates the receiving of a datagram into the given
- * buffer. The {@code handler} parameter is a completion handler that is
- * invoked when the receive operation completes (or fails). The result
- * passed to the completion handler is the datagram's source address.
- *
- * This method is equivalent to invoking {@link
- * #receive(ByteBuffer,long,TimeUnit,Object,CompletionHandler)} with a
- * timeout of {@code 0L}.
- *
- * @param dst
- * The buffer into which the datagram is to be transferred
- * @param attachment
- * The object to attach to the I/O operation; can be {@code null}
- * @param handler
- * The handler for consuming the result
- *
- * @throws IllegalArgumentException
- * If the buffer is read-only
- * @throws ShutdownChannelGroupException
- * If the channel group has terminated
- */
- public final void receive(ByteBuffer dst,
- A attachment,
- CompletionHandler This method initiates the receiving of a datagram into the given
- * buffer. The method behaves in exactly the same manner as the {@link
- * #receive(ByteBuffer,Object,CompletionHandler)
- * receive(ByteBuffer,Object,CompletionHandler)} method except that instead
- * of specifying a completion handler, this method returns a {@code Future}
- * representing the pending result. The {@code Future}'s {@link Future#get()
- * get} method returns the datagram's source address.
- *
- * @param dst
- * The buffer into which the datagram is to be transferred
- *
- * @return a {@code Future} object representing the pending result
- *
- * @throws IllegalArgumentException
- * If the buffer is read-only
- */
- public abstract Future This method initiates sending of a datagram from the given buffer to
- * the given address. The {@code handler} parameter is a completion handler
- * that is invoked when the send completes (or fails). The result passed to
- * the completion handler is the number of bytes sent.
- *
- * Otherwise this method works in the same manner as the {@link
- * AsynchronousByteChannel#write(ByteBuffer,Object,CompletionHandler)}
- * method.
- *
- * @param src
- * The buffer containing the datagram to be sent
- * @param target
- * The address to which the datagram is to be sent
- * @param attachment
- * The object to attach to the I/O operation; can be {@code null}
- * @param handler
- * The handler for consuming the result
- *
- * @throws UnresolvedAddressException
- * If the given remote address is not fully resolved
- * @throws UnsupportedAddressTypeException
- * If the type of the given remote address is not supported
- * @throws IllegalArgumentException
- * If the channel's socket is connected and is connected to an
- * address that is not equal to {@code target}
- * @throws SecurityException
- * If a security manager has been installed and it does not permit
- * datagrams to be sent to the given address
- * @throws ShutdownChannelGroupException
- * If the channel group has terminated
- */
- public abstract void send(ByteBuffer src,
- SocketAddress target,
- A attachment,
- CompletionHandler This method initiates sending of a datagram from the given buffer to
- * the given address. The method behaves in exactly the same manner as the
- * {@link #send(ByteBuffer,SocketAddress,Object,CompletionHandler)
- * send(ByteBuffer,SocketAddress,Object,CompletionHandler)} method except
- * that instead of specifying a completion handler, this method returns a
- * {@code Future} representing the pending result. The {@code Future}'s
- * {@link Future#get() get} method returns the number of bytes sent.
- *
- * @param src
- * The buffer containing the datagram to be sent
- * @param target
- * The address to which the datagram is to be sent
- *
- * @return a {@code Future} object representing the pending result
- *
- * @throws UnresolvedAddressException
- * If the given remote address is not fully resolved
- * @throws UnsupportedAddressTypeException
- * If the type of the given remote address is not supported
- * @throws IllegalArgumentException
- * If the channel's socket is connected and is connected to an
- * address that is not equal to {@code target}
- * @throws SecurityException
- * If a security manager has been installed and it does not permit
- * datagrams to be sent to the given address
- */
- public abstract Future This method initiates the receiving of a datagram into the given
- * buffer. The {@code handler} parameter is a completion handler that is
- * invoked when the receive operation completes (or fails). The result
- * passed to the completion handler is number of bytes read.
- *
- * This method may only be invoked if this channel is connected, and it
- * only accepts datagrams from the peer that the channel is connected too.
- * The datagram is transferred into the given byte buffer starting at
- * its current position and exactly as specified in the {@link
- * AsynchronousByteChannel} interface. If there are fewer bytes
- * remaining in the buffer than are required to hold the datagram then the
- * remainder of the datagram is silently discarded.
- *
- * If a timeout is specified and the timeout elapses before the operation
- * completes then the operation completes with the exception {@link
- * InterruptedByTimeoutException}. When a timeout elapses then the state of
- * the {@link ByteBuffer} is not defined. The buffers should be discarded or
- * at least care must be taken to ensure that the buffer is not accessed
- * while the channel remains open.
- *
- * @param dst
- * The buffer into which the datagram is to be transferred
- * @param timeout
- * The timeout, or {@code 0L} for no timeout
- * @param unit
- * The time unit of the {@code timeout} argument
- * @param attachment
- * The object to attach to the I/O operation; can be {@code null}
- * @param handler
- * The handler for consuming the result
- *
- * @throws IllegalArgumentException
- * If the timeout is negative or buffer is read-only
- * @throws NotYetConnectedException
- * If this channel is not connected
- * @throws ShutdownChannelGroupException
- * If the channel group has terminated
- */
- public abstract void read(ByteBuffer dst,
- long timeout,
- TimeUnit unit,
- A attachment,
- CompletionHandler
+ * {@code AlgorithmConstraints} objects are immutable. An implementation
+ * of this interface should not provide methods that can change the state
+ * of an instance once it has been created.
+ *
+ * Note that {@code AlgorithmConstraints} can be used to represent the
+ * restrictions described by the security properties
+ * {@code jdk.certpath.disabledAlgorithms} and
+ * {@code jdk.tls.disabledAlgorithms}, or could be used by a
+ * concrete {@code PKIXCertPathChecker} to check whether a specified
+ * certificate in the certification path contains the required algorithm
+ * constraints.
+ *
+ * @see javax.net.ssl.SSLParameters#getAlgorithmConstraints
+ * @see javax.net.ssl.SSLParameters#setAlgorithmConstraints(AlgorithmConstraints)
+ *
+ * @since 1.7
+ */
+
+public interface AlgorithmConstraints {
+
+ /**
+ * Determines whether an algorithm is granted permission for the
+ * specified cryptographic primitives.
+ *
+ * @param primitives a set of cryptographic primitives
+ * @param algorithm the algorithm name
+ * @param parameters the algorithm parameters, or null if no additional
+ * parameters
+ *
+ * @return true if the algorithm is permitted and can be used for all
+ * of the specified cryptographic primitives
+ *
+ * @throws IllegalArgumentException if primitives or algorithm is null
+ * or empty
+ */
+ public boolean permits(Set
+ * This method is usually used to check key size and key usage.
+ *
+ * @param primitives a set of cryptographic primitives
+ * @param key the key
+ *
+ * @return true if the key can be used for all of the specified
+ * cryptographic primitives
+ *
+ * @throws IllegalArgumentException if primitives is null or empty,
+ * or the key is null
+ */
+ public boolean permits(Set The serialVersionUID of this class is
+ * Note: this method is used to indicate to the peer which signature
+ * algorithms may be used for digital signatures in TLS 1.2. It is
+ * not meaningful for TLS versions prior to 1.2.
+ *
+ * The signature algorithm name must be a standard Java Security
+ * name (such as "SHA1withRSA", "SHA256withECDSA", and so on).
+ * See Appendix A in the
+ * Java Cryptography Architecture API Specification & Reference
+ * for information about standard algorithm names.
+ *
+ * Note: the local supported signature algorithms should conform to
+ * the algorithm constraints specified by
+ * {@link SSLParameters#getAlgorithmConstraints getAlgorithmConstraints()}
+ * method in
+ * Note: this method is used to indicate to the local side which signature
+ * algorithms may be used for digital signatures in TLS 1.2. It is
+ * not meaningful for TLS versions prior to 1.2.
+ *
+ * The signature algorithm name must be a standard Java Security
+ * name (such as "SHA1withRSA", "SHA256withECDSA", and so on).
+ * See Appendix A in the
+ * Java Cryptography Architecture API Specification & Reference
+ * for information about standard algorithm names.
+ *
+ * @return An array of supported signature algorithms, in descending
+ * order of preference. The return value is an empty array if
+ * the peer has not sent the supported signature algorithms.
+ *
+ * @see X509KeyManager
+ * @see X509ExtendedKeyManager
+ */
+ public abstract String[] getPeerSupportedSignatureAlgorithms();
+}
diff --git a/src/share/classes/javax/net/ssl/HttpsURLConnection.java b/src/share/classes/javax/net/ssl/HttpsURLConnection.java
index e9c478fece1549cb1deeed0a3ec631962ee98d77..6d799e3ff5fe8193a2a151eea111ba1c8cc007bf 100644
--- a/src/share/classes/javax/net/ssl/HttpsURLConnection.java
+++ b/src/share/classes/javax/net/ssl/HttpsURLConnection.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -188,19 +188,8 @@ class HttpsURLConnection extends HttpURLConnection
*
* The default implementation will deny such connections.
*/
- private static HostnameVerifier defaultHostnameVerifier;
-
- /**
- * Initialize the default
+ * TLS protocols may negotiate parameters that are needed when using
+ * an instance of this class, but before the {@code SSLSession} has
+ * been completely initialized and made available via {@code getSession}.
+ * For example, the list of valid signature algorithms may restrict
+ * the type of certificates that can used during TrustManager
+ * decisions, or the maximum TLS fragment packet sizes can be
+ * resized to better support the network environment.
+ *
+ * This method provides early access to the {@code SSLSession} being
+ * constructed. Depending on how far the handshake has progressed,
+ * some data may not yet be available for use. For example, if a
+ * remote server will be sending a Certificate chain, but that chain
+ * has yet not been processed, the {@code getPeerCertificates}
+ * method of {@code SSLSession} will throw a
+ * SSLPeerUnverifiedException. Once that chain has been processed,
+ * {@code getPeerCertificates} will return the proper value.
+ *
+ * @see SSLSocket
+ * @see SSLSession
+ * @see ExtendedSSLSession
+ * @see X509ExtendedKeyManager
+ * @see X509ExtendedTrustManager
+ *
+ * @return null if this instance is not currently handshaking, or
+ * if the current handshake has not progressed far enough to
+ * create a basic SSLSession. Otherwise, this method returns the
+ * {@code SSLSession} currently being negotiated.
+ * @throws UnsupportedOperationException if the underlying provider
+ * does not implement the operation.
+ *
+ * @since 1.7
+ */
+ public SSLSession getHandshakeSession() {
+ throw new UnsupportedOperationException();
+ }
+
+
/**
* Initiates handshaking (initial or renegotiation) on this SSLEngine.
*
diff --git a/src/share/classes/javax/net/ssl/SSLParameters.java b/src/share/classes/javax/net/ssl/SSLParameters.java
index ed8913230afbd8ee0fb6b0f4dd8c28d530abd3d0..4bb20a164eb50bc3a5657e5cbaa4395c52e529c2 100644
--- a/src/share/classes/javax/net/ssl/SSLParameters.java
+++ b/src/share/classes/javax/net/ssl/SSLParameters.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -25,24 +25,29 @@
package javax.net.ssl;
+import java.security.AlgorithmConstraints;
+
/**
* Encapsulates parameters for an SSL/TLS connection. The parameters
* are the list of ciphersuites to be accepted in an SSL/TLS handshake,
- * the list of protocols to be allowed, and whether SSL/TLS servers should
- * request or require client authentication.
- *
- * SSLParameters can be created via the constructors in this class.
+ * the list of protocols to be allowed, the endpoint identification
+ * algorithm during SSL/TLS handshaking, the algorithm constraints and
+ * whether SSL/TLS servers should request or require client authentication.
+ *
+ * SSLParameters can be created via the constructors in this class.
* Objects can also be obtained using the SSLParameters can be applied to a connection via the methods
+ *
+ * SSLParameters can be applied to a connection via the methods
* {@link SSLSocket#setSSLParameters SSLSocket.setSSLParameters()} and
- * {@link SSLEngine#setSSLParameters SSLEngine.getSSLParameters()}.
+ * {@link SSLServerSocket#setSSLParameters SSLServerSocket.setSSLParameters()}
+ * and {@link SSLEngine#setSSLParameters SSLEngine.getSSLParameters()}.
*
* @see SSLSocket
* @see SSLEngine
@@ -56,11 +61,13 @@ public class SSLParameters {
private String[] protocols;
private boolean wantClientAuth;
private boolean needClientAuth;
+ private String identificationAlgorithm;
+ private AlgorithmConstraints algorithmConstraints;
/**
* Constructs SSLParameters.
- *
- * The cipherSuites and protocols values are set to
+ * The cipherSuites and protocols values are set to
* Calling this constructor is equivalent to calling the no-args
* constructor followed by
*
* Calling this constructor is equivalent to calling the no-args
* constructor followed by
*
+ * If the
+ * If the
@@ -449,8 +449,79 @@ public abstract class SSLServerSocket extends ServerSocket
*
* @return true indicates that sessions may be created; this
* is the default. false indicates that an existing
- * session must be resumed.
+ * session must be resumed
* @see #setEnableSessionCreation(boolean)
*/
public abstract boolean getEnableSessionCreation();
+
+ /**
+ * Returns the SSLParameters in effect for newly accepted connections.
+ * The ciphersuites and protocols of the returned SSLParameters
+ * are always non-null.
+ *
+ * @return the SSLParameters in effect for newly accepted connections
+ *
+ * @see #setSSLParameters(SSLParameters)
+ *
+ * @since 1.7
+ */
+ public SSLParameters getSSLParameters() {
+ SSLParameters parameters = new SSLParameters();
+
+ parameters.setCipherSuites(getEnabledCipherSuites());
+ parameters.setProtocols(getEnabledProtocols());
+ if (getNeedClientAuth()) {
+ parameters.setNeedClientAuth(true);
+ } else if (getWantClientAuth()) {
+ parameters.setWantClientAuth(true);
+ }
+
+ return parameters;
+ }
+
+ /**
+ * Applies SSLParameters to newly accepted connections.
+ *
+ * This means:
+ *
+ * TLS protocols may negotiate parameters that are needed when using
+ * an instance of this class, but before the {@code SSLSession} has
+ * been completely initialized and made available via {@code getSession}.
+ * For example, the list of valid signature algorithms may restrict
+ * the type of certificates that can used during TrustManager
+ * decisions, or the maximum TLS fragment packet sizes can be
+ * resized to better support the network environment.
+ *
+ * This method provides early access to the {@code SSLSession} being
+ * constructed. Depending on how far the handshake has progressed,
+ * some data may not yet be available for use. For example, if a
+ * remote server will be sending a Certificate chain, but that chain
+ * has yet not been processed, the {@code getPeerCertificates}
+ * method of {@code SSLSession} will throw a
+ * SSLPeerUnverifiedException. Once that chain has been processed,
+ * {@code getPeerCertificates} will return the proper value.
+ *
+ * Unlike {@link #getSession()}, this method does not initiate the
+ * initial handshake and does not block until handshaking is
+ * complete.
+ *
+ * @see SSLEngine
+ * @see SSLSession
+ * @see ExtendedSSLSession
+ * @see X509ExtendedKeyManager
+ * @see X509ExtendedTrustManager
+ *
+ * @return null if this instance is not currently handshaking, or
+ * if the current handshake has not progressed far enough to
+ * create a basic SSLSession. Otherwise, this method returns the
+ * {@code SSLSession} currently being negotiated.
+ * @throws UnsupportedOperationException if the underlying provider
+ * does not implement the operation.
+ *
+ * @since 1.7
+ */
+ public SSLSession getHandshakeSession() {
+ throw new UnsupportedOperationException();
+ }
+
+
/**
* Registers an event listener to receive notifications that an
* SSL handshake has completed on this connection.
diff --git a/src/share/classes/javax/net/ssl/SSLSocketFactory.java b/src/share/classes/javax/net/ssl/SSLSocketFactory.java
index a7971b5504beb5cefa360f9255f7779488070aca..f7d5e5b0a2fc2ca1970cca081a4304c49c9717c0 100644
--- a/src/share/classes/javax/net/ssl/SSLSocketFactory.java
+++ b/src/share/classes/javax/net/ssl/SSLSocketFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -30,6 +30,7 @@ import java.net.*;
import javax.net.SocketFactory;
import java.io.IOException;
import java.security.*;
+import java.util.Locale;
import sun.security.action.GetPropertyAction;
@@ -50,7 +51,8 @@ public abstract class SSLSocketFactory extends SocketFactory
static {
String s = java.security.AccessController.doPrivileged(
- new GetPropertyAction("javax.net.debug", "")).toLowerCase();
+ new GetPropertyAction("javax.net.debug", "")).toLowerCase(
+ Locale.ENGLISH);
DEBUG = s.contains("all") || s.contains("ssl");
}
diff --git a/src/share/classes/javax/net/ssl/X509ExtendedTrustManager.java b/src/share/classes/javax/net/ssl/X509ExtendedTrustManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..e69a282c55f3149c9a0bcb759615911b11d336a3
--- /dev/null
+++ b/src/share/classes/javax/net/ssl/X509ExtendedTrustManager.java
@@ -0,0 +1,234 @@
+/*
+ * 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 javax.net.ssl;
+
+import java.net.Socket;
+import javax.net.ssl.X509TrustManager;
+
+import java.security.cert.X509Certificate;
+import java.security.cert.CertificateException;
+
+/**
+ * Extensions to the
+ * To prevent man-in-the-middle attacks, hostname checks can be done
+ * to verify that the hostname in an end-entity certificate matches the
+ * targeted hostname. TLS does not require such checks, but some protocols
+ * over TLS (such as HTTPS) do. In earlier versions of the JDK, the
+ * certificate chain checks were done at the SSL/TLS layer, and the hostname
+ * verification checks were done at the layer over TLS. This class allows
+ * for the checking to be done during a single call to this class.
+ *
+ * RFC 2830 defines the server identification specification for the "LDAPS"
+ * algorithm. RFC 2818 defines both the server identification and the
+ * client identification specification for the "HTTPS" algorithm.
+ *
+ * @see X509TrustManager
+ * @see HostnameVerifier
+ *
+ * @since 1.7
+ */
+public abstract class X509ExtendedTrustManager implements X509TrustManager {
+ /**
+ * Given the partial or complete certificate chain provided by the
+ * peer, build and validate the certificate path based on the
+ * authentication type and ssl parameters.
+ *
+ * The authentication type is determined by the actual certificate
+ * used. For instance, if RSAPublicKey is used, the authType
+ * should be "RSA". Checking is case-sensitive.
+ *
+ * If the
+ * If the
+ * The authentication type is the key exchange algorithm portion
+ * of the cipher suites represented as a String, such as "RSA",
+ * "DHE_DSS". Note: for some exportable cipher suites, the key
+ * exchange algorithm is determined at run time during the
+ * handshake. For instance, for TLS_RSA_EXPORT_WITH_RC4_40_MD5,
+ * the authType should be RSA_EXPORT when an ephemeral RSA key is
+ * used for the key exchange, and RSA when the key from the server
+ * certificate is used. Checking is case-sensitive.
+ *
+ * If the
+ * If the
+ * The authentication type is determined by the actual certificate
+ * used. For instance, if RSAPublicKey is used, the authType
+ * should be "RSA". Checking is case-sensitive.
+ *
+ * If the
+ * If the
+ * The authentication type is the key exchange algorithm portion
+ * of the cipher suites represented as a String, such as "RSA",
+ * "DHE_DSS". Note: for some exportable cipher suites, the key
+ * exchange algorithm is determined at run time during the
+ * handshake. For instance, for TLS_RSA_EXPORT_WITH_RC4_40_MD5,
+ * the authType should be RSA_EXPORT when an ephemeral RSA key is
+ * used for the key exchange, and RSA when the key from the server
+ * certificate is used. Checking is case-sensitive.
+ *
+ * If the
+ * If the
+ * Warning:
+ * Serialized objects of this class will not be compatible with
+ * future Swing releases. The current serialization support is
+ * appropriate for short term storage or RMI
+ * between applications running the same version of Swing.
+ * As of 1.4, support for long term storage of all JavaBeans™
+ * has been added to the A The An application-generated path will generally have no need
- * to contain calls to this method; they are typically introduced
- * by a Other
+ * Certificate fields such as the subject public key, the signature
+ * algorithm, key usage, extended key usage, etc. need to conform to
+ * the specified algorithm constraints.
*
- * @author Xuelei Fan
+ * @see PKIXCertPathChecker
+ * @see PKIXParameters
*/
final public class AlgorithmChecker extends PKIXCertPathChecker {
- // the disabled algorithms
- private static final String[] disabledAlgorithms = new String[] {"md2"};
+ private final AlgorithmConstraints constraints;
+ private final PublicKey trustedPubKey;
+ private PublicKey prevPubKey;
+
+ private final static Set
+ * Note that this constructor will be used to check a certification
+ * path where the trust anchor is unknown, or a certificate list which may
+ * contain the trust anchor. This constructor is used by SunJSSE.
+ *
+ * @param constraints the algorithm constraints (or null)
*/
- static AlgorithmChecker getInstance() {
- return INSTANCE;
+ public AlgorithmChecker(AlgorithmConstraints constraints) {
+ this.prevPubKey = null;
+ this.trustedPubKey = null;
+ this.constraints = constraints;
}
/**
- * Initializes the internal state of the checker from parameters
- * specified in the constructor.
+ * Create a new
+ * If there is no trust anchor specified and the checker has not started,
+ * set the trust anchor.
+ *
+ * @param anchor the trust anchor selected to validate the target
+ * certificate
+ */
+ void trySetTrustAnchor(TrustAnchor anchor) {
+ // Don't bother if the check has started or trust anchor has already
+ // specified.
+ if (prevPubKey == null) {
+ if (anchor == null) {
+ throw new IllegalArgumentException(
+ "The trust anchor cannot be null");
+ }
+
+ // Don't bother to change the trustedPubKey.
+ if (anchor.getTrustedCert() != null) {
+ prevPubKey = anchor.getTrustedCert().getPublicKey();
+ } else {
+ prevPubKey = anchor.getCAPublicKey();
+ }
+ }
}
- private static void check(String algName)
- throws CertPathValidatorException {
+ /**
+ * Check the signature algorithm with the specified public key.
+ *
+ * @param key the public key to verify the CRL signature
+ * @param crl the target CRL
+ */
+ static void check(PublicKey key, X509CRL crl)
+ throws CertPathValidatorException {
- String lowerCaseAlgName = algName.toLowerCase(Locale.ENGLISH);
+ X509CRLImpl x509CRLImpl = null;
+ try {
+ x509CRLImpl = X509CRLImpl.toImpl(crl);
+ } catch (CRLException ce) {
+ throw new CertPathValidatorException(ce);
+ }
- for (String disabled : disabledAlgorithms) {
- // checking the signature algorithm name
- if (lowerCaseAlgName.indexOf(disabled) != -1) {
- throw new CertPathValidatorException(
- "algorithm check failed: " + algName + " is disabled");
- }
+ AlgorithmId algorithmId = x509CRLImpl.getSigAlgId();
+ check(key, algorithmId);
+ }
+
+ /**
+ * Check the signature algorithm with the specified public key.
+ *
+ * @param key the public key to verify the CRL signature
+ * @param crl the target CRL
+ */
+ static void check(PublicKey key, AlgorithmId algorithmId)
+ throws CertPathValidatorException {
+ String sigAlgName = algorithmId.getName();
+ AlgorithmParameters sigAlgParams = algorithmId.getParameters();
+
+ if (!certPathDefaultConstraints.permits(
+ SIGNATURE_PRIMITIVE_SET, sigAlgName, key, sigAlgParams)) {
+ throw new CertPathValidatorException(
+ "algorithm check failed: " + sigAlgName + " is disabled");
}
}
}
+
diff --git a/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java b/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java
index 4dd29710ef1fbabdbf4e0928e8b8efe5e9d07682..a980e7d16573d083049a5ef52a41efb389f1a661 100644
--- a/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java
+++ b/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 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
@@ -289,16 +289,6 @@ class DistributionPointFetcher {
X500Name certIssuer = (X500Name) certImpl.getIssuerDN();
X500Name crlIssuer = (X500Name) crlImpl.getIssuerDN();
- // check the crl signature algorithm
- try {
- AlgorithmChecker.check(crl);
- } catch (CertPathValidatorException cpve) {
- if (debug != null) {
- debug.println("CRL signature algorithm check failed: " + cpve);
- }
- return false;
- }
-
// if crlIssuer is set, verify that it matches the issuer of the
// CRL and the CRL contains an IDP extension with the indirectCRL
// boolean asserted. Otherwise, verify that the CRL issuer matches the
@@ -637,6 +627,16 @@ class DistributionPointFetcher {
}
}
+ // check the crl signature algorithm
+ try {
+ AlgorithmChecker.check(prevKey, crl);
+ } catch (CertPathValidatorException cpve) {
+ if (debug != null) {
+ debug.println("CRL signature algorithm check failed: " + cpve);
+ }
+ return false;
+ }
+
// validate the signature on the CRL
try {
crl.verify(prevKey, provider);
diff --git a/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java b/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java
index ae7ccd3884684e68b89420bb64571606d448bca2..7e828884940bcacf8e3a75601ec449117c05b39e 100644
--- a/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java
+++ b/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -718,11 +718,6 @@ class ForwardBuilder extends Builder {
/* we don't perform any validation of the trusted cert */
if (!isTrustedCert) {
- /*
- * check that the signature algorithm is not disabled.
- */
- AlgorithmChecker.check(cert);
-
/*
* Check CRITICAL private extensions for user checkers that
* support forward checking (forwardCheckers) and remove
diff --git a/src/share/classes/sun/security/provider/certpath/OCSPChecker.java b/src/share/classes/sun/security/provider/certpath/OCSPChecker.java
index b72cd79a31cf6dccfa7556460e215dc109df613f..d734ff90408f9eaeb6248c31d867860def3db481 100644
--- a/src/share/classes/sun/security/provider/certpath/OCSPChecker.java
+++ b/src/share/classes/sun/security/provider/certpath/OCSPChecker.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -327,6 +327,10 @@ class OCSPChecker extends PKIXCertPathChecker {
"(set using the OCSP security properties).");
}
+ // The algorithm constraints of the OCSP trusted responder certificate
+ // does not need to be checked in this code. The constraints will be
+ // checked when the responder's certificate is validated.
+
CertId certId = null;
OCSPResponse response = null;
try {
diff --git a/src/share/classes/sun/security/provider/certpath/OCSPResponse.java b/src/share/classes/sun/security/provider/certpath/OCSPResponse.java
index 0b64e412cf688a02cb9964a3cd1ecc89dd67aa3d..63566dd555879a8f378873a8daab0f7d241e6e06 100644
--- a/src/share/classes/sun/security/provider/certpath/OCSPResponse.java
+++ b/src/share/classes/sun/security/provider/certpath/OCSPResponse.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -32,6 +32,7 @@ import java.security.cert.CertificateException;
import java.security.cert.CertificateParsingException;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CRLReason;
+import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.Date;
@@ -371,6 +372,13 @@ public final class OCSPResponse {
"OCSP responses", cpe);
}
+ // Check algorithm constraints specified in security property
+ // "jdk.certpath.disabledAlgorithms".
+ AlgorithmChecker algChecker = new AlgorithmChecker(
+ new TrustAnchor(responderCert, null));
+ algChecker.init(false);
+ algChecker.check(cert, Collections.
- *
+ *
* This class supports both the Simple validation algorithm from previous
* JSSE versions and PKIX validation. Currently, it is not possible for the
* application to specify PKIX parameters other than trust anchors. This will
@@ -50,19 +51,10 @@ import sun.security.util.HostnameChecker;
* classes.
*
* @author Andreas Sterbenz
- * @author Xuelei Fan
*/
final class X509TrustManagerImpl extends X509ExtendedTrustManager
implements X509TrustManager {
- /**
- * Flag indicating whether to enable revocation check for the PKIX trust
- * manager. Typically, this will only work if the PKIX implementation
- * supports CRL distribution points as we do not manually setup CertStores.
- */
- private final static boolean checkRevocation =
- Debug.getBooleanProperty("com.sun.net.ssl.checkRevocation", false);
-
private final String validatorType;
/**
@@ -103,188 +95,259 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager
showTrustedCerts();
}
- private void showTrustedCerts() {
- if (debug != null && Debug.isOn("trustmanager")) {
- for (X509Certificate cert : trustedCerts) {
- System.out.println("adding as trusted cert:");
- System.out.println(" Subject: "
- + cert.getSubjectX500Principal());
- System.out.println(" Issuer: "
- + cert.getIssuerX500Principal());
- System.out.println(" Algorithm: "
- + cert.getPublicKey().getAlgorithm()
- + "; Serial number: 0x"
- + cert.getSerialNumber().toString(16));
- System.out.println(" Valid from "
- + cert.getNotBefore() + " until "
- + cert.getNotAfter());
- System.out.println();
- }
- }
+ @Override
+ public void checkClientTrusted(X509Certificate chain[], String authType)
+ throws CertificateException {
+ checkTrusted(chain, authType, (Socket)null, true);
}
- private Validator getValidator(String variant) {
- Validator v;
- if (pkixParams == null) {
- v = Validator.getInstance(validatorType, variant, trustedCerts);
- // if the PKIX validator is created from a KeyStore,
- // disable revocation checking
- if (v instanceof PKIXValidator) {
- PKIXValidator pkixValidator = (PKIXValidator)v;
- pkixValidator.getParameters().setRevocationEnabled
- (checkRevocation);
- }
- } else {
- v = Validator.getInstance(validatorType, variant, pkixParams);
- }
- return v;
+ @Override
+ public void checkServerTrusted(X509Certificate chain[], String authType)
+ throws CertificateException {
+ checkTrusted(chain, authType, (Socket)null, false);
}
- private static X509Certificate[] validate(Validator v,
- X509Certificate[] chain, String authType) throws CertificateException {
- Object o = JsseJce.beginFipsProvider();
- try {
- return v.validate(chain, null, authType);
- } finally {
- JsseJce.endFipsProvider(o);
- }
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ X509Certificate[] certsArray = new X509Certificate[trustedCerts.size()];
+ trustedCerts.toArray(certsArray);
+ return certsArray;
}
- /**
- * Returns true if the client certificate can be trusted.
- *
- * @param chain certificates which establish an identity for the client.
- * Chains of arbitrary length are supported, and certificates
- * marked internally as trusted will short-circuit signature checks.
- * @throws IllegalArgumentException if null or zero-length chain
- * is passed in for the chain parameter or if null or zero-length
- * string is passed in for the authType parameter.
- * @throws CertificateException if the certificate chain is not trusted
- * by this TrustManager.
- */
- public void checkClientTrusted(X509Certificate chain[], String authType)
- throws CertificateException {
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType,
+ Socket socket) throws CertificateException {
+ checkTrusted(chain, authType, socket, true);
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType,
+ Socket socket) throws CertificateException {
+ checkTrusted(chain, authType, socket, false);
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType,
+ SSLEngine engine) throws CertificateException {
+ checkTrusted(chain, authType, engine, true);
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType,
+ SSLEngine engine) throws CertificateException {
+ checkTrusted(chain, authType, engine, false);
+ }
+
+ private Validator checkTrustedInit(X509Certificate[] chain,
+ String authType, boolean isClient) {
if (chain == null || chain.length == 0) {
throw new IllegalArgumentException(
"null or zero-length certificate chain");
}
+
if (authType == null || authType.length() == 0) {
throw new IllegalArgumentException(
"null or zero-length authentication type");
}
- // assume double checked locking with a volatile flag works
- // (guaranteed under the new Tiger memory model)
- Validator v = clientValidator;
- if (v == null) {
- synchronized (this) {
- v = clientValidator;
- if (v == null) {
- v = getValidator(Validator.VAR_TLS_CLIENT);
- clientValidator = v;
+ Validator v = null;
+ if (isClient) {
+ v = clientValidator;
+ if (v == null) {
+ synchronized (this) {
+ v = clientValidator;
+ if (v == null) {
+ v = getValidator(Validator.VAR_TLS_CLIENT);
+ clientValidator = v;
+ }
+ }
+ }
+ } else {
+ // assume double checked locking with a volatile flag works
+ // (guaranteed under the new Tiger memory model)
+ v = serverValidator;
+ if (v == null) {
+ synchronized (this) {
+ v = serverValidator;
+ if (v == null) {
+ v = getValidator(Validator.VAR_TLS_SERVER);
+ serverValidator = v;
+ }
+ }
+ }
+ }
+
+ return v;
+ }
+
+
+ private void checkTrusted(X509Certificate[] chain, String authType,
+ Socket socket, boolean isClient) throws CertificateException {
+ Validator v = checkTrustedInit(chain, authType, isClient);
+
+ AlgorithmConstraints constraints = null;
+ if ((socket != null) && socket.isConnected() &&
+ (socket instanceof SSLSocket)) {
+
+ SSLSocket sslSocket = (SSLSocket)socket;
+ SSLSession session = sslSocket.getHandshakeSession();
+ if (session == null) {
+ throw new CertificateException("No handshake session");
+ }
+
+ // check endpoint identity
+ String identityAlg = sslSocket.getSSLParameters().
+ getEndpointIdentificationAlgorithm();
+ if (identityAlg != null && identityAlg.length() != 0) {
+ String hostname = session.getPeerHost();
+ checkIdentity(hostname, chain[0], identityAlg);
+ }
+
+ // create the algorithm constraints
+ ProtocolVersion protocolVersion =
+ ProtocolVersion.valueOf(session.getProtocol());
+ if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+ if (session instanceof ExtendedSSLSession) {
+ ExtendedSSLSession extSession =
+ (ExtendedSSLSession)session;
+ String[] localSupportedSignAlgs =
+ extSession.getLocalSupportedSignatureAlgorithms();
+
+ constraints = new SSLAlgorithmConstraints(
+ sslSocket, localSupportedSignAlgs, false);
+ } else {
+ constraints =
+ new SSLAlgorithmConstraints(sslSocket, false);
}
+ } else {
+ constraints = new SSLAlgorithmConstraints(sslSocket, false);
}
}
- X509Certificate[] trustedChain = validate(v, chain, null);
+
+ X509Certificate[] trustedChain = null;
+ if (isClient) {
+ trustedChain = validate(v, chain, constraints, null);
+ } else {
+ trustedChain = validate(v, chain, constraints, authType);
+ }
if (debug != null && Debug.isOn("trustmanager")) {
System.out.println("Found trusted certificate:");
System.out.println(trustedChain[trustedChain.length - 1]);
}
}
- /**
- * Returns true if the server certifcate can be trusted.
- *
- * @param chain certificates which establish an identity for the server.
- * Chains of arbitrary length are supported, and certificates
- * marked internally as trusted will short-circuit signature checks.
- * @throws IllegalArgumentException if null or zero-length chain
- * is passed in for the chain parameter or if null or zero-length
- * string is passed in for the authType parameter.
- * @throws CertificateException if the certificate chain is not trusted
- * by this TrustManager.
- */
- public void checkServerTrusted(X509Certificate chain[], String authType)
- throws CertificateException {
- if (chain == null || chain.length == 0) {
- throw new IllegalArgumentException(
- "null or zero-length certificate chain");
- }
- if (authType == null || authType.length() == 0) {
- throw new IllegalArgumentException(
- "null or zero-length authentication type");
- }
+ private void checkTrusted(X509Certificate[] chain, String authType,
+ SSLEngine engine, boolean isClient) throws CertificateException {
+ Validator v = checkTrustedInit(chain, authType, isClient);
+
+ AlgorithmConstraints constraints = null;
+ if (engine != null) {
+ SSLSession session = engine.getHandshakeSession();
+ if (session == null) {
+ throw new CertificateException("No handshake session");
+ }
+
+ // check endpoint identity
+ String identityAlg = engine.getSSLParameters().
+ getEndpointIdentificationAlgorithm();
+ if (identityAlg != null && identityAlg.length() != 0) {
+ String hostname = session.getPeerHost();
+ checkIdentity(hostname, chain[0], identityAlg);
+ }
+
+ // create the algorithm constraints
+ ProtocolVersion protocolVersion =
+ ProtocolVersion.valueOf(session.getProtocol());
+ if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+ if (session instanceof ExtendedSSLSession) {
+ ExtendedSSLSession extSession =
+ (ExtendedSSLSession)session;
+ String[] localSupportedSignAlgs =
+ extSession.getLocalSupportedSignatureAlgorithms();
- // assume double checked locking with a volatile flag works
- // (guaranteed under the new Tiger memory model)
- Validator v = serverValidator;
- if (v == null) {
- synchronized (this) {
- v = serverValidator;
- if (v == null) {
- v = getValidator(Validator.VAR_TLS_SERVER);
- serverValidator = v;
+ constraints = new SSLAlgorithmConstraints(
+ engine, localSupportedSignAlgs, false);
+ } else {
+ constraints =
+ new SSLAlgorithmConstraints(engine, false);
}
+ } else {
+ constraints = new SSLAlgorithmConstraints(engine, false);
}
}
- X509Certificate[] trustedChain = validate(v, chain, authType);
+
+ X509Certificate[] trustedChain = null;
+ if (isClient) {
+ trustedChain = validate(v, chain, constraints, null);
+ } else {
+ trustedChain = validate(v, chain, constraints, authType);
+ }
if (debug != null && Debug.isOn("trustmanager")) {
System.out.println("Found trusted certificate:");
System.out.println(trustedChain[trustedChain.length - 1]);
}
}
- /**
- * Returns a list of CAs accepted to authenticate entities for the
- * specified purpose.
- *
- * @param purpose activity for which CAs should be trusted
- * @return list of CAs accepted for authenticating such tasks
- */
- public X509Certificate[] getAcceptedIssuers() {
- X509Certificate[] certsArray = new X509Certificate[trustedCerts.size()];
- trustedCerts.toArray(certsArray);
- return certsArray;
+ private void showTrustedCerts() {
+ if (debug != null && Debug.isOn("trustmanager")) {
+ for (X509Certificate cert : trustedCerts) {
+ System.out.println("adding as trusted cert:");
+ System.out.println(" Subject: "
+ + cert.getSubjectX500Principal());
+ System.out.println(" Issuer: "
+ + cert.getIssuerX500Principal());
+ System.out.println(" Algorithm: "
+ + cert.getPublicKey().getAlgorithm()
+ + "; Serial number: 0x"
+ + cert.getSerialNumber().toString(16));
+ System.out.println(" Valid from "
+ + cert.getNotBefore() + " until "
+ + cert.getNotAfter());
+ System.out.println();
+ }
+ }
}
- /**
- * Given the partial or complete certificate chain provided by the
- * peer, check its identity and build a certificate path to a trusted
- * root, return if it can be validated and is trusted for client SSL
- * authentication based on the authentication type.
- */
- public void checkClientTrusted(X509Certificate[] chain, String authType,
- String hostname, String algorithm) throws CertificateException {
- checkClientTrusted(chain, authType);
- checkIdentity(hostname, chain[0], algorithm);
+ private Validator getValidator(String variant) {
+ Validator v;
+ if (pkixParams == null) {
+ v = Validator.getInstance(validatorType, variant, trustedCerts);
+ } else {
+ v = Validator.getInstance(validatorType, variant, pkixParams);
+ }
+ return v;
}
- /**
- * Given the partial or complete certificate chain provided by the
- * peer, check its identity and build a certificate path to a trusted
- * root, return if it can be validated and is trusted for server SSL
- * authentication based on the authentication type.
- */
- public void checkServerTrusted(X509Certificate[] chain, String authType,
- String hostname, String algorithm) throws CertificateException {
- checkServerTrusted(chain, authType);
- checkIdentity(hostname, chain[0], algorithm);
+ private static X509Certificate[] validate(Validator v,
+ X509Certificate[] chain, AlgorithmConstraints constraints,
+ String authType) throws CertificateException {
+ Object o = JsseJce.beginFipsProvider();
+ try {
+ return v.validate(chain, null, constraints, authType);
+ } finally {
+ JsseJce.endFipsProvider(o);
+ }
}
- // Identify the peer by its certificate and hostname.
- private void checkIdentity(String hostname, X509Certificate cert,
- String algorithm) throws CertificateException {
+ /*
+ * Identify the peer by its certificate and hostname.
+ *
+ * Lifted from sun.net.www.protocol.https.HttpsClient.
+ */
+ static void checkIdentity(String hostname, X509Certificate cert,
+ String algorithm) throws CertificateException {
if (algorithm != null && algorithm.length() != 0) {
// if IPv6 strip off the "[]"
- if (hostname != null && hostname.startsWith("[") &&
- hostname.endsWith("]")) {
- hostname = hostname.substring(1, hostname.length()-1);
+ if ((hostname != null) && hostname.startsWith("[") &&
+ hostname.endsWith("]")) {
+ hostname = hostname.substring(1, hostname.length() - 1);
}
if (algorithm.equalsIgnoreCase("HTTPS")) {
HostnameChecker.getInstance(HostnameChecker.TYPE_TLS).match(
hostname, cert);
- } else if (algorithm.equalsIgnoreCase("LDAP")) {
+ } else if (algorithm.equalsIgnoreCase("LDAP") ||
+ algorithm.equalsIgnoreCase("LDAPS")) {
HostnameChecker.getInstance(HostnameChecker.TYPE_LDAP).match(
hostname, cert);
} else {
diff --git a/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java b/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java
index 8cc2d0e497dc47f8c2351606726f399aedca53f8..7e220bc06ebce22f0bb0167b3c585a91caedd4fd 100644
--- a/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java
+++ b/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java
@@ -244,7 +244,7 @@ public final class KerberosClientKeyExchangeImpl
clientVersion, rand, input, sessionKey);
} else {
// Generate bogus premaster secret
- preMaster = new KerberosPreMasterSecret(protocolVersion, rand);
+ preMaster = new KerberosPreMasterSecret(clientVersion, rand);
}
}
diff --git a/src/share/classes/sun/security/ssl/krb5/KerberosPreMasterSecret.java b/src/share/classes/sun/security/ssl/krb5/KerberosPreMasterSecret.java
index 0d7571aab7525e6ad815e6890bca705af0a97f24..84c96a35b3fa2404960223bba7ef2cdb2fec9dbe 100644
--- a/src/share/classes/sun/security/ssl/krb5/KerberosPreMasterSecret.java
+++ b/src/share/classes/sun/security/ssl/krb5/KerberosPreMasterSecret.java
@@ -176,13 +176,21 @@ final class KerberosPreMasterSecret {
// check if the premaster secret version is ok
// the specification says that it must be the maximum version supported
// by the client from its ClientHello message. However, many
- // implementations send the negotiated version, so accept both
+ // old implementations send the negotiated version, so accept both
+ // for SSL v3.0 and TLS v1.0.
// NOTE that we may be comparing two unsupported version numbers in
// the second case, which is why we cannot use object references
// equality in this special case
- boolean versionMismatch = (protocolVersion != currentVersion) &&
- (protocolVersion.v != clientVersion.v);
+ boolean versionMismatch = (protocolVersion.v != clientVersion.v);
+ /*
+ * we never checked the client_version in server side
+ * for TLS v1.0 and SSL v3.0. For compatibility, we
+ * maintain this behavior.
+ */
+ if (versionMismatch && (clientVersion.v <= 0x0301)) {
+ versionMismatch = (protocolVersion.v != currentVersion.v);
+ }
/*
* Bogus decrypted ClientKeyExchange? If so, conjure a
@@ -203,8 +211,14 @@ final class KerberosPreMasterSecret {
Debug.println(System.out, "Invalid secret", preMaster);
}
}
- preMaster = generatePreMaster(generator, currentVersion);
- protocolVersion = currentVersion;
+
+ /*
+ * Randomize the preMaster secret with the
+ * ClientHello.client_version, as will produce invalid master
+ * secret to prevent the attacks.
+ */
+ preMaster = generatePreMaster(generator, clientVersion);
+ protocolVersion = clientVersion;
}
}
diff --git a/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java b/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java
new file mode 100644
index 0000000000000000000000000000000000000000..a537c55485422f0d3b957fbe6144b1cd5929f34e
--- /dev/null
+++ b/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java
@@ -0,0 +1,486 @@
+/*
+ * 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.security.util;
+
+import java.security.AlgorithmConstraints;
+import java.security.CryptoPrimitive;
+import java.security.AlgorithmParameters;
+
+import java.security.Key;
+import java.security.Security;
+import java.security.PrivilegedAction;
+import java.security.AccessController;
+import java.security.interfaces.ECKey;
+import java.security.interfaces.RSAKey;
+import java.security.interfaces.DSAKey;
+import javax.crypto.SecretKey;
+import javax.crypto.interfaces.DHKey;
+
+import java.util.Locale;
+import java.util.Set;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+/**
+ * Algorithm constraints for disabled algorithms property
+ *
+ * See the "jdk.certpath.disabledAlgorithms" specification in java.security
+ * for the syntax of the disabled algorithm string.
+ */
+public class DisabledAlgorithmConstraints implements AlgorithmConstraints {
+
+ // the known security property, jdk.certpath.disabledAlgorithms
+ public final static String PROPERTY_CERTPATH_DISABLED_ALGS =
+ "jdk.certpath.disabledAlgorithms";
+
+ // the known security property, jdk.tls.disabledAlgorithms
+ public final static String PROPERTY_TLS_DISABLED_ALGS =
+ "jdk.tls.disabledAlgorithms";
+
+ private static Map
+ * For example, we need to decompose "SHA1WithRSA" into "SHA1" and "RSA"
+ * so that we can check the "SHA1" and "RSA" algorithm constraints
+ * separately.
+ *
+ * Please override the method if need to support more name pattern.
+ */
+ protected SetAffineTransform class represents a 2D affine transform
@@ -508,6 +509,7 @@ public class AffineTransform implements Cloneable, java.io.Serializable {
* @param m12 the Y coordinate translation element of the 3x3 matrix
* @since 1.2
*/
+ @ConstructorProperties({ "scaleX", "shearY", "shearX", "scaleY", "translateX", "translateY" })
public AffineTransform(float m00, float m10,
float m01, float m11,
float m02, float m12) {
diff --git a/src/share/classes/java/io/ObjectInputStream.java b/src/share/classes/java/io/ObjectInputStream.java
index 3a5c1dee08093c6922e01b9d9ae0ed53f22b07f4..2ed505f3b07c6cd940bb632037e8e854f9cf4cd9 100644
--- a/src/share/classes/java/io/ObjectInputStream.java
+++ b/src/share/classes/java/io/ObjectInputStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -265,7 +265,7 @@ public class ObjectInputStream
* object currently being deserialized and descriptor for current class.
* Null when not during readObject upcall.
*/
- private CallbackContext curContext;
+ private SerialCallbackContext curContext;
/**
* Creates an ObjectInputStream that reads from the specified InputStream.
@@ -1798,7 +1798,7 @@ public class ObjectInputStream
private void readExternalData(Externalizable obj, ObjectStreamClass desc)
throws IOException
{
- CallbackContext oldContext = curContext;
+ SerialCallbackContext oldContext = curContext;
curContext = null;
try {
boolean blocked = desc.hasBlockExternalData();
@@ -1857,10 +1857,10 @@ public class ObjectInputStream
slotDesc.hasReadObjectMethod() &&
handles.lookupException(passHandle) == null)
{
- CallbackContext oldContext = curContext;
+ SerialCallbackContext oldContext = curContext;
try {
- curContext = new CallbackContext(obj, slotDesc);
+ curContext = new SerialCallbackContext(obj, slotDesc);
bin.setBlockDataMode(true);
slotDesc.invokeReadObject(obj, this);
@@ -3505,42 +3505,4 @@ public class ObjectInputStream
}
}
- /**
- * Context that during upcalls to class-defined readObject methods; holds
- * object currently being deserialized and descriptor for current class.
- * This context keeps a boolean state to indicate that defaultReadObject
- * or readFields has already been invoked with this context or the class's
- * readObject method has returned; if true, the getObj method throws
- * NotActiveException.
- */
- private static class CallbackContext {
- private final Object obj;
- private final ObjectStreamClass desc;
- private final AtomicBoolean used = new AtomicBoolean();
-
- public CallbackContext(Object obj, ObjectStreamClass desc) {
- this.obj = obj;
- this.desc = desc;
- }
-
- public Object getObj() throws NotActiveException {
- checkAndSetUsed();
- return obj;
- }
-
- public ObjectStreamClass getDesc() {
- return desc;
- }
-
- private void checkAndSetUsed() throws NotActiveException {
- if (!used.compareAndSet(false, true)) {
- throw new NotActiveException(
- "not in readObject invocation or fields already read");
- }
- }
-
- public void setUsed() {
- used.set(true);
- }
- }
}
diff --git a/src/share/classes/java/io/ObjectOutputStream.java b/src/share/classes/java/io/ObjectOutputStream.java
index 3a722d43a9efdc0fe36fc9d7cb5196b7e83976d6..5b37e4dc6ca494b4bd549940d4fdafd6b6b27d08 100644
--- a/src/share/classes/java/io/ObjectOutputStream.java
+++ b/src/share/classes/java/io/ObjectOutputStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -35,6 +35,7 @@ import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import static java.io.ObjectStreamClass.processQueue;
+import java.io.SerialCallbackContext;
/**
* An ObjectOutputStream writes primitive data types and graphs of Java objects
@@ -191,10 +192,12 @@ public class ObjectOutputStream
private boolean enableReplace;
// values below valid only during upcalls to writeObject()/writeExternal()
- /** object currently being serialized */
- private Object curObj;
- /** descriptor for current class (null if in writeExternal()) */
- private ObjectStreamClass curDesc;
+ /**
+ * Context during upcalls to class-defined writeObject methods; holds
+ * object currently being serialized and descriptor for current class.
+ * Null when not during writeObject upcall.
+ */
+ private SerialCallbackContext curContext;
/** current PutField object */
private PutFieldImpl curPut;
@@ -426,9 +429,11 @@ public class ObjectOutputStream
* OutputStream
*/
public void defaultWriteObject() throws IOException {
- if (curObj == null || curDesc == null) {
+ if ( curContext == null ) {
throw new NotActiveException("not in call to writeObject");
}
+ Object curObj = curContext.getObj();
+ ObjectStreamClass curDesc = curContext.getDesc();
bout.setBlockDataMode(false);
defaultWriteFields(curObj, curDesc);
bout.setBlockDataMode(true);
@@ -446,9 +451,11 @@ public class ObjectOutputStream
*/
public ObjectOutputStream.PutField putFields() throws IOException {
if (curPut == null) {
- if (curObj == null || curDesc == null) {
+ if (curContext == null) {
throw new NotActiveException("not in call to writeObject");
}
+ Object curObj = curContext.getObj();
+ ObjectStreamClass curDesc = curContext.getDesc();
curPut = new PutFieldImpl(curDesc);
}
return curPut;
@@ -1420,17 +1427,15 @@ public class ObjectOutputStream
* writeExternal() method.
*/
private void writeExternalData(Externalizable obj) throws IOException {
- Object oldObj = curObj;
- ObjectStreamClass oldDesc = curDesc;
PutFieldImpl oldPut = curPut;
- curObj = obj;
- curDesc = null;
curPut = null;
if (extendedDebugInfo) {
debugInfoStack.push("writeExternal data");
}
+ SerialCallbackContext oldContext = curContext;
try {
+ curContext = null;
if (protocol == PROTOCOL_VERSION_1) {
obj.writeExternal(this);
} else {
@@ -1440,13 +1445,12 @@ public class ObjectOutputStream
bout.writeByte(TC_ENDBLOCKDATA);
}
} finally {
+ curContext = oldContext;
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
- curObj = oldObj;
- curDesc = oldDesc;
curPut = oldPut;
}
@@ -1461,12 +1465,9 @@ public class ObjectOutputStream
for (int i = 0; i < slots.length; i++) {
ObjectStreamClass slotDesc = slots[i].desc;
if (slotDesc.hasWriteObjectMethod()) {
- Object oldObj = curObj;
- ObjectStreamClass oldDesc = curDesc;
PutFieldImpl oldPut = curPut;
- curObj = obj;
- curDesc = slotDesc;
curPut = null;
+ SerialCallbackContext oldContext = curContext;
if (extendedDebugInfo) {
debugInfoStack.push(
@@ -1474,18 +1475,19 @@ public class ObjectOutputStream
slotDesc.getName() + "\")");
}
try {
+ curContext = new SerialCallbackContext(obj, slotDesc);
bout.setBlockDataMode(true);
slotDesc.invokeWriteObject(obj, this);
bout.setBlockDataMode(false);
bout.writeByte(TC_ENDBLOCKDATA);
} finally {
+ curContext.setUsed();
+ curContext = oldContext;
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
- curObj = oldObj;
- curDesc = oldDesc;
curPut = oldPut;
} else {
defaultWriteFields(obj, slotDesc);
diff --git a/src/share/classes/java/io/ObjectStreamClass.java b/src/share/classes/java/io/ObjectStreamClass.java
index 6b54f36f4b3754dcea51d288a781c873e5c868be..b3842f9128cf57e1f898d438bf6cf6a5111c2048 100644
--- a/src/share/classes/java/io/ObjectStreamClass.java
+++ b/src/share/classes/java/io/ObjectStreamClass.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -1830,8 +1830,10 @@ public class ObjectStreamClass implements Serializable {
private final ObjectStreamField[] fields;
/** number of primitive fields */
private final int numPrimFields;
- /** unsafe field keys */
- private final long[] keys;
+ /** unsafe field keys for reading fields - may contain dupes */
+ private final long[] readKeys;
+ /** unsafe fields keys for writing fields - no dupes */
+ private final long[] writeKeys;
/** field data offsets */
private final int[] offsets;
/** field type codes */
@@ -1849,16 +1851,22 @@ public class ObjectStreamClass implements Serializable {
FieldReflector(ObjectStreamField[] fields) {
this.fields = fields;
int nfields = fields.length;
- keys = new long[nfields];
+ readKeys = new long[nfields];
+ writeKeys = new long[nfields];
offsets = new int[nfields];
typeCodes = new char[nfields];
ArrayList
- *
- * Additional (implementation specific) options may also be supported.
- *
- *
- *
- *
- *
- * Option Name
- * Description
- *
- *
- * {@link java.net.StandardSocketOption#SO_SNDBUF SO_SNDBUF}
- * The size of the socket send buffer
- *
- *
- * {@link java.net.StandardSocketOption#SO_RCVBUF SO_RCVBUF}
- * The size of the socket receive buffer
- *
- *
- * {@link java.net.StandardSocketOption#SO_REUSEADDR SO_REUSEADDR}
- * Re-use address
- *
- *
- * {@link java.net.StandardSocketOption#SO_BROADCAST SO_BROADCAST}
- * Allow transmission of broadcast datagrams
- *
- *
- * {@link java.net.StandardSocketOption#IP_TOS IP_TOS}
- * The Type of Service (ToS) octet in the Internet Protocol (IP) header
- *
- *
- * {@link java.net.StandardSocketOption#IP_MULTICAST_IF IP_MULTICAST_IF}
- * The network interface for Internet Protocol (IP) multicast datagrams
- *
- *
- * {@link java.net.StandardSocketOption#IP_MULTICAST_TTL
- * IP_MULTICAST_TTL}
- * The time-to-live for Internet Protocol (IP) multicast
- * datagrams
- *
- *
- * {@link java.net.StandardSocketOption#IP_MULTICAST_LOOP
- * IP_MULTICAST_LOOP}
- * Loopback for Internet Protocol (IP) multicast datagrams
- *
- * final AsynchronousDatagramChannel dc = AsynchronousDatagramChannel.open()
- * .bind(new InetSocketAddress(4000));
- *
- * // print the source address of all packets that we receive
- * dc.receive(buffer, buffer, new CompletionHandler<SocketAddress,ByteBuffer>() {
- * public void completed(SocketAddress sa, ByteBuffer buffer) {
- * System.out.println(sa);
- * buffer.clear();
- * dc.receive(buffer, buffer, this);
- * }
- * public void failed(Throwable exc, ByteBuffer buffer) {
- * ...
- * }
- * });
- *
- *
- * @since 1.7
- */
-
-public abstract class AsynchronousDatagramChannel
- implements AsynchronousByteChannel, MulticastChannel
-{
- private final AsynchronousChannelProvider provider;
-
- /**
- * Initializes a new instance of this class.
- */
- protected AsynchronousDatagramChannel(AsynchronousChannelProvider provider) {
- this.provider = provider;
- }
-
- /**
- * Returns the provider that created this channel.
- */
- public final AsynchronousChannelProvider provider() {
- return provider;
- }
-
- /**
- * Opens an asynchronous datagram channel.
- *
- *
- *
- * @return A new asynchronous datagram channel
- *
- * @throws IOException
- * If an I/O error occurs
- */
- public static AsynchronousDatagramChannel open()
- throws IOException
- {
- return open(null, null);
- }
-
- // -- Socket-specific operations --
-
- /**
- * @throws AlreadyBoundException {@inheritDoc}
- * @throws UnsupportedAddressTypeException {@inheritDoc}
- * @throws ClosedChannelException {@inheritDoc}
- * @throws IOException {@inheritDoc}
- * @throws SecurityException
- * If a security manager has been installed and its {@link
- * SecurityManager#checkListen checkListen} method denies the
- * operation
- */
- @Override
- public abstract AsynchronousDatagramChannel bind(SocketAddress local)
- throws IOException;
-
- /**
- * @throws IllegalArgumentException {@inheritDoc}
- * @throws ClosedChannelException {@inheritDoc}
- * @throws IOException {@inheritDoc}
- */
- @Override
- public abstract
- * open((ProtocolFamily)null, (AsynchronousChannelGroup)null);
- *
An asynchronous channel to a stream-oriented connecting socket
*
- * {@link java.nio.channels.AsynchronousServerSocketChannel}
* An asynchronous channel to a stream-oriented listening socket
* {@link java.nio.channels.AsynchronousDatagramChannel}
- * An asynchronous channel to a datagram-oriented socket
* {@link java.nio.channels.CompletionHandler}
* A handler for consuming the result of an asynchronous operation {@link java.nio.channels.AsynchronousChannelGroup}
diff --git a/src/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java b/src/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java
index 4ed5a707768fd818f6da8511eca79045e6c1cdef..9df31d4645e92306856be6c0c3a6a1d8459684b3 100644
--- a/src/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java
+++ b/src/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java
@@ -26,7 +26,6 @@
package java.nio.channels.spi;
import java.nio.channels.*;
-import java.net.ProtocolFamily;
import java.io.IOException;
import java.util.Iterator;
import java.util.ServiceLoader;
@@ -239,26 +238,4 @@ public abstract class AsynchronousChannelProvider {
*/
public abstract AsynchronousSocketChannel openAsynchronousSocketChannel
(AsynchronousChannelGroup group) throws IOException;
-
- /**
- * Opens an asynchronous datagram channel.
- *
- * @param family
- * The protocol family, or {@code null} for the default protocol
- * family
- * @param group
- * The group to which the channel is bound, or {@code null} to
- * bind to the default group
- *
- * @return The new channel
- *
- * @throws IllegalChannelGroupException
- * If the provider that created the group differs from this provider
- * @throws ShutdownChannelGroupException
- * The group is shutdown
- * @throws IOException
- * If an I/O error occurs
- */
- public abstract AsynchronousDatagramChannel openAsynchronousDatagramChannel
- (ProtocolFamily family, AsynchronousChannelGroup group) throws IOException;
}
diff --git a/src/share/classes/java/security/AlgorithmConstraints.java b/src/share/classes/java/security/AlgorithmConstraints.java
new file mode 100644
index 0000000000000000000000000000000000000000..7341603dc7cf65d3941cee8dce0e38194ed1a560
--- /dev/null
+++ b/src/share/classes/java/security/AlgorithmConstraints.java
@@ -0,0 +1,108 @@
+/*
+ * 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 java.security;
+
+import java.util.Set;
+
+/**
+ * This interface specifies constraints for cryptographic algorithms,
+ * keys (key sizes), and other algorithm parameters.
+ * sun.com, would have
- * domains such as com.sun.MyDomain. This is essentially
+ * example.com would have
+ * domains such as com.example.MyDomain. This is essentially
* the same convention as for Java-language package names.1081892073854801359L.
diff --git a/src/share/classes/javax/management/build.xml b/src/share/classes/javax/management/build.xml
index 24357d694af18828523afdff2446903253aa7648..e1d263520f03c0d83bd5ea5eb419cc2981bb5ac6 100644
--- a/src/share/classes/javax/management/build.xml
+++ b/src/share/classes/javax/management/build.xml
@@ -35,18 +35,18 @@
. Please also read the important comment on basedir definition below.
-->
-SSLSession interface to support additional
+ * session attributes.
+ *
+ * @since 1.7
+ */
+public abstract class ExtendedSSLSession implements SSLSession {
+ /**
+ * Obtains an array of supported signature algorithms that the local side
+ * is willing to use.
+ * SSLParameters.
+ *
+ * @return An array of supported signature algorithms, in descending
+ * order of preference. The return value is an empty array if
+ * no signature algorithm is supported.
+ *
+ * @see SSLParameters#getAlgorithmConstraints
+ */
+ public abstract String[] getLocalSupportedSignatureAlgorithms();
+
+ /**
+ * Obtains an array of supported signature algorithms that the peer is
+ * able to use.
+ * HostnameVerifier.
- */
- static {
- try {
- defaultHostnameVerifier =
- new sun.net.www.protocol.https.DefaultHostnameVerifier();
- } catch (NoClassDefFoundError e) {
- defaultHostnameVerifier = new DefaultHostnameVerifier();
- }
- }
+ private static HostnameVerifier defaultHostnameVerifier =
+ new DefaultHostnameVerifier();
/*
* The initial default HostnameVerifier. Should be
diff --git a/src/share/classes/javax/net/ssl/SSLEngine.java b/src/share/classes/javax/net/ssl/SSLEngine.java
index df3830858a6d96654dfaab89b789ab5e799d49b5..2eea55121cb6ce401edaacb0fd79e6ab4d135627 100644
--- a/src/share/classes/javax/net/ssl/SSLEngine.java
+++ b/src/share/classes/javax/net/ssl/SSLEngine.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -967,6 +967,47 @@ public abstract class SSLEngine {
public abstract SSLSession getSession();
+ /**
+ * Returns the {@code SSLSession} being constructed during a SSL/TLS
+ * handshake.
+ * getSSLParameters()
* methods in
* {@link SSLSocket#getSSLParameters SSLSocket} and
+ * {@link SSLServerSocket#getSSLParameters SSLServerSocket} and
* {@link SSLEngine#getSSLParameters SSLEngine} or the
* {@link SSLContext#getDefaultSSLParameters getDefaultSSLParameters()} and
* {@link SSLContext#getSupportedSSLParameters getSupportedSSLParameters()}
* methods in SSLContext.
- *
- * null,
+ * null,
* wantClientAuth and needClientAuth are set to false.
*/
public SSLParameters() {
@@ -69,6 +76,7 @@ public class SSLParameters {
/**
* Constructs SSLParameters from the specified array of ciphersuites.
+ * setCipherSuites(cipherSuites);.
@@ -82,6 +90,7 @@ public class SSLParameters {
/**
* Constructs SSLParameters from the specified array of ciphersuites
* and protocols.
+ * setCipherSuites(cipherSuites); setProtocols(protocols);.
@@ -178,4 +187,71 @@ public class SSLParameters {
this.needClientAuth = needClientAuth;
}
+ /**
+ * Returns the cryptographic algorithm constraints.
+ *
+ * @return the cryptographic algorithm constraints, or null if the
+ * constraints have not been set
+ *
+ * @see #setAlgorithmConstraints(AlgorithmConstraints)
+ *
+ * @since 1.7
+ */
+ public AlgorithmConstraints getAlgorithmConstraints() {
+ return algorithmConstraints;
+ }
+
+ /**
+ * Sets the cryptographic algorithm constraints, which will be used
+ * in addition to any configured by the runtime environment.
+ * constraints parameter is non-null, every
+ * cryptographic algorithm, key and algorithm parameters used in the
+ * SSL/TLS handshake must be permitted by the constraints.
+ *
+ * @param constraints the algorithm constraints (or null)
+ *
+ * @since 1.7
+ */
+ public void setAlgorithmConstraints(AlgorithmConstraints constraints) {
+ // the constraints object is immutable
+ this.algorithmConstraints = constraints;
+ }
+
+ /**
+ * Gets the endpoint identification algorithm.
+ *
+ * @return the endpoint identification algorithm, or null if none
+ * has been set.
+ *
+ * @see X509ExtendedTrustManager
+ * @see #setEndpointIdentificationAlgorithm(String)
+ *
+ * @since 1.7
+ */
+ public String getEndpointIdentificationAlgorithm() {
+ return identificationAlgorithm;
+ }
+
+ /**
+ * Sets the endpoint identification algorithm.
+ * algorithm parameter is non-null or non-empty, the
+ * endpoint identification/verification procedures must be handled during
+ * SSL/TLS handshaking. This is to prevent man-in-the-middle attacks.
+ *
+ * @param algorithm The standard string name of the endpoint
+ * identification algorithm (or null). See Appendix A in the
+ * Java Cryptography Architecture API Specification & Reference
+ * for information about standard algorithm names.
+ *
+ * @see X509ExtendedTrustManager
+ *
+ * @since 1.7
+ */
+ public void setEndpointIdentificationAlgorithm(String algorithm) {
+ this.identificationAlgorithm = algorithm;
+ }
+
}
diff --git a/src/share/classes/javax/net/ssl/SSLServerSocket.java b/src/share/classes/javax/net/ssl/SSLServerSocket.java
index 6bcb8a678e8f14cb7acd0d41b6d16dca7fbbdf60..d5bbaaf5da5ab79d9dd0f6a60ecb87550b550570 100644
--- a/src/share/classes/javax/net/ssl/SSLServerSocket.java
+++ b/src/share/classes/javax/net/ssl/SSLServerSocket.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -56,8 +56,8 @@ import java.net.*;
* @since 1.4
* @author David Brownell
*/
-public abstract class SSLServerSocket extends ServerSocket
-{
+public abstract class SSLServerSocket extends ServerSocket {
+
/**
* Used only by subclasses.
*
+ *
+ *
+ * @param params the parameters
+ * @throws IllegalArgumentException if the setEnabledCipherSuites() or
+ * the setEnabledProtocols() call fails
+ *
+ * @see #getSSLParameters()
+ *
+ * @since 1.7
+ */
+ public void setSSLParameters(SSLParameters params) {
+ String[] s;
+ s = params.getCipherSuites();
+ if (s != null) {
+ setEnabledCipherSuites(s);
+ }
+
+ s = params.getProtocols();
+ if (s != null) {
+ setEnabledProtocols(s);
+ }
+
+ if (params.getNeedClientAuth()) {
+ setNeedClientAuth(true);
+ } else if (params.getWantClientAuth()) {
+ setWantClientAuth(true);
+ } else {
+ setWantClientAuth(false);
+ }
+ }
+
}
diff --git a/src/share/classes/javax/net/ssl/SSLSocket.java b/src/share/classes/javax/net/ssl/SSLSocket.java
index 29b69f1ccbf000821871fce2810de7da70725cf5..b61f94a5a75801dc67fb53bbb3dcec193f4a594e 100644
--- a/src/share/classes/javax/net/ssl/SSLSocket.java
+++ b/src/share/classes/javax/net/ssl/SSLSocket.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -370,6 +370,51 @@ public abstract class SSLSocket extends Socket
public abstract SSLSession getSession();
+ /**
+ * Returns the {@code SSLSession} being constructed during a SSL/TLS
+ * handshake.
+ * params.getCipherSuites() is non-null,
+ * setEnabledCipherSuites() is called with that value
+ * params.getProtocols() is non-null,
+ * setEnabledProtocols() is called with that value
+ * params.getNeedClientAuth() or
+ * params.getWantClientAuth() return true,
+ * setNeedClientAuth(true) and
+ * setWantClientAuth(true) are called, respectively;
+ * otherwise setWantClientAuth(false) is called.
+ * X509TrustManager interface to support
+ * SSL/TLS connection sensitive trust management.
+ * socket parameter is an instance of
+ * {@link javax.net.SSLSocket}, and the endpoint identification
+ * algorithm of the SSLParameters is non-empty, to prevent
+ * man-in-the-middle attacks, the address that the socket
+ * connected to should be checked against the peer's identity presented
+ * in the end-entity X509 certificate, as specified in the endpoint
+ * identification algorithm.
+ * socket parameter is an instance of
+ * {@link javax.net.SSLSocket}, and the algorithm constraints of the
+ * SSLParameters is non-null, for every certificate in the
+ * certification path, fields such as subject public key, the signature
+ * algorithm, key usage, extended key usage, etc. need to conform to the
+ * algorithm constraints in place on this socket.
+ *
+ * @param chain the peer certificate chain
+ * @param authType the key exchange algorithm used
+ * @param socket the socket used for this connection. This parameter
+ * can be null, which indicates that implementations need not check
+ * the ssl parameters
+ * @throws IllegalArgumentException if null or zero-length array is passed
+ * in for the chain parameter or if null or zero-length
+ * string is passed in for the authType parameter
+ * @throws CertificateException if the certificate chain is not trusted
+ * by this TrustManager
+ *
+ * @see SSLParameters#getEndpointIdentificationProtocol
+ * @see SSLParameters#setEndpointIdentificationProtocol(String)
+ * @see SSLParameters#getAlgorithmConstraints
+ * @see SSLParameters#setAlgorithmConstraints(AlgorithmConstraints)
+ */
+ public abstract void checkClientTrusted(X509Certificate[] chain,
+ String authType, Socket socket) throws CertificateException;
+
+ /**
+ * Given the partial or complete certificate chain provided by the
+ * peer, build and validate the certificate path based on the
+ * authentication type and ssl parameters.
+ * socket parameter is an instance of
+ * {@link javax.net.SSLSocket}, and the endpoint identification
+ * algorithm of the SSLParameters is non-empty, to prevent
+ * man-in-the-middle attacks, the address that the socket
+ * connected to should be checked against the peer's identity presented
+ * in the end-entity X509 certificate, as specified in the endpoint
+ * identification algorithm.
+ * socket parameter is an instance of
+ * {@link javax.net.SSLSocket}, and the algorithm constraints of the
+ * SSLParameters is non-null, for every certificate in the
+ * certification path, fields such as subject public key, the signature
+ * algorithm, key usage, extended key usage, etc. need to conform to the
+ * algorithm constraints in place on this socket.
+ *
+ * @param chain the peer certificate chain
+ * @param authType the key exchange algorithm used
+ * @param socket the socket used for this connection. This parameter
+ * can be null, which indicates that implementations need not check
+ * the ssl parameters
+ * @throws IllegalArgumentException if null or zero-length array is passed
+ * in for the chain parameter or if null or zero-length
+ * string is passed in for the authType parameter
+ * @throws CertificateException if the certificate chain is not trusted
+ * by this TrustManager
+ *
+ * @see SSLParameters#getEndpointIdentificationProtocol
+ * @see SSLParameters#setEndpointIdentificationProtocol(String)
+ * @see SSLParameters#getAlgorithmConstraints
+ * @see SSLParameters#setAlgorithmConstraints(AlgorithmConstraints)
+ */
+ public abstract void checkServerTrusted(X509Certificate[] chain,
+ String authType, Socket socket) throws CertificateException;
+
+ /**
+ * Given the partial or complete certificate chain provided by the
+ * peer, build and validate the certificate path based on the
+ * authentication type and ssl parameters.
+ * engine parameter is available, and the endpoint
+ * identification algorithm of the SSLParameters is
+ * non-empty, to prevent man-in-the-middle attacks, the address that
+ * the engine connected to should be checked against
+ * the peer's identity presented in the end-entity X509 certificate,
+ * as specified in the endpoint identification algorithm.
+ * engine parameter is available, and the algorithm
+ * constraints of the SSLParameters is non-null, for every
+ * certificate in the certification path, fields such as subject public
+ * key, the signature algorithm, key usage, extended key usage, etc.
+ * need to conform to the algorithm constraints in place on this engine.
+ *
+ * @param chain the peer certificate chain
+ * @param authType the key exchange algorithm used
+ * @param engine the engine used for this connection. This parameter
+ * can be null, which indicates that implementations need not check
+ * the ssl parameters
+ * @throws IllegalArgumentException if null or zero-length array is passed
+ * in for the chain parameter or if null or zero-length
+ * string is passed in for the authType parameter
+ * @throws CertificateException if the certificate chain is not trusted
+ * by this TrustManager
+ *
+ * @see SSLParameters#getEndpointIdentificationProtocol
+ * @see SSLParameters#setEndpointIdentificationProtocol(String)
+ * @see SSLParameters#getAlgorithmConstraints
+ * @see SSLParameters#setAlgorithmConstraints(AlgorithmConstraints)
+ */
+ public abstract void checkClientTrusted(X509Certificate[] chain,
+ String authType, SSLEngine engine) throws CertificateException;
+
+ /**
+ * Given the partial or complete certificate chain provided by the
+ * peer, build and validate the certificate path based on the
+ * authentication type and ssl parameters.
+ * engine parameter is available, and the endpoint
+ * identification algorithm of the SSLParameters is
+ * non-empty, to prevent man-in-the-middle attacks, the address that
+ * the engine connected to should be checked against
+ * the peer's identity presented in the end-entity X509 certificate,
+ * as specified in the endpoint identification algorithm.
+ * engine parameter is available, and the algorithm
+ * constraints of the SSLParameters is non-null, for every
+ * certificate in the certification path, fields such as subject public
+ * key, the signature algorithm, key usage, extended key usage, etc.
+ * need to conform to the algorithm constraints in place on this engine.
+ *
+ * @param chain the peer certificate chain
+ * @param authType the key exchange algorithm used
+ * @param engine the engine used for this connection. This parameter
+ * can be null, which indicates that implementations need not check
+ * the ssl parameters
+ * @throws IllegalArgumentException if null or zero-length array is passed
+ * in for the chain parameter or if null or zero-length
+ * string is passed in for the authType parameter
+ * @throws CertificateException if the certificate chain is not trusted
+ * by this TrustManager
+ *
+ * @see SSLParameters#getEndpointIdentificationProtocol
+ * @see SSLParameters#setEndpointIdentificationProtocol(String)
+ * @see SSLParameters#getAlgorithmConstraints
+ * @see SSLParameters#setAlgorithmConstraints(AlgorithmConstraints)
+ */
+ public abstract void checkServerTrusted(X509Certificate[] chain,
+ String authType, SSLEngine engine) throws CertificateException;
+
+}
diff --git a/src/share/classes/javax/swing/BorderFactory.java b/src/share/classes/javax/swing/BorderFactory.java
index 0f53bed456014fd067d77cc2b838fbba3c8cb3e1..e288d0bd4d8a3ed210e81a33929f21ff13b9c382 100644
--- a/src/share/classes/javax/swing/BorderFactory.java
+++ b/src/share/classes/javax/swing/BorderFactory.java
@@ -24,8 +24,10 @@
*/
package javax.swing;
+import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
+import java.awt.Paint;
import javax.swing.border.*;
/**
@@ -636,4 +638,125 @@ public class BorderFactory
Icon tileIcon) {
return new MatteBorder(top, left, bottom, right, tileIcon);
}
+
+//// StrokeBorder //////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Creates a border of the specified {@code stroke}.
+ * The component's foreground color will be used to render the border.
+ *
+ * @param stroke the {@link BasicStroke} object used to stroke a shape
+ * @return the {@code Border} object
+ *
+ * @throws NullPointerException if the specified {@code stroke} is {@code null}
+ *
+ * @since 1.7
+ */
+ public static Border createStrokeBorder(BasicStroke stroke) {
+ return new StrokeBorder(stroke);
+ }
+
+ /**
+ * Creates a border of the specified {@code stroke} and {@code paint}.
+ * If the specified {@code paint} is {@code null},
+ * the component's foreground color will be used to render the border.
+ *
+ * @param stroke the {@link BasicStroke} object used to stroke a shape
+ * @param paint the {@link Paint} object used to generate a color
+ * @return the {@code Border} object
+ *
+ * @throws NullPointerException if the specified {@code stroke} is {@code null}
+ *
+ * @since 1.7
+ */
+ public static Border createStrokeBorder(BasicStroke stroke, Paint paint) {
+ return new StrokeBorder(stroke, paint);
+ }
+
+//// DashedBorder //////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+ private static Border sharedDashedBorder;
+
+ /**
+ * Creates a dashed border of the specified {@code paint}.
+ * If the specified {@code paint} is {@code null},
+ * the component's foreground color will be used to render the border.
+ * The width of a dash line is equal to {@code 1}.
+ * The relative length of a dash line and
+ * the relative spacing between dash lines are equal to {@code 1}.
+ * A dash line is not rounded.
+ *
+ * @param paint the {@link Paint} object used to generate a color
+ * @return the {@code Border} object
+ *
+ * @since 1.7
+ */
+ public static Border createDashedBorder(Paint paint) {
+ return createDashedBorder(paint, 1.0f, 1.0f, 1.0f, false);
+ }
+
+ /**
+ * Creates a dashed border of the specified {@code paint},
+ * relative {@code length}, and relative {@code spacing}.
+ * If the specified {@code paint} is {@code null},
+ * the component's foreground color will be used to render the border.
+ * The width of a dash line is equal to {@code 1}.
+ * A dash line is not rounded.
+ *
+ * @param paint the {@link Paint} object used to generate a color
+ * @param length the relative length of a dash line
+ * @param spacing the relative spacing between dash lines
+ * @return the {@code Border} object
+ *
+ * @throws IllegalArgumentException if the specified {@code length} is less than {@code 1}, or
+ * if the specified {@code spacing} is less than {@code 0}
+ * @since 1.7
+ */
+ public static Border createDashedBorder(Paint paint, float length, float spacing) {
+ return createDashedBorder(paint, 1.0f, length, spacing, false);
+ }
+
+ /**
+ * Creates a dashed border of the specified {@code paint}, {@code thickness},
+ * line shape, relative {@code length}, and relative {@code spacing}.
+ * If the specified {@code paint} is {@code null},
+ * the component's foreground color will be used to render the border.
+ *
+ * @param paint the {@link Paint} object used to generate a color
+ * @param thickness the width of a dash line
+ * @param length the relative length of a dash line
+ * @param spacing the relative spacing between dash lines
+ * @param rounded whether or not line ends should be round
+ * @return the {@code Border} object
+ *
+ * @throws IllegalArgumentException if the specified {@code thickness} is less than {@code 1}, or
+ * if the specified {@code length} is less than {@code 1}, or
+ * if the specified {@code spacing} is less than {@code 0}
+ * @since 1.7
+ */
+ public static Border createDashedBorder(Paint paint, float thickness, float length, float spacing, boolean rounded) {
+ boolean shared = !rounded && (paint == null) && (thickness == 1.0f) && (length == 1.0f) && (spacing == 1.0f);
+ if (shared && (sharedDashedBorder != null)) {
+ return sharedDashedBorder;
+ }
+ if (thickness < 1.0f) {
+ throw new IllegalArgumentException("thickness is less than 1");
+ }
+ if (length < 1.0f) {
+ throw new IllegalArgumentException("length is less than 1");
+ }
+ if (spacing < 0.0f) {
+ throw new IllegalArgumentException("spacing is less than 0");
+ }
+ int cap = rounded ? BasicStroke.CAP_ROUND : BasicStroke.CAP_SQUARE;
+ int join = rounded ? BasicStroke.JOIN_ROUND : BasicStroke.JOIN_MITER;
+ float[] array = { thickness * (length - 1.0f), thickness * (spacing + 1.0f) };
+ Border border = createStrokeBorder(new BasicStroke(thickness, cap, join, thickness * 2.0f, array, 0.0f), paint);
+ if (shared) {
+ sharedDashedBorder = border;
+ }
+ return border;
+ }
}
diff --git a/src/share/classes/javax/swing/DebugGraphics.java b/src/share/classes/javax/swing/DebugGraphics.java
index 0549e231cfbfbb7280177d42fc915086d49f6c96..fb6939e4ff7f760e50d62d2ac94259d8b382bec1 100644
--- a/src/share/classes/javax/swing/DebugGraphics.java
+++ b/src/share/classes/javax/swing/DebugGraphics.java
@@ -1322,13 +1322,11 @@ public class DebugGraphics extends Graphics {
}
String toShortString() {
- StringBuffer buffer = new StringBuffer("Graphics" + (isDrawingBuffer() ? "" : "") + "(" + graphicsID + "-" + debugOptions + ")");
- return buffer.toString();
+ return "Graphics" + (isDrawingBuffer() ? "" : "") + "(" + graphicsID + "-" + debugOptions + ")";
}
String pointToString(int x, int y) {
- StringBuffer buffer = new StringBuffer("(" + x + ", " + y + ")");
- return buffer.toString();
+ return "(" + x + ", " + y + ")";
}
/** Enables/disables diagnostic information about every graphics
diff --git a/src/share/classes/javax/swing/JComponent.java b/src/share/classes/javax/swing/JComponent.java
index f94a797ae6c695113bf43e54a8a88d2fb1bf2d7b..6f017402ec7e01e9d8f6b1bc480a35ae7c38e0e8 100644
--- a/src/share/classes/javax/swing/JComponent.java
+++ b/src/share/classes/javax/swing/JComponent.java
@@ -4783,21 +4783,11 @@ public abstract class JComponent extends Container implements Serializable,
* @param y the y value of the dirty region
* @param width the width of the dirty region
* @param height the height of the dirty region
+ * @see #isPaintingOrigin()
* @see java.awt.Component#isShowing
* @see RepaintManager#addDirtyRegion
*/
public void repaint(long tm, int x, int y, int width, int height) {
- Container p = this;
- while ((p = p.getParent()) instanceof JComponent) {
- JComponent jp = (JComponent) p;
- if (jp.isPaintingOrigin()) {
- Rectangle rectangle = SwingUtilities.convertRectangle(
- this, new Rectangle(x, y, width, height), jp);
- jp.repaint(tm,
- rectangle.x, rectangle.y, rectangle.width, rectangle.height);
- return;
- }
- }
RepaintManager.currentManager(this).addDirtyRegion(this, x, y, width, height);
}
@@ -4808,6 +4798,7 @@ public abstract class JComponent extends Container implements Serializable,
* currently pending events have been dispatched.
*
* @param r a Rectangle containing the dirty region
+ * @see #isPaintingOrigin()
* @see java.awt.Component#isShowing
* @see RepaintManager#addDirtyRegion
*/
@@ -4912,13 +4903,19 @@ public abstract class JComponent extends Container implements Serializable,
}
/**
- * Returns true if a paint triggered on a child component should cause
+ * Returns {@code true} if a paint triggered on a child component should cause
* painting to originate from this Component, or one of its ancestors.
+ * JViewport, or one of its
- * ancestors. Otherwise returns false.
+ * Returns true if scroll mode is a {@code BACKINGSTORE_SCROLL_MODE} to cause
+ * painting to originate from {@code JViewport}, or one of its
+ * ancestors. Otherwise returns {@code false}.
*
- * @return true if if scroll mode is a BACKINGSTORE_SCROLL_MODE.
+ * @return true if if scroll mode is a {@code BACKINGSTORE_SCROLL_MODE}.
* @see JComponent#isPaintingOrigin()
*/
- boolean isPaintingOrigin() {
+ protected boolean isPaintingOrigin() {
return scrollMode == BACKINGSTORE_SCROLL_MODE;
}
diff --git a/src/share/classes/javax/swing/RepaintManager.java b/src/share/classes/javax/swing/RepaintManager.java
index d1166f90633fcaa37a8771e4c55d58a0de909434..63444b422be246d3b189da54ba55228134688673 100644
--- a/src/share/classes/javax/swing/RepaintManager.java
+++ b/src/share/classes/javax/swing/RepaintManager.java
@@ -438,6 +438,7 @@ public class RepaintManager
* @param y Y coordinate of the region to repaint
* @param w Width of the region to repaint
* @param h Height of the region to repaint
+ * @see JComponent#isPaintingOrigin()
* @see JComponent#repaint
*/
public void addDirtyRegion(JComponent c, int x, int y, int w, int h)
@@ -447,6 +448,16 @@ public class RepaintManager
delegate.addDirtyRegion(c, x, y, w, h);
return;
}
+ Container p = c;
+ while ((p = p.getParent()) instanceof JComponent) {
+ JComponent jp = (JComponent) p;
+ if (jp.isPaintingOrigin()) {
+ Rectangle rectangle = SwingUtilities.convertRectangle(
+ c, new Rectangle(x, y, w, h), jp);
+ jp.repaint(0, rectangle.x, rectangle.y, rectangle.width, rectangle.height);
+ return;
+ }
+ }
addDirtyRegion0(c, x, y, w, h);
}
diff --git a/src/share/classes/javax/swing/border/StrokeBorder.java b/src/share/classes/javax/swing/border/StrokeBorder.java
new file mode 100644
index 0000000000000000000000000000000000000000..b2538bae2dc8b8d7bf90578d12a4aa5d7996e424
--- /dev/null
+++ b/src/share/classes/javax/swing/border/StrokeBorder.java
@@ -0,0 +1,156 @@
+/*
+ * 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 javax.swing.border;
+
+import java.awt.BasicStroke;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Insets;
+import java.awt.Paint;
+import java.awt.RenderingHints;
+import java.awt.geom.Rectangle2D;
+import java.beans.ConstructorProperties;
+
+/**
+ * A class which implements a border of an arbitrary stroke.
+ * java.beans package.
+ * Please see {@link java.beans.XMLEncoder}.
+ *
+ * @author Sergey A. Malenkov
+ *
+ * @since 1.7
+ */
+public class StrokeBorder extends AbstractBorder {
+ private final BasicStroke stroke;
+ private final Paint paint;
+
+ /**
+ * Creates a border of the specified {@code stroke}.
+ * The component's foreground color will be used to render the border.
+ *
+ * @param stroke the {@link BasicStroke} object used to stroke a shape
+ *
+ * @throws NullPointerException if the specified {@code stroke} is {@code null}
+ */
+ public StrokeBorder(BasicStroke stroke) {
+ this(stroke, null);
+ }
+
+ /**
+ * Creates a border of the specified {@code stroke} and {@code paint}.
+ * If the specified {@code paint} is {@code null},
+ * the component's foreground color will be used to render the border.
+ *
+ * @param stroke the {@link BasicStroke} object used to stroke a shape
+ * @param paint the {@link Paint} object used to generate a color
+ *
+ * @throws NullPointerException if the specified {@code stroke} is {@code null}
+ */
+ @ConstructorProperties({ "stroke", "paint" })
+ public StrokeBorder(BasicStroke stroke, Paint paint) {
+ if (stroke == null) {
+ throw new NullPointerException("border's stroke");
+ }
+ this.stroke = stroke;
+ this.paint = paint;
+ }
+
+ /**
+ * Paints the border for the specified component
+ * with the specified position and size.
+ *
+ * @param c the component for which this border is being painted
+ * @param g the paint graphics
+ * @param x the x position of the painted border
+ * @param y the y position of the painted border
+ * @param width the width of the painted border
+ * @param height the height of the painted border
+ *
+ * @throws NullPointerException if the specified {@code c} or {@code g} are {@code null}
+ */
+ @Override
+ public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
+ float size = this.stroke.getLineWidth();
+ if (size > 0.0f) {
+ g = g.create();
+ if (g instanceof Graphics2D) {
+ Graphics2D g2d = (Graphics2D) g;
+ g2d.setStroke(this.stroke);
+ g2d.setPaint(this.paint != null ? this.paint : c.getForeground());
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON);
+ g2d.draw(new Rectangle2D.Float(x + size / 2, y + size / 2, width - size, height - size));
+ }
+ g.dispose();
+ }
+ }
+
+ /**
+ * Reinitializes the {@code insets} parameter
+ * with this border's current insets.
+ * All insets are equal to the line width of the stroke.
+ *
+ * @param c the component for which this border insets value applies
+ * @param insets the {@code Insets} object to be reinitialized
+ * @return the reinitialized {@code insets} parameter
+ *
+ * @throws NullPointerException if the specified {@code insets} is {@code null}
+ */
+ @Override
+ public Insets getBorderInsets(Component c, Insets insets) {
+ int size = (int) Math.ceil(this.stroke.getLineWidth());
+ insets.set(size, size, size, size);
+ return insets;
+ }
+
+ /**
+ * Returns the {@link BasicStroke} object used to stroke a shape
+ * during the border rendering.
+ *
+ * @return the {@link BasicStroke} object
+ */
+ public BasicStroke getStroke() {
+ return this.stroke;
+ }
+
+ /**
+ * Returns the {@link Paint} object used to generate a color
+ * during the border rendering.
+ *
+ * @return the {@link Paint} object or {@code null}
+ * if the {@code paint} parameter is not set
+ */
+ public Paint getPaint() {
+ return this.paint;
+ }
+}
diff --git a/src/share/classes/javax/swing/plaf/basic/BasicScrollPaneUI.java b/src/share/classes/javax/swing/plaf/basic/BasicScrollPaneUI.java
index 410491b99137a4feb9d7ba55864f37fa72b5be2c..44a512d58362312ec78cef2fecc47328bb7a9e1b 100644
--- a/src/share/classes/javax/swing/plaf/basic/BasicScrollPaneUI.java
+++ b/src/share/classes/javax/swing/plaf/basic/BasicScrollPaneUI.java
@@ -362,6 +362,14 @@ public class BasicScrollPaneUI
* @since 1.6
*/
public int getBaseline(JComponent c, int width, int height) {
+ if (c == null) {
+ throw new NullPointerException("Component must be non-null");
+ }
+
+ if (width < 0 || height < 0) {
+ throw new IllegalArgumentException("Width and height must be >= 0");
+ }
+
JViewport viewport = scrollpane.getViewport();
Insets spInsets = scrollpane.getInsets();
int y = spInsets.top;
diff --git a/src/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java b/src/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java
index ea67ac038527198933137e6e127ef410693d0ef2..84a773ab300bdd74c1574616b61588f6fd0429b6 100644
--- a/src/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java
+++ b/src/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java
@@ -115,10 +115,7 @@ public class SynthTabbedPaneUI extends BasicTabbedPaneUI
return new SynthTabbedPaneUI();
}
- private SynthTabbedPaneUI() {
- }
-
- private boolean scrollableTabLayoutEnabled() {
+ private boolean scrollableTabLayoutEnabled() {
return (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT);
}
diff --git a/src/share/classes/javax/swing/table/DefaultTableCellRenderer.java b/src/share/classes/javax/swing/table/DefaultTableCellRenderer.java
index 83c689f5117839bbde1f4da76d5e695d61d0b174..c87f865562cd13336dba2f1c3d1b1b043b40bde9 100644
--- a/src/share/classes/javax/swing/table/DefaultTableCellRenderer.java
+++ b/src/share/classes/javax/swing/table/DefaultTableCellRenderer.java
@@ -186,6 +186,9 @@ public class DefaultTableCellRenderer extends JLabel
*/
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
+ if (table == null) {
+ return this;
+ }
Color fg = null;
Color bg = null;
diff --git a/src/share/classes/javax/swing/text/DefaultCaret.java b/src/share/classes/javax/swing/text/DefaultCaret.java
index bba42d258e9118d2d4080eec3a814af0d9156b7c..3f148812821b725c39726e232b9cefd220653146 100644
--- a/src/share/classes/javax/swing/text/DefaultCaret.java
+++ b/src/share/classes/javax/swing/text/DefaultCaret.java
@@ -1334,13 +1334,13 @@ public class DefaultCaret extends Rectangle implements Caret, FocusListener, Mou
&& component.getClientProperty("JPasswordField.cutCopyAllowed") !=
Boolean.TRUE) {
//fix for 4793761
- StringBuffer txt = null;
+ StringBuilder txt = null;
char echoChar = ((JPasswordField)component).getEchoChar();
int p0 = Math.min(getDot(), getMark());
int p1 = Math.max(getDot(), getMark());
for (int i = p0; i < p1; i++) {
if (txt == null) {
- txt = new StringBuffer();
+ txt = new StringBuilder();
}
txt.append(echoChar);
}
@@ -1675,7 +1675,6 @@ public class DefaultCaret extends Rectangle implements Caret, FocusListener, Mou
}
return;
}
- int adjust = 0;
int offset = e.getOffset();
int length = e.getLength();
int newDot = dot;
@@ -1759,7 +1758,6 @@ public class DefaultCaret extends Rectangle implements Caret, FocusListener, Mou
}
int offs0 = e.getOffset();
int offs1 = offs0 + e.getLength();
- int adjust = 0;
int newDot = dot;
boolean adjustDotBias = false;
int newMark = mark;
diff --git a/src/share/classes/javax/swing/text/DefaultStyledDocument.java b/src/share/classes/javax/swing/text/DefaultStyledDocument.java
index 938fd84f2b7cb21d7625a25e69175865d11d9a15..e2413038f169db9850fe45d3ed18e1aa25f53978 100644
--- a/src/share/classes/javax/swing/text/DefaultStyledDocument.java
+++ b/src/share/classes/javax/swing/text/DefaultStyledDocument.java
@@ -132,7 +132,7 @@ public class DefaultStyledDocument extends AbstractDocument implements StyledDoc
// install the content
Content c = getContent();
int n = data.length;
- StringBuffer sb = new StringBuffer();
+ StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
ElementSpec es = data[i];
if (es.getLength() > 0) {
@@ -191,7 +191,7 @@ public class DefaultStyledDocument extends AbstractDocument implements StyledDoc
// install the content
Content c = getContent();
int n = data.length;
- StringBuffer sb = new StringBuffer();
+ StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++) {
ElementSpec es = data[i];
if (es.getLength() > 0) {
diff --git a/src/share/classes/javax/swing/text/InternationalFormatter.java b/src/share/classes/javax/swing/text/InternationalFormatter.java
index b49fed2e3ce54b0298c2fa0f9de2954935579b8c..a8ba2206fd19c11989edb90327524ebbcd2cc2cc 100644
--- a/src/share/classes/javax/swing/text/InternationalFormatter.java
+++ b/src/share/classes/javax/swing/text/InternationalFormatter.java
@@ -30,7 +30,6 @@ import java.text.*;
import java.text.AttributedCharacterIterator.Attribute;
import java.util.*;
import javax.swing.*;
-import javax.swing.text.*;
/**
* InternationalFormatter extends DefaultFormatter,
@@ -875,7 +874,6 @@ public class InternationalFormatter extends DefaultFormatter {
(f instanceof AttributedCharacterIterator.Attribute)) {
AttributedCharacterIterator.Attribute field =
(AttributedCharacterIterator.Attribute)f;
- int index = 0;
iterator.first();
while (iterator.getIndex() < start) {
diff --git a/src/share/classes/javax/swing/text/JTextComponent.java b/src/share/classes/javax/swing/text/JTextComponent.java
index f5450903b6a81eaa0f99d2e66c9905f37414dc0e..d00fffef0ac4982cb912f8855c3258e93535fd6f 100644
--- a/src/share/classes/javax/swing/text/JTextComponent.java
+++ b/src/share/classes/javax/swing/text/JTextComponent.java
@@ -35,10 +35,7 @@ import java.util.HashMap;
import java.util.Hashtable;
import java.util.Enumeration;
import java.util.Vector;
-import java.util.Iterator;
import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
import java.util.concurrent.*;
@@ -4058,7 +4055,7 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A
private static final Object KEYMAP_TABLE =
new StringBuilder("JTextComponent_KeymapTable");
- private JTextComponent editor;
+
//
// member variables used for on-the-spot input method
// editing style support
@@ -4748,14 +4745,14 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A
processKeyEvent(ke);
}
} else {
- StringBuffer strBuf = new StringBuffer();
+ StringBuilder strBuf = new StringBuilder();
for (char c = text.current(); commitCount > 0;
c = text.next(), commitCount--) {
strBuf.append(c);
}
// map it to an ActionEvent
- mapCommittedTextToAction(new String(strBuf));
+ mapCommittedTextToAction(strBuf.toString());
}
// Remember latest committed text end index
@@ -4801,7 +4798,7 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A
private void createComposedTextAttribute(int composedIndex,
AttributedCharacterIterator text) {
Document doc = getDocument();
- StringBuffer strBuf = new StringBuffer();
+ StringBuilder strBuf = new StringBuilder();
// create attributed string with no attributes
for (char c = text.setIndex(composedIndex);
@@ -4809,7 +4806,7 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A
strBuf.append(c);
}
- composedTextContent = new String(strBuf);
+ composedTextContent = strBuf.toString();
composedTextAttribute = new SimpleAttributeSet();
composedTextAttribute.addAttribute(StyleConstants.ComposedTextAttribute,
new AttributedString(text, composedIndex, text.getEndIndex()));
diff --git a/src/share/classes/javax/swing/text/MaskFormatter.java b/src/share/classes/javax/swing/text/MaskFormatter.java
index b8bd70b49490c3843df1df18ab95d209cd203fef..b3ad721cf84817ca9a6c07e854d44987b1596afe 100644
--- a/src/share/classes/javax/swing/text/MaskFormatter.java
+++ b/src/share/classes/javax/swing/text/MaskFormatter.java
@@ -29,7 +29,6 @@ import java.io.*;
import java.text.*;
import java.util.*;
import javax.swing.*;
-import javax.swing.text.*;
/**
* MaskFormatter is used to format and edit strings. The behavior
@@ -385,7 +384,7 @@ public class MaskFormatter extends DefaultFormatter {
*/
public String valueToString(Object value) throws ParseException {
String sValue = (value == null) ? "" : value.toString();
- StringBuffer result = new StringBuffer();
+ StringBuilder result = new StringBuilder();
String placeholder = getPlaceholder();
int[] valueCounter = { 0 };
@@ -484,7 +483,7 @@ public class MaskFormatter extends DefaultFormatter {
* Invokes append on the mask characters in
* mask.
*/
- private void append(StringBuffer result, String value, int[] index,
+ private void append(StringBuilder result, String value, int[] index,
String placeholder, MaskCharacter[] mask)
throws ParseException {
for (int counter = 0, maxCounter = mask.length;
@@ -611,13 +610,13 @@ public class MaskFormatter extends DefaultFormatter {
* Removes the literal characters from the passed in string.
*/
private String stripLiteralChars(String string) {
- StringBuffer sb = null;
+ StringBuilder sb = null;
int last = 0;
for (int counter = 0, max = string.length(); counter < max; counter++){
if (isLiteral(counter)) {
if (sb == null) {
- sb = new StringBuffer();
+ sb = new StringBuilder();
if (counter > 0) {
sb.append(string.substring(0, counter));
}
@@ -715,10 +714,10 @@ public class MaskFormatter extends DefaultFormatter {
*/
boolean canReplace(ReplaceHolder rh) {
// This method is rather long, but much of the burden is in
- // maintaining a String and swapping to a StringBuffer only if
+ // maintaining a String and swapping to a StringBuilder only if
// absolutely necessary.
if (!getAllowsInvalid()) {
- StringBuffer replace = null;
+ StringBuilder replace = null;
String text = rh.text;
int tl = (text != null) ? text.length() : 0;
@@ -737,7 +736,7 @@ public class MaskFormatter extends DefaultFormatter {
char aChar = text.charAt(textIndex);
if (aChar != getCharacter(rh.offset + counter, aChar)) {
if (replace == null) {
- replace = new StringBuffer();
+ replace = new StringBuilder();
if (textIndex > 0) {
replace.append(text.substring(0, textIndex));
}
@@ -758,7 +757,7 @@ public class MaskFormatter extends DefaultFormatter {
}
}
else if (textIndex > 0) {
- replace = new StringBuffer(max);
+ replace = new StringBuilder(max);
replace.append(text.substring(0, textIndex));
replace.append(getLiteral(rh.offset + counter));
if (textIndex < tl) {
@@ -780,7 +779,7 @@ public class MaskFormatter extends DefaultFormatter {
else if (textIndex >= tl) {
// placeholder
if (replace == null) {
- replace = new StringBuffer();
+ replace = new StringBuilder();
if (text != null) {
replace.append(text);
}
@@ -863,7 +862,7 @@ public class MaskFormatter extends DefaultFormatter {
* Appends the necessary character in formatting at
* index to buff.
*/
- public void append(StringBuffer buff, String formatting, int[] index,
+ public void append(StringBuilder buff, String formatting, int[] index,
String placeholder)
throws ParseException {
boolean inString = index[0] < formatting.length();
diff --git a/src/share/classes/javax/swing/text/NumberFormatter.java b/src/share/classes/javax/swing/text/NumberFormatter.java
index 9a83c836234a31a74991f5d8100aee8f7f5e3238..2787b036b8a7cb6af5f8add5e37cebeb8ed0e4f5 100644
--- a/src/share/classes/javax/swing/text/NumberFormatter.java
+++ b/src/share/classes/javax/swing/text/NumberFormatter.java
@@ -27,7 +27,6 @@ package javax.swing.text;
import java.lang.reflect.*;
import java.text.*;
import java.util.*;
-import javax.swing.text.*;
/**
* NumberFormatter subclasses InternationalFormatter
@@ -132,7 +131,7 @@ public class NumberFormatter extends InternationalFormatter {
DecimalFormatSymbols dfs = getDecimalFormatSymbols();
if (dfs != null) {
- StringBuffer sb = new StringBuffer();
+ StringBuilder sb = new StringBuilder();
sb.append(dfs.getCurrencySymbol());
sb.append(dfs.getDecimalSeparator());
@@ -239,13 +238,6 @@ public class NumberFormatter extends InternationalFormatter {
return null;
}
- /**
- */
- private boolean isValidInsertionCharacter(char aChar) {
- return (Character.isDigit(aChar) || specialChars.indexOf(aChar) != -1);
- }
-
-
/**
* Subclassed to return false if text contains in an invalid
* character to insert, that is, it is not a digit
@@ -402,28 +394,6 @@ public class NumberFormatter extends InternationalFormatter {
return false;
}
- /**
- * Returns true if the range offset to length identifies the only
- * integer field.
- */
- private boolean isOnlyIntegerField(int offset, int length) {
- if (isValidMask()) {
- int start = getAttributeStart(NumberFormat.Field.INTEGER);
-
- if (start != -1) {
- AttributedCharacterIterator iterator = getIterator();
-
- iterator.setIndex(start);
- if (offset > start || iterator.getRunLimit(
- NumberFormat.Field.INTEGER) > (offset + length)) {
- return false;
- }
- return true;
- }
- }
- return false;
- }
-
/**
* Invoked to toggle the sign. For this to work the value class
* must have a single arg constructor that takes a String.
diff --git a/src/share/classes/javax/swing/text/PlainDocument.java b/src/share/classes/javax/swing/text/PlainDocument.java
index 2698cef3067df6e9674cf8d2213ef0af3e356176..f75a06faa0ef9ee8eedb4c54081031a447c6c7b6 100644
--- a/src/share/classes/javax/swing/text/PlainDocument.java
+++ b/src/share/classes/javax/swing/text/PlainDocument.java
@@ -25,7 +25,6 @@
package javax.swing.text;
import java.util.Vector;
-import javax.swing.event.*;
/**
* A plain document that maintains no character attributes. The
@@ -118,7 +117,7 @@ public class PlainDocument extends AbstractDocument {
Object filterNewlines = getProperty("filterNewlines");
if ((filterNewlines instanceof Boolean) && filterNewlines.equals(Boolean.TRUE)) {
if ((str != null) && (str.indexOf('\n') >= 0)) {
- StringBuffer filtered = new StringBuffer(str);
+ StringBuilder filtered = new StringBuilder(str);
int n = filtered.length();
for (int i = 0; i < n; i++) {
if (filtered.charAt(i) == '\n') {
@@ -204,11 +203,9 @@ public class PlainDocument extends AbstractDocument {
}
}
if (hasBreaks) {
- int rmCount = 1;
removed.addElement(rmCandidate);
if ((offset + length == rmOffs1) && (lastOffset != rmOffs1) &&
((index+1) < lineMap.getElementCount())) {
- rmCount += 1;
Element e = lineMap.getElement(index+1);
removed.addElement(e);
rmOffs1 = e.getEndOffset();
diff --git a/src/share/classes/javax/swing/text/TabSet.java b/src/share/classes/javax/swing/text/TabSet.java
index 986b9bcb320f3538c4c4546b7e1f8b1236e14f8e..a4d433facbb7c22ccb377c751217075eb0a5498f 100644
--- a/src/share/classes/javax/swing/text/TabSet.java
+++ b/src/share/classes/javax/swing/text/TabSet.java
@@ -199,7 +199,7 @@ public class TabSet implements Serializable
*/
public String toString() {
int tabCount = getTabCount();
- StringBuffer buffer = new StringBuffer("[ ");
+ StringBuilder buffer = new StringBuilder("[ ");
for(int counter = 0; counter < tabCount; counter++) {
if(counter > 0)
diff --git a/src/share/classes/javax/swing/text/html/FormView.java b/src/share/classes/javax/swing/text/html/FormView.java
index 1aeb7e17ec37f38666eeedca2d232964f3a0a0b2..903ef88ec8d0ac2627685da84c78d9bac3fa8f33 100644
--- a/src/share/classes/javax/swing/text/html/FormView.java
+++ b/src/share/classes/javax/swing/text/html/FormView.java
@@ -362,7 +362,7 @@ public class FormView extends ComponentView implements ActionListener {
*/
public void actionPerformed(ActionEvent evt) {
Element element = getElement();
- StringBuffer dataBuffer = new StringBuffer();
+ StringBuilder dataBuffer = new StringBuilder();
HTMLDocument doc = (HTMLDocument)getDocument();
AttributeSet attr = element.getAttributes();
@@ -508,7 +508,7 @@ public class FormView extends ComponentView implements ActionListener {
*/
protected void imageSubmit(String imageData) {
- StringBuffer dataBuffer = new StringBuffer();
+ StringBuilder dataBuffer = new StringBuilder();
Element elem = getElement();
HTMLDocument hdoc = (HTMLDocument)elem.getDocument();
getFormData(dataBuffer);
@@ -589,7 +589,7 @@ public class FormView extends ComponentView implements ActionListener {
* @param targetElement the element that triggered the
* form submission
*/
- void getFormData(StringBuffer buffer) {
+ private void getFormData(StringBuilder buffer) {
Element formE = getFormElement();
if (formE != null) {
ElementIterator it = new ElementIterator(formE);
@@ -623,7 +623,7 @@ public class FormView extends ComponentView implements ActionListener {
* data is loaded in name/value pairs.
*
*/
- private void loadElementDataIntoBuffer(Element elem, StringBuffer buffer) {
+ private void loadElementDataIntoBuffer(Element elem, StringBuilder buffer) {
AttributeSet attr = elem.getAttributes();
String name = (String)attr.getAttribute(HTML.Attribute.NAME);
@@ -692,29 +692,6 @@ public class FormView extends ComponentView implements ActionListener {
}
if (path != null && path.length() > 0) {
value = path;
-/*
-
- try {
- Reader reader = new BufferedReader(new FileReader(path));
- StringBuffer buffer = new StringBuffer();
- char[] cBuff = new char[1024];
- int read;
-
- try {
- while ((read = reader.read(cBuff)) != -1) {
- buffer.append(cBuff, 0, read);
- }
- } catch (IOException ioe) {
- buffer = null;
- }
- try {
- reader.close();
- } catch (IOException ioe) {}
- if (buffer != null) {
- value = buffer.toString();
- }
- } catch (IOException ioe) {}
-*/
}
}
return value;
@@ -740,7 +717,7 @@ public class FormView extends ComponentView implements ActionListener {
* form element. Basically, only items that are selected
* and have their name attribute set are added to the buffer.
*/
- private void loadSelectData(AttributeSet attr, StringBuffer buffer) {
+ private void loadSelectData(AttributeSet attr, StringBuilder buffer) {
String name = (String)attr.getAttribute(HTML.Attribute.NAME);
if (name == null) {
@@ -771,7 +748,7 @@ public class FormView extends ComponentView implements ActionListener {
* URLEncoder.encode() method before being added to the
* buffer.
*/
- private void appendBuffer(StringBuffer buffer, String name, String value) {
+ private void appendBuffer(StringBuilder buffer, String name, String value) {
if (buffer.length() > 0) {
buffer.append('&');
}
diff --git a/src/share/classes/javax/swing/text/html/MinimalHTMLWriter.java b/src/share/classes/javax/swing/text/html/MinimalHTMLWriter.java
index 26bcaa30fbaac4f923ed2d5d2ae8fa1005ffe2d1..fd7bc85936cc44fb14060614a419526f1211d8f6 100644
--- a/src/share/classes/javax/swing/text/html/MinimalHTMLWriter.java
+++ b/src/share/classes/javax/swing/text/html/MinimalHTMLWriter.java
@@ -691,11 +691,11 @@ public class MinimalHTMLWriter extends AbstractWriter {
if (styleNameMapping == null) {
return style;
}
- StringBuffer sb = null;
+ StringBuilder sb = null;
for (int counter = style.length() - 1; counter >= 0; counter--) {
if (!isValidCharacter(style.charAt(counter))) {
if (sb == null) {
- sb = new StringBuffer(style);
+ sb = new StringBuilder(style);
}
sb.setCharAt(counter, 'a');
}
diff --git a/src/share/classes/javax/swing/text/html/StyleSheet.java b/src/share/classes/javax/swing/text/html/StyleSheet.java
index 47eeefe2c7d2351c4934db8017150b8f2f34954c..642e57aa06a5203c6ae0381c8d722e3ae4b87062 100644
--- a/src/share/classes/javax/swing/text/html/StyleSheet.java
+++ b/src/share/classes/javax/swing/text/html/StyleSheet.java
@@ -998,7 +998,7 @@ public class StyleSheet extends StyleContext {
void addRule(String[] selector, AttributeSet declaration,
boolean isLinked) {
int n = selector.length;
- StringBuffer sb = new StringBuffer();
+ StringBuilder sb = new StringBuilder();
sb.append(selector[0]);
for (int counter = 1; counter < n; counter++) {
sb.append(' ');
diff --git a/src/share/classes/javax/swing/text/html/parser/Parser.java b/src/share/classes/javax/swing/text/html/parser/Parser.java
index abcb05adbc128e7fc79e68d10e5e5bc3016ab36b..78cb30165c4baab2ae46fc692646663776a8bf93 100644
--- a/src/share/classes/javax/swing/text/html/parser/Parser.java
+++ b/src/share/classes/javax/swing/text/html/parser/Parser.java
@@ -1470,7 +1470,7 @@ class Parser implements DTDConstants {
*/
public String parseDTDMarkup() throws IOException {
- StringBuffer strBuff = new StringBuffer();
+ StringBuilder strBuff = new StringBuilder();
ch = readCh();
while(true) {
switch (ch) {
diff --git a/src/share/classes/javax/swing/text/rtf/AbstractFilter.java b/src/share/classes/javax/swing/text/rtf/AbstractFilter.java
index cdbec2a816dfa3574700384e3597b2db8963d6f4..aaffbb6092048c53faa63cd25c72d25402c40293 100644
--- a/src/share/classes/javax/swing/text/rtf/AbstractFilter.java
+++ b/src/share/classes/javax/swing/text/rtf/AbstractFilter.java
@@ -160,7 +160,7 @@ abstract class AbstractFilter extends OutputStream
public void write(byte[] buf, int off, int len)
throws IOException
{
- StringBuffer accumulator = null;
+ StringBuilder accumulator = null;
while (len > 0) {
short b = (short)buf[off];
@@ -178,7 +178,7 @@ abstract class AbstractFilter extends OutputStream
char ch = translationTable[b];
if (ch != (char)0) {
if (accumulator == null)
- accumulator = new StringBuffer();
+ accumulator = new StringBuilder();
accumulator.append(ch);
}
}
diff --git a/src/share/classes/sun/java2d/pisces/Curve.java b/src/share/classes/sun/java2d/pisces/Curve.java
new file mode 100644
index 0000000000000000000000000000000000000000..f8beae69fd35f9e189bdff7826bb4260b50fb9c8
--- /dev/null
+++ b/src/share/classes/sun/java2d/pisces/Curve.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. 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.pisces;
+
+import java.util.Iterator;
+
+class Curve {
+
+ float ax, ay, bx, by, cx, cy, dx, dy;
+ float dax, day, dbx, dby;
+
+ Curve() {
+ }
+
+ void set(float[] points, int type) {
+ switch(type) {
+ case 8:
+ set(points[0], points[1],
+ points[2], points[3],
+ points[4], points[5],
+ points[6], points[7]);
+ break;
+ case 6:
+ set(points[0], points[1],
+ points[2], points[3],
+ points[4], points[5]);
+ break;
+ default:
+ throw new InternalError("Curves can only be cubic or quadratic");
+ }
+ }
+
+ void set(float x1, float y1,
+ float x2, float y2,
+ float x3, float y3,
+ float x4, float y4)
+ {
+ ax = 3 * (x2 - x3) + x4 - x1;
+ ay = 3 * (y2 - y3) + y4 - y1;
+ bx = 3 * (x1 - 2 * x2 + x3);
+ by = 3 * (y1 - 2 * y2 + y3);
+ cx = 3 * (x2 - x1);
+ cy = 3 * (y2 - y1);
+ dx = x1;
+ dy = y1;
+ dax = 3 * ax; day = 3 * ay;
+ dbx = 2 * bx; dby = 2 * by;
+ }
+
+ void set(float x1, float y1,
+ float x2, float y2,
+ float x3, float y3)
+ {
+ ax = ay = 0f;
+
+ bx = x1 - 2 * x2 + x3;
+ by = y1 - 2 * y2 + y3;
+ cx = 2 * (x2 - x1);
+ cy = 2 * (y2 - y1);
+ dx = x1;
+ dy = y1;
+ dax = 0; day = 0;
+ dbx = 2 * bx; dby = 2 * by;
+ }
+
+ float xat(float t) {
+ return t * (t * (t * ax + bx) + cx) + dx;
+ }
+ float yat(float t) {
+ return t * (t * (t * ay + by) + cy) + dy;
+ }
+
+ float dxat(float t) {
+ return t * (t * dax + dbx) + cx;
+ }
+
+ float dyat(float t) {
+ return t * (t * day + dby) + cy;
+ }
+
+ private float ddxat(float t) {
+ return 2 * dax * t + dbx;
+ }
+
+ private float ddyat(float t) {
+ return 2 * day * t + dby;
+ }
+
+ int dxRoots(float[] roots, int off) {
+ return Helpers.quadraticRoots(dax, dbx, cx, roots, off);
+ }
+
+ int dyRoots(float[] roots, int off) {
+ return Helpers.quadraticRoots(day, dby, cy, roots, off);
+ }
+
+ int infPoints(float[] pts, int off) {
+ // inflection point at t if -f'(t)x*f''(t)y + f'(t)y*f''(t)x == 0
+ // Fortunately, this turns out to be quadratic, so there are at
+ // most 2 inflection points.
+ final float a = dax * dby - dbx * day;
+ final float b = 2 * (cy * dax - day * cx);
+ final float c = cy * dbx - cx * dby;
+
+ return Helpers.quadraticRoots(a, b, c, pts, off);
+ }
+
+ // finds points where the first and second derivative are
+ // perpendicular. This happens when g(t) = f'(t)*f''(t) == 0 (where
+ // * is a dot product). Unfortunately, we have to solve a cubic.
+ private int perpendiculardfddf(float[] pts, int off, final float err) {
+ assert pts.length >= off + 4;
+
+ // these are the coefficients of g(t):
+ final float a = 2*(dax*dax + day*day);
+ final float b = 3*(dax*dbx + day*dby);
+ final float c = 2*(dax*cx + day*cy) + dbx*dbx + dby*dby;
+ final float d = dbx*cx + dby*cy;
+ // TODO: We might want to divide the polynomial by a to make the
+ // coefficients smaller. This won't change the roots.
+ return Helpers.cubicRootsInAB(a, b, c, d, pts, off, err, 0f, 1f);
+ }
+
+ // Tries to find the roots of the function ROC(t)-w in [0, 1). It uses
+ // a variant of the false position algorithm to find the roots. False
+ // position requires that 2 initial values x0,x1 be given, and that the
+ // function must have opposite signs at those values. To find such
+ // values, we need the local extrema of the ROC function, for which we
+ // need the roots of its derivative; however, it's harder to find the
+ // roots of the derivative in this case than it is to find the roots
+ // of the original function. So, we find all points where this curve's
+ // first and second derivative are perpendicular, and we pretend these
+ // are our local extrema. There are at most 3 of these, so we will check
+ // at most 4 sub-intervals of (0,1). ROC has asymptotes at inflection
+ // points, so roc-w can have at least 6 roots. This shouldn't be a
+ // problem for what we're trying to do (draw a nice looking curve).
+ int rootsOfROCMinusW(float[] roots, int off, final float w, final float err) {
+ // no OOB exception, because by now off<=6, and roots.length >= 10
+ assert off <= 6 && roots.length >= 10;
+ int ret = off;
+ int numPerpdfddf = perpendiculardfddf(roots, off, err);
+ float t0 = 0, ft0 = ROCsq(t0) - w*w;
+ roots[off + numPerpdfddf] = 1f; // always check interval end points
+ numPerpdfddf++;
+ for (int i = off; i < off + numPerpdfddf; i++) {
+ float t1 = roots[i], ft1 = ROCsq(t1) - w*w;
+ if (ft0 == 0f) {
+ roots[ret++] = t0;
+ } else if (ft1 * ft0 < 0f) { // have opposite signs
+ // (ROC(t)^2 == w^2) == (ROC(t) == w) is true because
+ // ROC(t) >= 0 for all t.
+ roots[ret++] = falsePositionROCsqMinusX(t0, t1, w*w, err);
+ }
+ t0 = t1;
+ ft0 = ft1;
+ }
+
+ return ret - off;
+ }
+
+ private static float eliminateInf(float x) {
+ return (x == Float.POSITIVE_INFINITY ? Float.MAX_VALUE :
+ (x == Float.NEGATIVE_INFINITY ? Float.MIN_VALUE : x));
+ }
+
+ // A slight modification of the false position algorithm on wikipedia.
+ // This only works for the ROCsq-x functions. It might be nice to have
+ // the function as an argument, but that would be awkward in java6.
+ // It is something to consider for java7, depending on how closures
+ // and function objects turn out. Same goes for the newton's method
+ // algorithm in Helpers.java
+ private float falsePositionROCsqMinusX(float x0, float x1,
+ final float x, final float err)
+ {
+ final int iterLimit = 100;
+ int side = 0;
+ float t = x1, ft = eliminateInf(ROCsq(t) - x);
+ float s = x0, fs = eliminateInf(ROCsq(s) - x);
+ float r = s, fr;
+ for (int i = 0; i < iterLimit && Math.abs(t - s) > err * Math.abs(t + s); i++) {
+ r = (fs * t - ft * s) / (fs - ft);
+ fr = ROCsq(r) - x;
+ if (fr * ft > 0) {// have the same sign
+ ft = fr; t = r;
+ if (side < 0) {
+ fs /= (1 << (-side));
+ side--;
+ } else {
+ side = -1;
+ }
+ } else if (fr * fs > 0) {
+ fs = fr; s = r;
+ if (side > 0) {
+ ft /= (1 << side);
+ side++;
+ } else {
+ side = 1;
+ }
+ } else {
+ break;
+ }
+ }
+ return r;
+ }
+
+ // returns the radius of curvature squared at t of this curve
+ // see http://en.wikipedia.org/wiki/Radius_of_curvature_(applications)
+ private float ROCsq(final float t) {
+ final float dx = dxat(t);
+ final float dy = dyat(t);
+ final float ddx = ddxat(t);
+ final float ddy = ddyat(t);
+ final float dx2dy2 = dx*dx + dy*dy;
+ final float ddx2ddy2 = ddx*ddx + ddy*ddy;
+ final float ddxdxddydy = ddx*dx + ddy*dy;
+ float ret = ((dx2dy2*dx2dy2) / (dx2dy2 * ddx2ddy2 - ddxdxddydy*ddxdxddydy))*dx2dy2;
+ return ret;
+ }
+
+ // curve to be broken should be in pts[0]
+ // this will change the contents of both pts and Ts
+ // TODO: There's no reason for Ts to be an array. All we need is a sequence
+ // of t values at which to subdivide. An array statisfies this condition,
+ // but is unnecessarily restrictive. Ts should be an IteratorDasher class takes a series of linear commands
* (moveTo, lineTo, close and
@@ -36,18 +38,16 @@ package sun.java2d.pisces;
* semantics are unclear.
*
*/
-public class Dasher implements LineSink {
- private final LineSink output;
+public class Dasher implements sun.awt.geom.PathConsumer2D {
+
+ private final PathConsumer2D out;
private final float[] dash;
private final float startPhase;
private final boolean startDashOn;
private final int startIdx;
- private final float m00, m10, m01, m11;
- private final float det;
-
- private boolean firstDashOn;
private boolean starting;
+ private boolean needsMoveTo;
private int idx;
private boolean dashOn;
@@ -55,28 +55,23 @@ public class Dasher implements LineSink {
private float sx, sy;
private float x0, y0;
- private float sx1, sy1;
+ // temporary storage for the current curve
+ private float[] curCurvepts;
/**
* Constructs a Dasher.
*
- * @param output an output LineSink.
- * @param dash an array of ints containing the dash pattern
- * @param phase an int containing the dash phase
- * @param transform a Transform4 object indicating
- * the transform that has been previously applied to all incoming
- * coordinates. This is required in order to compute dash lengths
- * properly.
+ * @param out an output PathConsumer2D.
+ * @param dash an array of floats containing the dash pattern
+ * @param phase a float containing the dash phase
*/
- public Dasher(LineSink output,
- float[] dash, float phase,
- float a00, float a01, float a10, float a11) {
+ public Dasher(PathConsumer2D out, float[] dash, float phase) {
if (phase < 0) {
throw new IllegalArgumentException("phase < 0 !");
}
- this.output = output;
+ this.out = out;
// Normalize so 0 <= phase < dash[0]
int idx = 0;
@@ -92,16 +87,19 @@ public class Dasher implements LineSink {
this.startPhase = this.phase = phase;
this.startDashOn = dashOn;
this.startIdx = idx;
+ this.starting = true;
- m00 = a00;
- m01 = a01;
- m10 = a10;
- m11 = a11;
- det = m00 * m11 - m01 * m10;
+ // we need curCurvepts to be able to contain 2 curves because when
+ // dashing curves, we need to subdivide it
+ curCurvepts = new float[8 * 2];
}
public void moveTo(float x0, float y0) {
- output.moveTo(x0, y0);
+ if (firstSegidx > 0) {
+ out.moveTo(sx, sy);
+ emitFirstSegments();
+ }
+ needsMoveTo = true;
this.idx = startIdx;
this.dashOn = this.startDashOn;
this.phase = this.startPhase;
@@ -110,104 +108,398 @@ public class Dasher implements LineSink {
this.starting = true;
}
- public void lineJoin() {
- output.lineJoin();
+ private void emitSeg(float[] buf, int off, int type) {
+ switch (type) {
+ case 8:
+ out.curveTo(buf[off+0], buf[off+1],
+ buf[off+2], buf[off+3],
+ buf[off+4], buf[off+5]);
+ break;
+ case 6:
+ out.quadTo(buf[off+0], buf[off+1],
+ buf[off+2], buf[off+3]);
+ break;
+ case 4:
+ out.lineTo(buf[off], buf[off+1]);
+ }
+ }
+
+ private void emitFirstSegments() {
+ for (int i = 0; i < firstSegidx; ) {
+ emitSeg(firstSegmentsBuffer, i+1, (int)firstSegmentsBuffer[i]);
+ i += (((int)firstSegmentsBuffer[i]) - 1);
+ }
+ firstSegidx = 0;
}
- private void goTo(float x1, float y1) {
+ // We don't emit the first dash right away. If we did, caps would be
+ // drawn on it, but we need joins to be drawn if there's a closePath()
+ // So, we store the path elements that make up the first dash in the
+ // buffer below.
+ private float[] firstSegmentsBuffer = new float[7];
+ private int firstSegidx = 0;
+ // precondition: pts must be in relative coordinates (relative to x0,y0)
+ // fullCurve is true iff the curve in pts has not been split.
+ private void goTo(float[] pts, int off, final int type) {
+ float x = pts[off + type - 4];
+ float y = pts[off + type - 3];
if (dashOn) {
if (starting) {
- this.sx1 = x1;
- this.sy1 = y1;
- firstDashOn = true;
- starting = false;
+ firstSegmentsBuffer = Helpers.widenArray(firstSegmentsBuffer,
+ firstSegidx, type - 2);
+ firstSegmentsBuffer[firstSegidx++] = type;
+ System.arraycopy(pts, off, firstSegmentsBuffer, firstSegidx, type - 2);
+ firstSegidx += type - 2;
+ } else {
+ if (needsMoveTo) {
+ out.moveTo(x0, y0);
+ needsMoveTo = false;
+ }
+ emitSeg(pts, off, type);
}
- output.lineTo(x1, y1);
} else {
- if (starting) {
- firstDashOn = false;
- starting = false;
- }
- output.moveTo(x1, y1);
+ starting = false;
+ needsMoveTo = true;
}
- this.x0 = x1;
- this.y0 = y1;
+ this.x0 = x;
+ this.y0 = y;
}
public void lineTo(float x1, float y1) {
- // The widened line is squished to a 0 width one, so no drawing is done
- if (det == 0) {
- goTo(x1, y1);
- return;
- }
float dx = x1 - x0;
float dy = y1 - y0;
+ float len = (float) Math.hypot(dx, dy);
- // Compute segment length in the untransformed
- // coordinate system
-
- float la = (dy*m00 - dx*m10)/det;
- float lb = (dy*m01 - dx*m11)/det;
- float origLen = (float) Math.hypot(la, lb);
-
- if (origLen == 0) {
- // Let the output LineSink deal with cases where dx, dy are 0.
- goTo(x1, y1);
+ if (len == 0) {
return;
}
// The scaling factors needed to get the dx and dy of the
// transformed dash segments.
- float cx = dx / origLen;
- float cy = dy / origLen;
+ float cx = dx / len;
+ float cy = dy / len;
while (true) {
float leftInThisDashSegment = dash[idx] - phase;
- if (origLen < leftInThisDashSegment) {
- goTo(x1, y1);
+ if (len <= leftInThisDashSegment) {
+ curCurvepts[0] = x1;
+ curCurvepts[1] = y1;
+ goTo(curCurvepts, 0, 4);
// Advance phase within current dash segment
- phase += origLen;
- return;
- } else if (origLen == leftInThisDashSegment) {
- goTo(x1, y1);
- phase = 0f;
- idx = (idx + 1) % dash.length;
- dashOn = !dashOn;
+ phase += len;
+ if (len == leftInThisDashSegment) {
+ phase = 0f;
+ idx = (idx + 1) % dash.length;
+ dashOn = !dashOn;
+ }
return;
}
- float dashx, dashy;
float dashdx = dash[idx] * cx;
float dashdy = dash[idx] * cy;
if (phase == 0) {
- dashx = x0 + dashdx;
- dashy = y0 + dashdy;
+ curCurvepts[0] = x0 + dashdx;
+ curCurvepts[1] = y0 + dashdy;
} else {
- float p = (leftInThisDashSegment) / dash[idx];
- dashx = x0 + p * dashdx;
- dashy = y0 + p * dashdy;
+ float p = leftInThisDashSegment / dash[idx];
+ curCurvepts[0] = x0 + p * dashdx;
+ curCurvepts[1] = y0 + p * dashdy;
}
- goTo(dashx, dashy);
+ goTo(curCurvepts, 0, 4);
+
+ len -= leftInThisDashSegment;
+ // Advance to next dash segment
+ idx = (idx + 1) % dash.length;
+ dashOn = !dashOn;
+ phase = 0;
+ }
+ }
+
+ private LengthIterator li = null;
+
+ // preconditions: curCurvepts must be an array of length at least 2 * type,
+ // that contains the curve we want to dash in the first type elements
+ private void somethingTo(int type) {
+ if (pointCurve(curCurvepts, type)) {
+ return;
+ }
+ if (li == null) {
+ li = new LengthIterator(4, 0.0001f);
+ }
+ li.initializeIterationOnCurve(curCurvepts, type);
- origLen -= (dash[idx] - phase);
+ int curCurveoff = 0; // initially the current curve is at curCurvepts[0...type]
+ float lastSplitT = 0;
+ float t = 0;
+ float leftInThisDashSegment = dash[idx] - phase;
+ while ((t = li.next(leftInThisDashSegment)) < 1) {
+ if (t != 0) {
+ Helpers.subdivideAt((t - lastSplitT) / (1 - lastSplitT),
+ curCurvepts, curCurveoff,
+ curCurvepts, 0,
+ curCurvepts, type, type);
+ lastSplitT = t;
+ goTo(curCurvepts, 2, type);
+ curCurveoff = type;
+ }
// Advance to next dash segment
idx = (idx + 1) % dash.length;
dashOn = !dashOn;
phase = 0;
+ leftInThisDashSegment = dash[idx];
+ }
+ goTo(curCurvepts, curCurveoff+2, type);
+ phase += li.lastSegLen();
+ if (phase >= dash[idx]) {
+ phase = 0f;
+ idx = (idx + 1) % dash.length;
+ dashOn = !dashOn;
+ }
+ }
+
+ private static boolean pointCurve(float[] curve, int type) {
+ for (int i = 2; i < type; i++) {
+ if (curve[i] != curve[i-2]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // Objects of this class are used to iterate through curves. They return
+ // t values where the left side of the curve has a specified length.
+ // It does this by subdividing the input curve until a certain error
+ // condition has been met. A recursive subdivision procedure would
+ // return as many as 1<src array at indices srcoff
+ * through (srcoff + 7) and stores the
+ * resulting two subdivided curves into the two result arrays at the
+ * corresponding indices.
+ * Either or both of the left and right
+ * arrays may be null or a reference to the same array
+ * as the src array.
+ * Note that the last point in the first subdivided curve is the
+ * same as the first point in the second subdivided curve. Thus,
+ * it is possible to pass the same array for left
+ * and right and to use offsets, such as rightoff
+ * equals (leftoff + 6), in order
+ * to avoid allocating extra storage for this common point.
+ * @param src the array holding the coordinates for the source curve
+ * @param srcoff the offset into the array of the beginning of the
+ * the 6 source coordinates
+ * @param left the array for storing the coordinates for the first
+ * half of the subdivided curve
+ * @param leftoff the offset into the array of the beginning of the
+ * the 6 left coordinates
+ * @param right the array for storing the coordinates for the second
+ * half of the subdivided curve
+ * @param rightoff the offset into the array of the beginning of the
+ * the 6 right coordinates
+ * @since 1.7
+ */
+ static void subdivideCubic(float src[], int srcoff,
+ float left[], int leftoff,
+ float right[], int rightoff)
+ {
+ float x1 = src[srcoff + 0];
+ float y1 = src[srcoff + 1];
+ float ctrlx1 = src[srcoff + 2];
+ float ctrly1 = src[srcoff + 3];
+ float ctrlx2 = src[srcoff + 4];
+ float ctrly2 = src[srcoff + 5];
+ float x2 = src[srcoff + 6];
+ float y2 = src[srcoff + 7];
+ if (left != null) {
+ left[leftoff + 0] = x1;
+ left[leftoff + 1] = y1;
+ }
+ if (right != null) {
+ right[rightoff + 6] = x2;
+ right[rightoff + 7] = y2;
+ }
+ x1 = (x1 + ctrlx1) / 2.0f;
+ y1 = (y1 + ctrly1) / 2.0f;
+ x2 = (x2 + ctrlx2) / 2.0f;
+ y2 = (y2 + ctrly2) / 2.0f;
+ float centerx = (ctrlx1 + ctrlx2) / 2.0f;
+ float centery = (ctrly1 + ctrly2) / 2.0f;
+ ctrlx1 = (x1 + centerx) / 2.0f;
+ ctrly1 = (y1 + centery) / 2.0f;
+ ctrlx2 = (x2 + centerx) / 2.0f;
+ ctrly2 = (y2 + centery) / 2.0f;
+ centerx = (ctrlx1 + ctrlx2) / 2.0f;
+ centery = (ctrly1 + ctrly2) / 2.0f;
+ if (left != null) {
+ left[leftoff + 2] = x1;
+ left[leftoff + 3] = y1;
+ left[leftoff + 4] = ctrlx1;
+ left[leftoff + 5] = ctrly1;
+ left[leftoff + 6] = centerx;
+ left[leftoff + 7] = centery;
+ }
+ if (right != null) {
+ right[rightoff + 0] = centerx;
+ right[rightoff + 1] = centery;
+ right[rightoff + 2] = ctrlx2;
+ right[rightoff + 3] = ctrly2;
+ right[rightoff + 4] = x2;
+ right[rightoff + 5] = y2;
+ }
+ }
+
+
+ static void subdivideCubicAt(float t, float src[], int srcoff,
+ float left[], int leftoff,
+ float right[], int rightoff)
+ {
+ float x1 = src[srcoff + 0];
+ float y1 = src[srcoff + 1];
+ float ctrlx1 = src[srcoff + 2];
+ float ctrly1 = src[srcoff + 3];
+ float ctrlx2 = src[srcoff + 4];
+ float ctrly2 = src[srcoff + 5];
+ float x2 = src[srcoff + 6];
+ float y2 = src[srcoff + 7];
+ if (left != null) {
+ left[leftoff + 0] = x1;
+ left[leftoff + 1] = y1;
+ }
+ if (right != null) {
+ right[rightoff + 6] = x2;
+ right[rightoff + 7] = y2;
+ }
+ x1 = x1 + t * (ctrlx1 - x1);
+ y1 = y1 + t * (ctrly1 - y1);
+ x2 = ctrlx2 + t * (x2 - ctrlx2);
+ y2 = ctrly2 + t * (y2 - ctrly2);
+ float centerx = ctrlx1 + t * (ctrlx2 - ctrlx1);
+ float centery = ctrly1 + t * (ctrly2 - ctrly1);
+ ctrlx1 = x1 + t * (centerx - x1);
+ ctrly1 = y1 + t * (centery - y1);
+ ctrlx2 = centerx + t * (x2 - centerx);
+ ctrly2 = centery + t * (y2 - centery);
+ centerx = ctrlx1 + t * (ctrlx2 - ctrlx1);
+ centery = ctrly1 + t * (ctrly2 - ctrly1);
+ if (left != null) {
+ left[leftoff + 2] = x1;
+ left[leftoff + 3] = y1;
+ left[leftoff + 4] = ctrlx1;
+ left[leftoff + 5] = ctrly1;
+ left[leftoff + 6] = centerx;
+ left[leftoff + 7] = centery;
+ }
+ if (right != null) {
+ right[rightoff + 0] = centerx;
+ right[rightoff + 1] = centery;
+ right[rightoff + 2] = ctrlx2;
+ right[rightoff + 3] = ctrly2;
+ right[rightoff + 4] = x2;
+ right[rightoff + 5] = y2;
+ }
+ }
+
+ static void subdivideQuad(float src[], int srcoff,
+ float left[], int leftoff,
+ float right[], int rightoff)
+ {
+ float x1 = src[srcoff + 0];
+ float y1 = src[srcoff + 1];
+ float ctrlx = src[srcoff + 2];
+ float ctrly = src[srcoff + 3];
+ float x2 = src[srcoff + 4];
+ float y2 = src[srcoff + 5];
+ if (left != null) {
+ left[leftoff + 0] = x1;
+ left[leftoff + 1] = y1;
+ }
+ if (right != null) {
+ right[rightoff + 4] = x2;
+ right[rightoff + 5] = y2;
+ }
+ x1 = (x1 + ctrlx) / 2.0f;
+ y1 = (y1 + ctrly) / 2.0f;
+ x2 = (x2 + ctrlx) / 2.0f;
+ y2 = (y2 + ctrly) / 2.0f;
+ ctrlx = (x1 + x2) / 2.0f;
+ ctrly = (y1 + y2) / 2.0f;
+ if (left != null) {
+ left[leftoff + 2] = x1;
+ left[leftoff + 3] = y1;
+ left[leftoff + 4] = ctrlx;
+ left[leftoff + 5] = ctrly;
+ }
+ if (right != null) {
+ right[rightoff + 0] = ctrlx;
+ right[rightoff + 1] = ctrly;
+ right[rightoff + 2] = x2;
+ right[rightoff + 3] = y2;
+ }
+ }
+
+ static void subdivideQuadAt(float t, float src[], int srcoff,
+ float left[], int leftoff,
+ float right[], int rightoff)
+ {
+ float x1 = src[srcoff + 0];
+ float y1 = src[srcoff + 1];
+ float ctrlx = src[srcoff + 2];
+ float ctrly = src[srcoff + 3];
+ float x2 = src[srcoff + 4];
+ float y2 = src[srcoff + 5];
+ if (left != null) {
+ left[leftoff + 0] = x1;
+ left[leftoff + 1] = y1;
+ }
+ if (right != null) {
+ right[rightoff + 4] = x2;
+ right[rightoff + 5] = y2;
+ }
+ x1 = x1 + t * (ctrlx - x1);
+ y1 = y1 + t * (ctrly - y1);
+ x2 = ctrlx + t * (x2 - ctrlx);
+ y2 = ctrly + t * (y2 - ctrly);
+ ctrlx = x1 + t * (x2 - x1);
+ ctrly = y1 + t * (y2 - y1);
+ if (left != null) {
+ left[leftoff + 2] = x1;
+ left[leftoff + 3] = y1;
+ left[leftoff + 4] = ctrlx;
+ left[leftoff + 5] = ctrly;
+ }
+ if (right != null) {
+ right[rightoff + 0] = ctrlx;
+ right[rightoff + 1] = ctrly;
+ right[rightoff + 2] = x2;
+ right[rightoff + 3] = y2;
+ }
+ }
+
+ static void subdivideAt(float t, float src[], int srcoff,
+ float left[], int leftoff,
+ float right[], int rightoff, int size)
+ {
+ switch(size) {
+ case 8:
+ subdivideCubicAt(t, src, srcoff, left, leftoff, right, rightoff);
+ break;
+ case 6:
+ subdivideQuadAt(t, src, srcoff, left, leftoff, right, rightoff);
+ break;
+ }
+ }
+}
diff --git a/src/share/classes/sun/java2d/pisces/LineSink.java b/src/share/classes/sun/java2d/pisces/LineSink.java
deleted file mode 100644
index 81300a25fa067cac00c2ba57d66049e62bdd3c0c..0000000000000000000000000000000000000000
--- a/src/share/classes/sun/java2d/pisces/LineSink.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. 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.pisces;
-
-/**
- * The LineSink interface accepts a series of line
- * drawing commands: moveTo, lineTo,
- * close (equivalent to a lineTo command
- * with an argument equal to the argument of the last
- * moveTo command), and end.
- *
- * Flattener may be used to connect a general path
- * source to a LineSink.
- *
- * Renderer class implements the
- * LineSink interface.
- *
- */
-public interface LineSink {
-
- /**
- * Moves the current drawing position to the point (x0,
- * y0).
- *
- * @param x0 the X coordinate
- * @param y0 the Y coordinate
- */
- public void moveTo(float x0, float y0);
-
- /**
- * Provides a hint that the current segment should be joined to
- * the following segment using an explicit miter or round join if
- * required.
- *
- * Flattener to mark segment divisions that
- * appear in its input, and consumed by a Stroker
- * that is responsible for emitting the miter or round join
- * segments.
- *
- * LineSink classes should simply pass this
- * hint to their output sink as needed.
- */
- public void lineJoin();
-
- /**
- * Draws a line from the current drawing position to the point
- * (x1, y1) and sets the current drawing position to
- * (x1, y1).
- *
- * @param x1 the X coordinate
- * @param y1 the Y coordinate
- */
- public void lineTo(float x1, float y1);
-
- /**
- * Closes the current path by drawing a line from the current
- * drawing position to the point specified by the moset recent
- * moveTo command.
- */
- public void close();
-
- /**
- * Ends the current path. It may be necessary to end a path in
- * order to allow end caps to be drawn.
- */
- public void end();
-
-}
diff --git a/src/share/classes/sun/java2d/pisces/PiscesCache.java b/src/share/classes/sun/java2d/pisces/PiscesCache.java
index 0ecc420969887808e72f5635e79852331954efb5..dcd595c48f636887a405ae8b1e9da8e3103cfad5 100644
--- a/src/share/classes/sun/java2d/pisces/PiscesCache.java
+++ b/src/share/classes/sun/java2d/pisces/PiscesCache.java
@@ -25,6 +25,8 @@
package sun.java2d.pisces;
+import java.util.Arrays;
+
/**
* An object used to cache pre-rendered complex paths.
*
@@ -32,115 +34,153 @@ package sun.java2d.pisces;
*/
public final class PiscesCache {
- int bboxX0, bboxY0, bboxX1, bboxY1;
+ final int bboxX0, bboxY0, bboxX1, bboxY1;
+
+ // rowAARLE[i] holds the encoding of the pixel row with y = bboxY0+i.
+ // The format of each of the inner arrays is: rowAARLE[i][0,1] = (x0, n)
+ // where x0 is the first x in row i with nonzero alpha, and n is the
+ // number of RLE entries in this row. rowAARLE[i][j,j+1] for j>1 is
+ // (val,runlen)
+ final int[][] rowAARLE;
+
+ // RLE encodings are added in increasing y rows and then in increasing
+ // x inside those rows. Therefore, at any one time there is a well
+ // defined position (x,y) where a run length is about to be added (or
+ // the row terminated). x0,y0 is this (x,y)-(bboxX0,bboxY0). They
+ // are used to get indices into the current tile.
+ private int x0 = Integer.MIN_VALUE, y0 = Integer.MIN_VALUE;
+
+ // touchedTile[i][j] is the sum of all the alphas in the tile with
+ // y=i*TILE_SIZE+bboxY0 and x=j*TILE_SIZE+bboxX0.
+ private final int[][] touchedTile;
+
+ static final int TILE_SIZE_LG = 5;
+ static final int TILE_SIZE = 1 << TILE_SIZE_LG; // 32
+ private static final int INIT_ROW_SIZE = 8; // enough for 3 run lengths
+
+ PiscesCache(int minx, int miny, int maxx, int maxy) {
+ assert maxy >= miny && maxx >= minx;
+ bboxX0 = minx;
+ bboxY0 = miny;
+ bboxX1 = maxx + 1;
+ bboxY1 = maxy + 1;
+ // we could just leave the inner arrays as null and allocate them
+ // lazily (which would be beneficial for shapes with gaps), but we
+ // assume there won't be too many of those so we allocate everything
+ // up front (which is better for other cases)
+ rowAARLE = new int[bboxY1 - bboxY0 + 1][INIT_ROW_SIZE];
+ x0 = 0;
+ y0 = -1; // -1 makes the first assert in startRow succeed
+ // the ceiling of (maxy - miny + 1) / TILE_SIZE;
+ int nyTiles = (maxy - miny + TILE_SIZE) >> TILE_SIZE_LG;
+ int nxTiles = (maxx - minx + TILE_SIZE) >> TILE_SIZE_LG;
+
+ touchedTile = new int[nyTiles][nxTiles];
+ }
- byte[] rowAARLE;
- int alphaRLELength;
+ void addRLERun(int val, int runLen) {
+ if (runLen > 0) {
+ addTupleToRow(y0, val, runLen);
+ if (val != 0) {
+ // the x and y of the current row, minus bboxX0, bboxY0
+ int tx = x0 >> TILE_SIZE_LG;
+ int ty = y0 >> TILE_SIZE_LG;
+ int tx1 = (x0 + runLen - 1) >> TILE_SIZE_LG;
+ // while we forbid rows from starting before bboxx0, our users
+ // can still store rows that go beyond bboxx1 (although this
+ // shouldn't happen), so it's a good idea to check that i
+ // is not going out of bounds in touchedTile[ty]
+ if (tx1 >= touchedTile[ty].length) {
+ tx1 = touchedTile[ty].length - 1;
+ }
+ if (tx <= tx1) {
+ int nextTileXCoord = (tx + 1) << TILE_SIZE_LG;
+ if (nextTileXCoord > x0+runLen) {
+ touchedTile[ty][tx] += val * runLen;
+ } else {
+ touchedTile[ty][tx] += val * (nextTileXCoord - x0);
+ }
+ tx++;
+ }
+ // don't go all the way to tx1 - we need to handle the last
+ // tile as a special case (just like we did with the first
+ for (; tx < tx1; tx++) {
+// try {
+ touchedTile[ty][tx] += (val << TILE_SIZE_LG);
+// } catch (RuntimeException e) {
+// System.out.println("x0, y0: " + x0 + ", " + y0);
+// System.out.printf("tx, ty, tx1: %d, %d, %d %n", tx, ty, tx1);
+// System.out.printf("bboxX/Y0/1: %d, %d, %d, %d %n",
+// bboxX0, bboxY0, bboxX1, bboxY1);
+// throw e;
+// }
+ }
+ // they will be equal unless x0>>TILE_SIZE_LG == tx1
+ if (tx == tx1) {
+ int lastXCoord = Math.min(x0 + runLen, (tx + 1) << TILE_SIZE_LG);
+ int txXCoord = tx << TILE_SIZE_LG;
+ touchedTile[ty][tx] += val * (lastXCoord - txXCoord);
+ }
+ }
+ x0 += runLen;
+ }
+ }
- int[] rowOffsetsRLE;
- int[] minTouched;
- int alphaRows;
+ void startRow(int y, int x) {
+ // rows are supposed to be added by increasing y.
+ assert y - bboxY0 > y0;
+ assert y <= bboxY1; // perhaps this should be < instead of <=
- private PiscesCache() {}
+ y0 = y - bboxY0;
+ // this should be a new, uninitialized row.
+ assert rowAARLE[y0][1] == 0;
- public static PiscesCache createInstance() {
- return new PiscesCache();
- }
+ x0 = x - bboxX0;
+ assert x0 >= 0 : "Input must not be to the left of bbox bounds";
- private static final float ROWAA_RLE_FACTOR = 1.5f;
- private static final float TOUCHED_FACTOR = 1.5f;
- private static final int MIN_TOUCHED_LEN = 64;
-
- private void reallocRowAARLE(int newLength) {
- if (rowAARLE == null) {
- rowAARLE = new byte[newLength];
- } else if (rowAARLE.length < newLength) {
- int len = Math.max(newLength,
- (int)(rowAARLE.length*ROWAA_RLE_FACTOR));
- byte[] newRowAARLE = new byte[len];
- System.arraycopy(rowAARLE, 0, newRowAARLE, 0, rowAARLE.length);
- rowAARLE = newRowAARLE;
- }
+ // the way addTupleToRow is implemented it would work for this but it's
+ // not a good idea to use it because it is meant for adding
+ // RLE tuples, not the first tuple (which is special).
+ rowAARLE[y0][0] = x;
+ rowAARLE[y0][1] = 2;
}
- private void reallocRowInfo(int newHeight) {
- if (minTouched == null) {
- int len = Math.max(newHeight, MIN_TOUCHED_LEN);
- minTouched = new int[len];
- rowOffsetsRLE = new int[len];
- } else if (minTouched.length < newHeight) {
- int len = Math.max(newHeight,
- (int)(minTouched.length*TOUCHED_FACTOR));
- int[] newMinTouched = new int[len];
- int[] newRowOffsetsRLE = new int[len];
- System.arraycopy(minTouched, 0, newMinTouched, 0,
- alphaRows);
- System.arraycopy(rowOffsetsRLE, 0, newRowOffsetsRLE, 0,
- alphaRows);
- minTouched = newMinTouched;
- rowOffsetsRLE = newRowOffsetsRLE;
- }
+ int alphaSumInTile(int x, int y) {
+ x -= bboxX0;
+ y -= bboxY0;
+ return touchedTile[y>>TILE_SIZE_LG][x>>TILE_SIZE_LG];
}
- void addRLERun(byte val, int runLen) {
- reallocRowAARLE(alphaRLELength + 2);
- rowAARLE[alphaRLELength++] = val;
- rowAARLE[alphaRLELength++] = (byte)runLen;
+ int minTouched(int rowidx) {
+ return rowAARLE[rowidx][0];
}
- void startRow(int y, int x0, int x1) {
- if (alphaRows == 0) {
- bboxY0 = y;
- bboxY1 = y+1;
- bboxX0 = x0;
- bboxX1 = x1+1;
- } else {
- if (bboxX0 > x0) bboxX0 = x0;
- if (bboxX1 < x1 + 1) bboxX1 = x1 + 1;
- while (bboxY1++ < y) {
- reallocRowInfo(alphaRows+1);
- minTouched[alphaRows] = 0;
- // Assuming last 2 entries in rowAARLE are 0,0
- rowOffsetsRLE[alphaRows] = alphaRLELength-2;
- alphaRows++;
- }
- }
- reallocRowInfo(alphaRows+1);
- minTouched[alphaRows] = x0;
- rowOffsetsRLE[alphaRows] = alphaRLELength;
- alphaRows++;
+ int rowLength(int rowidx) {
+ return rowAARLE[rowidx][1];
}
- public synchronized void dispose() {
- rowAARLE = null;
- alphaRLELength = 0;
-
- minTouched = null;
- rowOffsetsRLE = null;
- alphaRows = 0;
-
- bboxX0 = bboxY0 = bboxX1 = bboxY1 = 0;
+ private void addTupleToRow(int row, int a, int b) {
+ int end = rowAARLE[row][1];
+ rowAARLE[row] = Helpers.widenArray(rowAARLE[row], end, 2);
+ rowAARLE[row][end++] = a;
+ rowAARLE[row][end++] = b;
+ rowAARLE[row][1] = end;
}
- public void print(java.io.PrintStream out) {
- synchronized (out) {
- out.println("bbox = ["+
- bboxX0+", "+bboxY0+" => "+
- bboxX1+", "+bboxY1+"]");
-
- out.println("alphRLELength = "+alphaRLELength);
-
- for (int y = bboxY0; y < bboxY1; y++) {
- int i = y-bboxY0;
- out.println("row["+i+"] == {"+
- "minX = "+minTouched[i]+
- ", off = "+rowOffsetsRLE[i]+"}");
- }
-
- for (int i = 0; i < alphaRLELength; i += 2) {
- out.println("rle["+i+"] = "+
- (rowAARLE[i+1]&0xff)+" of "+(rowAARLE[i]&0xff));
+ @Override
+ public String toString() {
+ String ret = "bbox = ["+
+ bboxX0+", "+bboxY0+" => "+
+ bboxX1+", "+bboxY1+"]\n";
+ for (int[] row : rowAARLE) {
+ if (row != null) {
+ ret += ("minTouchedX=" + row[0] +
+ "\tRLE Entries: " + Arrays.toString(
+ Arrays.copyOfRange(row, 2, row[1])) + "\n");
+ } else {
+ ret += "[]\n";
+ }
}
- }
+ return ret;
}
}
diff --git a/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java b/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java
index ee2b35e68096cc7140380f083b865d03e842db7d..ed6524ceb1b1447a6099449f386180071893d0ac 100644
--- a/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java
+++ b/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java
@@ -27,7 +27,7 @@ package sun.java2d.pisces;
import java.awt.Shape;
import java.awt.BasicStroke;
-import java.awt.geom.FlatteningPathIterator;
+import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Path2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
@@ -38,8 +38,6 @@ import sun.java2d.pipe.RenderingEngine;
import sun.java2d.pipe.AATileGenerator;
public class PiscesRenderingEngine extends RenderingEngine {
- public static double defaultFlat = 0.1;
-
private static enum NormMode {OFF, ON_NO_AA, ON_WITH_AA}
/**
@@ -78,20 +76,29 @@ public class PiscesRenderingEngine extends RenderingEngine {
miterlimit,
dashes,
dashphase,
- new LineSink() {
+ new PathConsumer2D() {
public void moveTo(float x0, float y0) {
p2d.moveTo(x0, y0);
}
- public void lineJoin() {}
public void lineTo(float x1, float y1) {
p2d.lineTo(x1, y1);
}
- public void close() {
+ public void closePath() {
p2d.closePath();
}
- public void end() {}
+ public void pathDone() {}
+ public void curveTo(float x1, float y1,
+ float x2, float y2,
+ float x3, float y3) {
+ p2d.curveTo(x1, y1, x2, y2, x3, y3);
+ }
+ public void quadTo(float x1, float y1, float x2, float y2) {
+ p2d.quadTo(x1, y1, x2, y2);
+ }
+ public long getNativeConsumer() {
+ throw new InternalError("Not using a native peer");
+ }
});
-
return p2d;
}
@@ -133,22 +140,7 @@ public class PiscesRenderingEngine extends RenderingEngine {
NormMode norm = (normalize) ?
((antialias) ? NormMode.ON_WITH_AA : NormMode.ON_NO_AA)
: NormMode.OFF;
- strokeTo(src, at, bs, thin, norm, antialias,
- new LineSink() {
- public void moveTo(float x0, float y0) {
- consumer.moveTo(x0, y0);
- }
- public void lineJoin() {}
- public void lineTo(float x1, float y1) {
- consumer.lineTo(x1, y1);
- }
- public void close() {
- consumer.closePath();
- }
- public void end() {
- consumer.pathDone();
- }
- });
+ strokeTo(src, at, bs, thin, norm, antialias, consumer);
}
void strokeTo(Shape src,
@@ -157,7 +149,7 @@ public class PiscesRenderingEngine extends RenderingEngine {
boolean thin,
NormMode normalize,
boolean antialias,
- LineSink lsink)
+ PathConsumer2D pc2d)
{
float lw;
if (thin) {
@@ -178,7 +170,7 @@ public class PiscesRenderingEngine extends RenderingEngine {
bs.getMiterLimit(),
bs.getDashArray(),
bs.getDashPhase(),
- lsink);
+ pc2d);
}
private float userSpaceLineWidth(AffineTransform at, float lw) {
@@ -256,28 +248,113 @@ public class PiscesRenderingEngine extends RenderingEngine {
float miterlimit,
float dashes[],
float dashphase,
- LineSink lsink)
+ PathConsumer2D pc2d)
{
- float a00 = 1f, a01 = 0f, a10 = 0f, a11 = 1f;
+ // We use inat and outat so that in Stroker and Dasher we can work only
+ // with the pre-transformation coordinates. This will repeat a lot of
+ // computations done in the path iterator, but the alternative is to
+ // work with transformed paths and compute untransformed coordinates
+ // as needed. This would be faster but I do not think the complexity
+ // of working with both untransformed and transformed coordinates in
+ // the same code is worth it.
+ // However, if a path's width is constant after a transformation,
+ // we can skip all this untransforming.
+
+ // If normalization is off we save some transformations by not
+ // transforming the input to pisces. Instead, we apply the
+ // transformation after the path processing has been done.
+ // We can't do this if normalization is on, because it isn't a good
+ // idea to normalize before the transformation is applied.
+ AffineTransform inat = null;
+ AffineTransform outat = null;
+
+ PathIterator pi = null;
+
if (at != null && !at.isIdentity()) {
- a00 = (float)at.getScaleX();
- a01 = (float)at.getShearX();
- a10 = (float)at.getShearY();
- a11 = (float)at.getScaleY();
+ final double a = at.getScaleX();
+ final double b = at.getShearX();
+ final double c = at.getShearY();
+ final double d = at.getScaleY();
+ final double det = a * d - c * b;
+ if (Math.abs(det) <= 2 * Float.MIN_VALUE) {
+ // this rendering engine takes one dimensional curves and turns
+ // them into 2D shapes by giving them width.
+ // However, if everything is to be passed through a singular
+ // transformation, these 2D shapes will be squashed down to 1D
+ // again so, nothing can be drawn.
+
+ // Every path needs an initial moveTo and a pathDone. If these
+ // aren't there this causes a SIGSEV in libawt.so (at the time
+ // of writing of this comment (September 16, 2010)). Actually,
+ // I'm not sure if the moveTo is necessary to avoid the SIGSEV
+ // but the pathDone is definitely needed.
+ pc2d.moveTo(0, 0);
+ pc2d.pathDone();
+ return;
+ }
+
+ // If the transform is a constant multiple of an orthogonal transformation
+ // then every length is just multiplied by a constant, so we just
+ // need to transform input paths to stroker and tell stroker
+ // the scaled width. This condition is satisfied if
+ // a*b == -c*d && a*a+c*c == b*b+d*d. In the actual check below, we
+ // leave a bit of room for error.
+ if (nearZero(a*b + c*d, 2) && nearZero(a*a+c*c - (b*b+d*d), 2)) {
+ double scale = Math.sqrt(a*a + c*c);
+ if (dashes != null) {
+ dashes = java.util.Arrays.copyOf(dashes, dashes.length);
+ for (int i = 0; i < dashes.length; i++) {
+ dashes[i] = (float)(scale * dashes[i]);
+ }
+ dashphase = (float)(scale * dashphase);
+ }
+ width = (float)(scale * width);
+ pi = src.getPathIterator(at);
+ if (normalize != NormMode.OFF) {
+ pi = new NormalizingPathIterator(pi, normalize);
+ }
+ // leave inat and outat null.
+ } else {
+ // We only need the inverse if normalization is on. Otherwise
+ // we just don't transform the input paths, do all the stroking
+ // and then transform out output (instead of making PathIterator
+ // apply the transformation, us applying the inverse, and then
+ // us applying the transform again to our output).
+ outat = at;
+ if (normalize != NormMode.OFF) {
+ try {
+ inat = outat.createInverse();
+ } catch (NoninvertibleTransformException e) {
+ // we made sure this can't happen
+ e.printStackTrace();
+ }
+ pi = src.getPathIterator(at);
+ pi = new NormalizingPathIterator(pi, normalize);
+ } else {
+ pi = src.getPathIterator(null);
+ }
+ }
+ } else {
+ // either at is null or it's the identity. In either case
+ // we don't transform the path.
+ pi = src.getPathIterator(null);
+ if (normalize != NormMode.OFF) {
+ pi = new NormalizingPathIterator(pi, normalize);
+ }
}
- lsink = new Stroker(lsink, width, caps, join, miterlimit, a00, a01, a10, a11);
+
+ pc2d = TransformingPathConsumer2D.transformConsumer(pc2d, outat);
+ pc2d = new Stroker(pc2d, width, caps, join, miterlimit);
if (dashes != null) {
- lsink = new Dasher(lsink, dashes, dashphase, a00, a01, a10, a11);
- }
- PathIterator pi;
- if (normalize != NormMode.OFF) {
- pi = new FlatteningPathIterator(
- new NormalizingPathIterator(src.getPathIterator(at), normalize),
- defaultFlat);
- } else {
- pi = src.getPathIterator(at, defaultFlat);
+ pc2d = new Dasher(pc2d, dashes, dashphase);
}
- pathTo(pi, lsink);
+ pc2d = TransformingPathConsumer2D.transformConsumer(pc2d, inat);
+
+ pathTo(pi, pc2d);
+ }
+
+ private static boolean nearZero(double num, int nulps) {
+ return Math.abs(num) < nulps * Math.ulp(num);
}
private static class NormalizingPathIterator implements PathIterator {
@@ -337,10 +414,10 @@ public class PiscesRenderingEngine extends RenderingEngine {
}
// normalize endpoint
- float x_adjust = (float)Math.floor(coords[lastCoord] + lval) + rval -
- coords[lastCoord];
- float y_adjust = (float)Math.floor(coords[lastCoord+1] + lval) + rval -
- coords[lastCoord + 1];
+ float x_adjust = (float)Math.floor(coords[lastCoord] + lval) +
+ rval - coords[lastCoord];
+ float y_adjust = (float)Math.floor(coords[lastCoord+1] + lval) +
+ rval - coords[lastCoord + 1];
coords[lastCoord ] += x_adjust;
coords[lastCoord + 1] += y_adjust;
@@ -393,27 +470,9 @@ public class PiscesRenderingEngine extends RenderingEngine {
}
}
- void pathTo(PathIterator pi, LineSink lsink) {
- float coords[] = new float[2];
- while (!pi.isDone()) {
- switch (pi.currentSegment(coords)) {
- case PathIterator.SEG_MOVETO:
- lsink.moveTo(coords[0], coords[1]);
- break;
- case PathIterator.SEG_LINETO:
- lsink.lineJoin();
- lsink.lineTo(coords[0], coords[1]);
- break;
- case PathIterator.SEG_CLOSE:
- lsink.lineJoin();
- lsink.close();
- break;
- default:
- throw new InternalError("unknown flattened segment type");
- }
- pi.next();
- }
- lsink.end();
+ static void pathTo(PathIterator pi, PathConsumer2D pc2d) {
+ RenderingEngine.feedConsumer(pi, pc2d);
+ pc2d.pathDone();
}
/**
@@ -471,32 +530,29 @@ public class PiscesRenderingEngine extends RenderingEngine {
boolean normalize,
int bbox[])
{
- PiscesCache pc = PiscesCache.createInstance();
Renderer r;
NormMode norm = (normalize) ? NormMode.ON_WITH_AA : NormMode.OFF;
if (bs == null) {
PathIterator pi;
if (normalize) {
- pi = new FlatteningPathIterator(
- new NormalizingPathIterator(s.getPathIterator(at), norm),
- defaultFlat);
+ pi = new NormalizingPathIterator(s.getPathIterator(at), norm);
} else {
- pi = s.getPathIterator(at, defaultFlat);
+ pi = s.getPathIterator(at);
}
r = new Renderer(3, 3,
clip.getLoX(), clip.getLoY(),
clip.getWidth(), clip.getHeight(),
- pi.getWindingRule(), pc);
+ pi.getWindingRule());
pathTo(pi, r);
} else {
r = new Renderer(3, 3,
clip.getLoX(), clip.getLoY(),
clip.getWidth(), clip.getHeight(),
- PathIterator.WIND_NON_ZERO, pc);
+ PathIterator.WIND_NON_ZERO);
strokeTo(s, at, bs, thin, norm, true, r);
}
r.endRendering();
- PiscesTileGenerator ptg = new PiscesTileGenerator(pc, r.MAX_AA_ALPHA);
+ PiscesTileGenerator ptg = new PiscesTileGenerator(r, r.MAX_AA_ALPHA);
ptg.getBbox(bbox);
return ptg;
}
diff --git a/src/share/classes/sun/java2d/pisces/PiscesTileGenerator.java b/src/share/classes/sun/java2d/pisces/PiscesTileGenerator.java
index 93ff5315d9fc96b45762aa9aae7d82a29175a06a..e2779b8fe0393002c50842540b7b4bc2fd761939 100644
--- a/src/share/classes/sun/java2d/pisces/PiscesTileGenerator.java
+++ b/src/share/classes/sun/java2d/pisces/PiscesTileGenerator.java
@@ -25,40 +25,54 @@
package sun.java2d.pisces;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
import sun.java2d.pipe.AATileGenerator;
-public class PiscesTileGenerator implements AATileGenerator {
- public static final int TILE_SIZE = 32;
+public final class PiscesTileGenerator implements AATileGenerator {
+ public static final int TILE_SIZE = PiscesCache.TILE_SIZE;
+
+ // perhaps we should be using weak references here, but right now
+ // that's not necessary. The way the renderer is, this map will
+ // never contain more than one element - the one with key 64, since
+ // we only do 8x8 supersampling.
+ private static final MapStroker.
*
- * @param output an output LineSink.
+ * @param pc2d an output PathConsumer2D.
* @param lineWidth the desired line width in pixels
* @param capStyle the desired end cap style, one of
* CAP_BUTT, CAP_ROUND or
@@ -120,183 +108,61 @@ public class Stroker implements LineSink {
* JOIN_MITER, JOIN_ROUND or
* JOIN_BEVEL.
* @param miterLimit the desired miter limit
- * @param transform a Transform4 object indicating
- * the transform that has been previously applied to all incoming
- * coordinates. This is required in order to produce consistently
- * shaped end caps and joins.
*/
- public Stroker(LineSink output,
+ public Stroker(PathConsumer2D pc2d,
float lineWidth,
int capStyle,
int joinStyle,
- float miterLimit,
- float m00, float m01, float m10, float m11) {
- this.output = output;
+ float miterLimit)
+ {
+ this.out = pc2d;
this.lineWidth2 = lineWidth / 2;
- this.scaledLineWidth2 = m00 * lineWidth2;
this.capStyle = capStyle;
this.joinStyle = joinStyle;
- m00_2_m01_2 = m00*m00 + m01*m01;
- m10_2_m11_2 = m10*m10 + m11*m11;
- m00_m10_m01_m11 = m00*m10 + m01*m11;
-
- this.m00 = m00;
- this.m01 = m01;
- this.m10 = m10;
- this.m11 = m11;
- det = m00*m11 - m01*m10;
-
- float limit = miterLimit * lineWidth2 * det;
+ float limit = miterLimit * lineWidth2;
this.miterLimitSq = limit*limit;
- this.numPenSegments = (int)(3.14159f * lineWidth);
- this.pen_dx = new float[numPenSegments];
- this.pen_dy = new float[numPenSegments];
- this.penIncluded = new boolean[numPenSegments];
- this.join = new float[2*numPenSegments];
-
- for (int i = 0; i < numPenSegments; i++) {
- double theta = (i * 2.0 * Math.PI)/numPenSegments;
-
- double cos = Math.cos(theta);
- double sin = Math.sin(theta);
- pen_dx[i] = (float)(lineWidth2 * (m00*cos + m01*sin));
- pen_dy[i] = (float)(lineWidth2 * (m10*cos + m11*sin));
- }
-
- prev = CLOSE;
- rindex = 0;
- started = false;
- lineToOrigin = false;
+ this.prev = CLOSE;
}
- private void computeOffset(float x0, float y0,
- float x1, float y1, float[] m) {
- float lx = x1 - x0;
- float ly = y1 - y0;
-
- float dx, dy;
- if (m00 > 0 && m00 == m11 && m01 == 0 & m10 == 0) {
- float ilen = (float)Math.hypot(lx, ly);
- if (ilen == 0) {
- dx = dy = 0;
- } else {
- dx = (ly * scaledLineWidth2)/ilen;
- dy = -(lx * scaledLineWidth2)/ilen;
- }
+ private static void computeOffset(final float lx, final float ly,
+ final float w, final float[] m)
+ {
+ final float len = (float)Math.hypot(lx, ly);
+ if (len == 0) {
+ m[0] = m[1] = 0;
} else {
- int sdet = (det > 0) ? 1 : -1;
- float a = ly * m00 - lx * m10;
- float b = ly * m01 - lx * m11;
- float dh = (float)Math.hypot(a, b);
- float div = sdet * lineWidth2/dh;
-
- float ddx = ly * m00_2_m01_2 - lx * m00_m10_m01_m11;
- float ddy = ly * m00_m10_m01_m11 - lx * m10_2_m11_2;
- dx = ddx*div;
- dy = ddy*div;
- }
-
- m[0] = dx;
- m[1] = dy;
- }
-
- private void ensureCapacity(int newrindex) {
- if (reverse.length < newrindex) {
- reverse = java.util.Arrays.copyOf(reverse, 6*reverse.length/5);
+ m[0] = (ly * w)/len;
+ m[1] = -(lx * w)/len;
}
}
- private boolean isCCW(float x0, float y0,
- float x1, float y1,
- float x2, float y2) {
- return (x1 - x0) * (y2 - y1) < (y1 - y0) * (x2 - x1);
- }
-
- private boolean side(float x, float y,
- float x0, float y0,
- float x1, float y1) {
- return (y0 - y1)*x + (x1 - x0)*y + (x0*y1 - x1*y0) > 0;
- }
-
- private int computeRoundJoin(float cx, float cy,
- float xa, float ya,
- float xb, float yb,
- int side,
- boolean flip,
- float[] join) {
- float px, py;
- int ncoords = 0;
-
- boolean centerSide;
- if (side == 0) {
- centerSide = side(cx, cy, xa, ya, xb, yb);
- } else {
- centerSide = (side == 1);
- }
- for (int i = 0; i < numPenSegments; i++) {
- px = cx + pen_dx[i];
- py = cy + pen_dy[i];
-
- boolean penSide = side(px, py, xa, ya, xb, yb);
- penIncluded[i] = (penSide != centerSide);
- }
-
- int start = -1, end = -1;
- for (int i = 0; i < numPenSegments; i++) {
- if (penIncluded[i] &&
- !penIncluded[(i + numPenSegments - 1) % numPenSegments]) {
- start = i;
- }
- if (penIncluded[i] &&
- !penIncluded[(i + 1) % numPenSegments]) {
- end = i;
- }
- }
-
- if (end < start) {
- end += numPenSegments;
- }
-
- if (start != -1 && end != -1) {
- float dxa = cx + pen_dx[start] - xa;
- float dya = cy + pen_dy[start] - ya;
- float dxb = cx + pen_dx[start] - xb;
- float dyb = cy + pen_dy[start] - yb;
-
- boolean rev = (dxa*dxa + dya*dya > dxb*dxb + dyb*dyb);
- int i = rev ? end : start;
- int incr = rev ? -1 : 1;
- while (true) {
- int idx = i % numPenSegments;
- px = cx + pen_dx[idx];
- py = cy + pen_dy[idx];
- join[ncoords++] = px;
- join[ncoords++] = py;
- if (i == (rev ? start : end)) {
- break;
- }
- i += incr;
- }
- }
-
- return ncoords/2;
+ // Returns true if the vectors (dx1, dy1) and (dx2, dy2) are
+ // clockwise (if dx1,dy1 needs to be rotated clockwise to close
+ // the smallest angle between it and dx2,dy2).
+ // This is equivalent to detecting whether a point q is on the right side
+ // of a line passing through points p1, p2 where p2 = p1+(dx1,dy1) and
+ // q = p2+(dx2,dy2), which is the same as saying p1, p2, q are in a
+ // clockwise order.
+ // NOTE: "clockwise" here assumes coordinates with 0,0 at the bottom left.
+ private static boolean isCW(final float dx1, final float dy1,
+ final float dx2, final float dy2)
+ {
+ return dx1 * dy2 <= dy1 * dx2;
}
// pisces used to use fixed point arithmetic with 16 decimal digits. I
- // didn't want to change the values of the constants below when I converted
+ // didn't want to change the values of the constant below when I converted
// it to floating point, so that's why the divisions by 2^16 are there.
private static final float ROUND_JOIN_THRESHOLD = 1000/65536f;
- private static final float ROUND_JOIN_INTERNAL_THRESHOLD = 1000000000/65536f;
private void drawRoundJoin(float x, float y,
float omx, float omy, float mx, float my,
- int side,
- boolean flip,
boolean rev,
- float threshold) {
+ float threshold)
+ {
if ((omx == 0 && omy == 0) || (mx == 0 && my == 0)) {
return;
}
@@ -314,54 +180,148 @@ public class Stroker implements LineSink {
mx = -mx;
my = -my;
}
+ drawRoundJoin(x, y, omx, omy, mx, my, rev);
+ }
- float bx0 = x + omx;
- float by0 = y + omy;
- float bx1 = x + mx;
- float by1 = y + my;
+ private void drawRoundJoin(float cx, float cy,
+ float omx, float omy,
+ float mx, float my,
+ boolean rev)
+ {
+ // The sign of the dot product of mx,my and omx,omy is equal to the
+ // the sign of the cosine of ext
+ // (ext is the angle between omx,omy and mx,my).
+ double cosext = omx * mx + omy * my;
+ // If it is >=0, we know that abs(ext) is <= 90 degrees, so we only
+ // need 1 curve to approximate the circle section that joins omx,omy
+ // and mx,my.
+ final int numCurves = cosext >= 0 ? 1 : 2;
+
+ switch (numCurves) {
+ case 1:
+ drawBezApproxForArc(cx, cy, omx, omy, mx, my, rev);
+ break;
+ case 2:
+ // we need to split the arc into 2 arcs spanning the same angle.
+ // The point we want will be one of the 2 intersections of the
+ // perpendicular bisector of the chord (omx,omy)->(mx,my) and the
+ // circle. We could find this by scaling the vector
+ // (omx+mx, omy+my)/2 so that it has length=lineWidth2 (and thus lies
+ // on the circle), but that can have numerical problems when the angle
+ // between omx,omy and mx,my is close to 180 degrees. So we compute a
+ // normal of (omx,omy)-(mx,my). This will be the direction of the
+ // perpendicular bisector. To get one of the intersections, we just scale
+ // this vector that its length is lineWidth2 (this works because the
+ // perpendicular bisector goes through the origin). This scaling doesn't
+ // have numerical problems because we know that lineWidth2 divided by
+ // this normal's length is at least 0.5 and at most sqrt(2)/2 (because
+ // we know the angle of the arc is > 90 degrees).
+ float nx = my - omy, ny = omx - mx;
+ float nlen = (float)Math.sqrt(nx*nx + ny*ny);
+ float scale = lineWidth2/nlen;
+ float mmx = nx * scale, mmy = ny * scale;
+
+ // if (isCW(omx, omy, mx, my) != isCW(mmx, mmy, mx, my)) then we've
+ // computed the wrong intersection so we get the other one.
+ // The test above is equivalent to if (rev).
+ if (rev) {
+ mmx = -mmx;
+ mmy = -mmy;
+ }
+ drawBezApproxForArc(cx, cy, omx, omy, mmx, mmy, rev);
+ drawBezApproxForArc(cx, cy, mmx, mmy, mx, my, rev);
+ break;
+ }
+ }
- int npoints = computeRoundJoin(x, y,
- bx0, by0, bx1, by1, side, flip,
- join);
- for (int i = 0; i < npoints; i++) {
- emitLineTo(join[2*i], join[2*i + 1], rev);
+ // the input arc defined by omx,omy and mx,my must span <= 90 degrees.
+ private void drawBezApproxForArc(final float cx, final float cy,
+ final float omx, final float omy,
+ final float mx, final float my,
+ boolean rev)
+ {
+ float cosext2 = (omx * mx + omy * my) / (2 * lineWidth2 * lineWidth2);
+ // cv is the length of P1-P0 and P2-P3 divided by the radius of the arc
+ // (so, cv assumes the arc has radius 1). P0, P1, P2, P3 are the points that
+ // define the bezier curve we're computing.
+ // It is computed using the constraints that P1-P0 and P3-P2 are parallel
+ // to the arc tangents at the endpoints, and that |P1-P0|=|P3-P2|.
+ float cv = (float)((4.0 / 3.0) * Math.sqrt(0.5-cosext2) /
+ (1.0 + Math.sqrt(cosext2+0.5)));
+ // if clockwise, we need to negate cv.
+ if (rev) { // rev is equivalent to isCW(omx, omy, mx, my)
+ cv = -cv;
}
+ final float x1 = cx + omx;
+ final float y1 = cy + omy;
+ final float x2 = x1 - cv * omy;
+ final float y2 = y1 + cv * omx;
+
+ final float x4 = cx + mx;
+ final float y4 = cy + my;
+ final float x3 = x4 + cv * my;
+ final float y3 = y4 - cv * mx;
+
+ emitCurveTo(x1, y1, x2, y2, x3, y3, x4, y4, rev);
}
- // Return the intersection point of the lines (ix0, iy0) -> (ix1, iy1)
- // and (ix0p, iy0p) -> (ix1p, iy1p) in m[0] and m[1]
- private void computeMiter(float x0, float y0, float x1, float y1,
- float x0p, float y0p, float x1p, float y1p,
- float[] m) {
+ private void drawRoundCap(float cx, float cy, float mx, float my) {
+ final float C = 0.5522847498307933f;
+ // the first and second arguments of the following two calls
+ // are really will be ignored by emitCurveTo (because of the false),
+ // but we put them in anyway, as opposed to just giving it 4 zeroes,
+ // because it's just 4 additions and it's not good to rely on this
+ // sort of assumption (right now it's true, but that may change).
+ emitCurveTo(cx+mx, cy+my,
+ cx+mx-C*my, cy+my+C*mx,
+ cx-my+C*mx, cy+mx+C*my,
+ cx-my, cy+mx,
+ false);
+ emitCurveTo(cx-my, cy+mx,
+ cx-my-C*mx, cy+mx-C*my,
+ cx-mx-C*my, cy-my+C*mx,
+ cx-mx, cy-my,
+ false);
+ }
+
+ // Return the intersection point of the lines (x0, y0) -> (x1, y1)
+ // and (x0p, y0p) -> (x1p, y1p) in m[0] and m[1]
+ private void computeMiter(final float x0, final float y0,
+ final float x1, final float y1,
+ final float x0p, final float y0p,
+ final float x1p, final float y1p,
+ final float[] m, int off)
+ {
float x10 = x1 - x0;
float y10 = y1 - y0;
float x10p = x1p - x0p;
float y10p = y1p - y0p;
+ // if this is 0, the lines are parallel. If they go in the
+ // same direction, there is no intersection so m[off] and
+ // m[off+1] will contain infinity, so no miter will be drawn.
+ // If they go in the same direction that means that the start of the
+ // current segment and the end of the previous segment have the same
+ // tangent, in which case this method won't even be involved in
+ // miter drawing because it won't be called by drawMiter (because
+ // (mx == omx && my == omy) will be true, and drawMiter will return
+ // immediately).
float den = x10*y10p - x10p*y10;
- if (den == 0) {
- m[0] = x0;
- m[1] = y0;
- return;
- }
-
- float t = x1p*(y0 - y0p) - x0*y10p + x0p*(y1p - y0);
- m[0] = x0 + (t*x10)/den;
- m[1] = y0 + (t*y10)/den;
+ float t = x10p*(y0-y0p) - y10p*(x0-x0p);
+ t /= den;
+ m[off++] = x0 + t*x10;
+ m[off] = y0 + t*y10;
}
- private void drawMiter(float px0, float py0,
- float x0, float y0,
- float x1, float y1,
+ private void drawMiter(final float pdx, final float pdy,
+ final float x0, final float y0,
+ final float dx, final float dy,
float omx, float omy, float mx, float my,
- boolean rev) {
- if (mx == omx && my == omy) {
- return;
- }
- if (px0 == x0 && py0 == y0) {
- return;
- }
- if (x0 == x1 && y0 == y1) {
+ boolean rev)
+ {
+ if ((mx == omx && my == omy) ||
+ (pdx == 0 && pdy == 0) ||
+ (dx == 0 && dy == 0)) {
return;
}
@@ -372,297 +332,734 @@ public class Stroker implements LineSink {
my = -my;
}
- computeMiter(px0 + omx, py0 + omy, x0 + omx, y0 + omy,
- x0 + mx, y0 + my, x1 + mx, y1 + my,
- miter);
+ computeMiter((x0 - pdx) + omx, (y0 - pdy) + omy, x0 + omx, y0 + omy,
+ (dx + x0) + mx, (dy + y0) + my, x0 + mx, y0 + my,
+ miter, 0);
- // Compute miter length in untransformed coordinates
- float dx = miter[0] - x0;
- float dy = miter[1] - y0;
- float a = dy*m00 - dx*m10;
- float b = dy*m01 - dx*m11;
- float lenSq = a*a + b*b;
+ float lenSq = (miter[0]-x0)*(miter[0]-x0) + (miter[1]-y0)*(miter[1]-y0);
if (lenSq < miterLimitSq) {
emitLineTo(miter[0], miter[1], rev);
}
}
-
public void moveTo(float x0, float y0) {
- // System.out.println("Stroker.moveTo(" + x0/65536.0 + ", " + y0/65536.0 + ")");
-
- if (lineToOrigin) {
- // not closing the path, do the previous lineTo
- lineToImpl(sx0, sy0, joinToOrigin);
- lineToOrigin = false;
- }
-
- if (prev == LINE_TO) {
+ if (prev == DRAWING_OP_TO) {
finish();
}
-
- this.sx0 = this.x0 = x0;
- this.sy0 = this.y0 = y0;
- this.rindex = 0;
- this.started = false;
- this.joinSegment = false;
+ this.sx0 = this.cx0 = x0;
+ this.sy0 = this.cy0 = y0;
+ this.cdx = this.sdx = 1;
+ this.cdy = this.sdy = 0;
this.prev = MOVE_TO;
}
- boolean joinSegment = false;
+ public void lineTo(float x1, float y1) {
+ float dx = x1 - cx0;
+ float dy = y1 - cy0;
+ if (dx == 0f && dy == 0f) {
+ dx = 1;
+ }
+ computeOffset(dx, dy, lineWidth2, offset[0]);
+ float mx = offset[0][0];
+ float my = offset[0][1];
+
+ drawJoin(cdx, cdy, cx0, cy0, dx, dy, cmx, cmy, mx, my);
- public void lineJoin() {
- // System.out.println("Stroker.lineJoin()");
- this.joinSegment = true;
- }
+ emitLineTo(cx0 + mx, cy0 + my);
+ emitLineTo(x1 + mx, y1 + my);
- public void lineTo(float x1, float y1) {
- // System.out.println("Stroker.lineTo(" + x1/65536.0 + ", " + y1/65536.0 + ")");
+ emitLineTo(cx0 - mx, cy0 - my, true);
+ emitLineTo(x1 - mx, y1 - my, true);
+
+ this.cmx = mx;
+ this.cmy = my;
+ this.cdx = dx;
+ this.cdy = dy;
+ this.cx0 = x1;
+ this.cy0 = y1;
+ this.prev = DRAWING_OP_TO;
+ }
- if (lineToOrigin) {
- if (x1 == sx0 && y1 == sy0) {
- // staying in the starting point
+ public void closePath() {
+ if (prev != DRAWING_OP_TO) {
+ if (prev == CLOSE) {
return;
}
-
- // not closing the path, do the previous lineTo
- lineToImpl(sx0, sy0, joinToOrigin);
- lineToOrigin = false;
- } else if (x1 == x0 && y1 == y0) {
- return;
- } else if (x1 == sx0 && y1 == sy0) {
- lineToOrigin = true;
- joinToOrigin = joinSegment;
- joinSegment = false;
+ emitMoveTo(cx0, cy0 - lineWidth2);
+ this.cmx = this.smx = 0;
+ this.cmy = this.smy = -lineWidth2;
+ this.cdx = this.sdx = 1;
+ this.cdy = this.sdy = 0;
+ finish();
return;
}
- lineToImpl(x1, y1, joinSegment);
- joinSegment = false;
+ if (cx0 != sx0 || cy0 != sy0) {
+ lineTo(sx0, sy0);
+ }
+
+ drawJoin(cdx, cdy, cx0, cy0, sdx, sdy, cmx, cmy, smx, smy);
+
+ emitLineTo(sx0 + smx, sy0 + smy);
+
+ emitMoveTo(sx0 - smx, sy0 - smy);
+ emitReverse();
+
+ this.prev = CLOSE;
+ emitClose();
}
- private void lineToImpl(float x1, float y1, boolean joinSegment) {
- computeOffset(x0, y0, x1, y1, offset);
- float mx = offset[0];
- float my = offset[1];
+ private void emitReverse() {
+ while(!reverse.isEmpty()) {
+ reverse.pop(out);
+ }
+ }
- if (!started) {
- emitMoveTo(x0 + mx, y0 + my);
- this.sx1 = x1;
- this.sy1 = y1;
- this.mx0 = mx;
- this.my0 = my;
- started = true;
- } else {
- boolean ccw = isCCW(px0, py0, x0, y0, x1, y1);
- if (joinSegment) {
- if (joinStyle == JOIN_MITER) {
- drawMiter(px0, py0, x0, y0, x1, y1, omx, omy, mx, my,
- ccw);
- } else if (joinStyle == JOIN_ROUND) {
- drawRoundJoin(x0, y0,
- omx, omy,
- mx, my, 0, false, ccw,
- ROUND_JOIN_THRESHOLD);
- }
- } else {
- // Draw internal joins as round
- drawRoundJoin(x0, y0,
- omx, omy,
- mx, my, 0, false, ccw,
- ROUND_JOIN_INTERNAL_THRESHOLD);
- }
+ public void pathDone() {
+ if (prev == DRAWING_OP_TO) {
+ finish();
+ }
+
+ out.pathDone();
+ // this shouldn't matter since this object won't be used
+ // after the call to this method.
+ this.prev = CLOSE;
+ }
- emitLineTo(x0, y0, !ccw);
+ private void finish() {
+ if (capStyle == CAP_ROUND) {
+ drawRoundCap(cx0, cy0, cmx, cmy);
+ } else if (capStyle == CAP_SQUARE) {
+ emitLineTo(cx0 - cmy + cmx, cy0 + cmx + cmy);
+ emitLineTo(cx0 - cmy - cmx, cy0 + cmx - cmy);
}
- emitLineTo(x0 + mx, y0 + my, false);
- emitLineTo(x1 + mx, y1 + my, false);
+ emitReverse();
- emitLineTo(x0 - mx, y0 - my, true);
- emitLineTo(x1 - mx, y1 - my, true);
+ if (capStyle == CAP_ROUND) {
+ drawRoundCap(sx0, sy0, -smx, -smy);
+ } else if (capStyle == CAP_SQUARE) {
+ emitLineTo(sx0 + smy - smx, sy0 - smx - smy);
+ emitLineTo(sx0 + smy + smx, sy0 - smx + smy);
+ }
- this.omx = mx;
- this.omy = my;
- this.px0 = x0;
- this.py0 = y0;
- this.x0 = x1;
- this.y0 = y1;
- this.prev = LINE_TO;
+ emitClose();
}
- public void close() {
- // System.out.println("Stroker.close()");
+ private void emitMoveTo(final float x0, final float y0) {
+ out.moveTo(x0, y0);
+ }
- if (lineToOrigin) {
- // ignore the previous lineTo
- lineToOrigin = false;
+ private void emitLineTo(final float x1, final float y1) {
+ out.lineTo(x1, y1);
+ }
+
+ private void emitLineTo(final float x1, final float y1,
+ final boolean rev)
+ {
+ if (rev) {
+ reverse.pushLine(x1, y1);
+ } else {
+ emitLineTo(x1, y1);
}
+ }
- if (!started) {
- finish();
- return;
+ private void emitQuadTo(final float x0, final float y0,
+ final float x1, final float y1,
+ final float x2, final float y2, final boolean rev)
+ {
+ if (rev) {
+ reverse.pushQuad(x0, y0, x1, y1);
+ } else {
+ out.quadTo(x1, y1, x2, y2);
}
+ }
+
+ private void emitCurveTo(final float x0, final float y0,
+ final float x1, final float y1,
+ final float x2, final float y2,
+ final float x3, final float y3, final boolean rev)
+ {
+ if (rev) {
+ reverse.pushCubic(x0, y0, x1, y1, x2, y2);
+ } else {
+ out.curveTo(x1, y1, x2, y2, x3, y3);
+ }
+ }
- computeOffset(x0, y0, sx0, sy0, offset);
- float mx = offset[0];
- float my = offset[1];
+ private void emitClose() {
+ out.closePath();
+ }
- // Draw penultimate join
- boolean ccw = isCCW(px0, py0, x0, y0, sx0, sy0);
- if (joinSegment) {
+ private void drawJoin(float pdx, float pdy,
+ float x0, float y0,
+ float dx, float dy,
+ float omx, float omy,
+ float mx, float my)
+ {
+ if (prev != DRAWING_OP_TO) {
+ emitMoveTo(x0 + mx, y0 + my);
+ this.sdx = dx;
+ this.sdy = dy;
+ this.smx = mx;
+ this.smy = my;
+ } else {
+ boolean cw = isCW(pdx, pdy, dx, dy);
if (joinStyle == JOIN_MITER) {
- drawMiter(px0, py0, x0, y0, sx0, sy0, omx, omy, mx, my, ccw);
+ drawMiter(pdx, pdy, x0, y0, dx, dy, omx, omy, mx, my, cw);
} else if (joinStyle == JOIN_ROUND) {
- drawRoundJoin(x0, y0, omx, omy, mx, my, 0, false, ccw,
+ drawRoundJoin(x0, y0,
+ omx, omy,
+ mx, my, cw,
ROUND_JOIN_THRESHOLD);
}
- } else {
- // Draw internal joins as round
- drawRoundJoin(x0, y0,
- omx, omy,
- mx, my, 0, false, ccw,
- ROUND_JOIN_INTERNAL_THRESHOLD);
+ emitLineTo(x0, y0, !cw);
}
+ prev = DRAWING_OP_TO;
+ }
- emitLineTo(x0 + mx, y0 + my);
- emitLineTo(sx0 + mx, sy0 + my);
+ private static boolean within(final float x1, final float y1,
+ final float x2, final float y2,
+ final float ERR)
+ {
+ assert ERR > 0 : "";
+ // compare taxicab distance. ERR will always be small, so using
+ // true distance won't give much benefit
+ return (Helpers.within(x1, x2, ERR) && // we want to avoid calling Math.abs
+ Helpers.within(y1, y2, ERR)); // this is just as good.
+ }
- ccw = isCCW(x0, y0, sx0, sy0, sx1, sy1);
+ private void getLineOffsets(float x1, float y1,
+ float x2, float y2,
+ float[] left, float[] right) {
+ computeOffset(x2 - x1, y2 - y1, lineWidth2, offset[0]);
+ left[0] = x1 + offset[0][0];
+ left[1] = y1 + offset[0][1];
+ left[2] = x2 + offset[0][0];
+ left[3] = y2 + offset[0][1];
+ right[0] = x1 - offset[0][0];
+ right[1] = y1 - offset[0][1];
+ right[2] = x2 - offset[0][0];
+ right[3] = y2 - offset[0][1];
+ }
- // Draw final join on the outside
- if (!ccw) {
- if (joinStyle == JOIN_MITER) {
- drawMiter(x0, y0, sx0, sy0, sx1, sy1,
- mx, my, mx0, my0, false);
- } else if (joinStyle == JOIN_ROUND) {
- drawRoundJoin(sx0, sy0, mx, my, mx0, my0, 0, false, false,
- ROUND_JOIN_THRESHOLD);
- }
+ private int computeOffsetCubic(float[] pts, final int off,
+ float[] leftOff, float[] rightOff)
+ {
+ // if p1=p2 or p3=p4 it means that the derivative at the endpoint
+ // vanishes, which creates problems with computeOffset. Usually
+ // this happens when this stroker object is trying to winden
+ // a curve with a cusp. What happens is that curveTo splits
+ // the input curve at the cusp, and passes it to this function.
+ // because of inaccuracies in the splitting, we consider points
+ // equal if they're very close to each other.
+ final float x1 = pts[off + 0], y1 = pts[off + 1];
+ final float x2 = pts[off + 2], y2 = pts[off + 3];
+ final float x3 = pts[off + 4], y3 = pts[off + 5];
+ final float x4 = pts[off + 6], y4 = pts[off + 7];
+
+ float dx4 = x4 - x3;
+ float dy4 = y4 - y3;
+ float dx1 = x2 - x1;
+ float dy1 = y2 - y1;
+
+ // if p1 == p2 && p3 == p4: draw line from p1->p4, unless p1 == p4,
+ // in which case ignore if p1 == p2
+ final boolean p1eqp2 = within(x1,y1,x2,y2, 6 * Math.ulp(y2));
+ final boolean p3eqp4 = within(x3,y3,x4,y4, 6 * Math.ulp(y4));
+ if (p1eqp2 && p3eqp4) {
+ getLineOffsets(x1, y1, x4, y4, leftOff, rightOff);
+ return 4;
+ } else if (p1eqp2) {
+ dx1 = x3 - x1;
+ dy1 = y3 - y1;
+ } else if (p3eqp4) {
+ dx4 = x4 - x2;
+ dy4 = y4 - y2;
}
- emitLineTo(sx0 + mx0, sy0 + my0);
- emitLineTo(sx0 - mx0, sy0 - my0); // same as reverse[0], reverse[1]
+ // if p2-p1 and p4-p3 are parallel, that must mean this curve is a line
+ float dotsq = (dx1 * dx4 + dy1 * dy4);
+ dotsq = dotsq * dotsq;
+ float l1sq = dx1 * dx1 + dy1 * dy1, l4sq = dx4 * dx4 + dy4 * dy4;
+ if (Helpers.within(dotsq, l1sq * l4sq, 4 * Math.ulp(dotsq))) {
+ getLineOffsets(x1, y1, x4, y4, leftOff, rightOff);
+ return 4;
+ }
- // Draw final join on the inside
- if (ccw) {
- if (joinStyle == JOIN_MITER) {
- drawMiter(x0, y0, sx0, sy0, sx1, sy1,
- -mx, -my, -mx0, -my0, false);
- } else if (joinStyle == JOIN_ROUND) {
- drawRoundJoin(sx0, sy0, -mx, -my, -mx0, -my0, 0,
- true, false,
- ROUND_JOIN_THRESHOLD);
- }
+// What we're trying to do in this function is to approximate an ideal
+// offset curve (call it I) of the input curve B using a bezier curve Bp.
+// The constraints I use to get the equations are:
+//
+// 1. The computed curve Bp should go through I(0) and I(1). These are
+// x1p, y1p, x4p, y4p, which are p1p and p4p. We still need to find
+// 4 variables: the x and y components of p2p and p3p (i.e. x2p, y2p, x3p, y3p).
+//
+// 2. Bp should have slope equal in absolute value to I at the endpoints. So,
+// (by the way, the operator || in the comments below means "aligned with".
+// It is defined on vectors, so when we say I'(0) || Bp'(0) we mean that
+// vectors I'(0) and Bp'(0) are aligned, which is the same as saying
+// that the tangent lines of I and Bp at 0 are parallel. Mathematically
+// this means (I'(t) || Bp'(t)) <==> (I'(t) = c * Bp'(t)) where c is some
+// nonzero constant.)
+// I'(0) || Bp'(0) and I'(1) || Bp'(1). Obviously, I'(0) || B'(0) and
+// I'(1) || B'(1); therefore, Bp'(0) || B'(0) and Bp'(1) || B'(1).
+// We know that Bp'(0) || (p2p-p1p) and Bp'(1) || (p4p-p3p) and the same
+// is true for any bezier curve; therefore, we get the equations
+// (1) p2p = c1 * (p2-p1) + p1p
+// (2) p3p = c2 * (p4-p3) + p4p
+// We know p1p, p4p, p2, p1, p3, and p4; therefore, this reduces the number
+// of unknowns from 4 to 2 (i.e. just c1 and c2).
+// To eliminate these 2 unknowns we use the following constraint:
+//
+// 3. Bp(0.5) == I(0.5). Bp(0.5)=(x,y) and I(0.5)=(xi,yi), and I should note
+// that I(0.5) is *the only* reason for computing dxm,dym. This gives us
+// (3) Bp(0.5) = (p1p + 3 * (p2p + p3p) + p4p)/8, which is equivalent to
+// (4) p2p + p3p = (Bp(0.5)*8 - p1p - p4p) / 3
+// We can substitute (1) and (2) from above into (4) and we get:
+// (5) c1*(p2-p1) + c2*(p4-p3) = (Bp(0.5)*8 - p1p - p4p)/3 - p1p - p4p
+// which is equivalent to
+// (6) c1*(p2-p1) + c2*(p4-p3) = (4/3) * (Bp(0.5) * 2 - p1p - p4p)
+//
+// The right side of this is a 2D vector, and we know I(0.5), which gives us
+// Bp(0.5), which gives us the value of the right side.
+// The left side is just a matrix vector multiplication in disguise. It is
+//
+// [x2-x1, x4-x3][c1]
+// [y2-y1, y4-y3][c2]
+// which, is equal to
+// [dx1, dx4][c1]
+// [dy1, dy4][c2]
+// At this point we are left with a simple linear system and we solve it by
+// getting the inverse of the matrix above. Then we use [c1,c2] to compute
+// p2p and p3p.
+
+ float x = 0.125f * (x1 + 3 * (x2 + x3) + x4);
+ float y = 0.125f * (y1 + 3 * (y2 + y3) + y4);
+ // (dxm,dym) is some tangent of B at t=0.5. This means it's equal to
+ // c*B'(0.5) for some constant c.
+ float dxm = x3 + x4 - x1 - x2, dym = y3 + y4 - y1 - y2;
+
+ // this computes the offsets at t=0, 0.5, 1, using the property that
+ // for any bezier curve the vectors p2-p1 and p4-p3 are parallel to
+ // the (dx/dt, dy/dt) vectors at the endpoints.
+ computeOffset(dx1, dy1, lineWidth2, offset[0]);
+ computeOffset(dxm, dym, lineWidth2, offset[1]);
+ computeOffset(dx4, dy4, lineWidth2, offset[2]);
+ float x1p = x1 + offset[0][0]; // start
+ float y1p = y1 + offset[0][1]; // point
+ float xi = x + offset[1][0]; // interpolation
+ float yi = y + offset[1][1]; // point
+ float x4p = x4 + offset[2][0]; // end
+ float y4p = y4 + offset[2][1]; // point
+
+ float invdet43 = 4f / (3f * (dx1 * dy4 - dy1 * dx4));
+
+ float two_pi_m_p1_m_p4x = 2*xi - x1p - x4p;
+ float two_pi_m_p1_m_p4y = 2*yi - y1p - y4p;
+ float c1 = invdet43 * (dy4 * two_pi_m_p1_m_p4x - dx4 * two_pi_m_p1_m_p4y);
+ float c2 = invdet43 * (dx1 * two_pi_m_p1_m_p4y - dy1 * two_pi_m_p1_m_p4x);
+
+ float x2p, y2p, x3p, y3p;
+ x2p = x1p + c1*dx1;
+ y2p = y1p + c1*dy1;
+ x3p = x4p + c2*dx4;
+ y3p = y4p + c2*dy4;
+
+ leftOff[0] = x1p; leftOff[1] = y1p;
+ leftOff[2] = x2p; leftOff[3] = y2p;
+ leftOff[4] = x3p; leftOff[5] = y3p;
+ leftOff[6] = x4p; leftOff[7] = y4p;
+
+ x1p = x1 - offset[0][0]; y1p = y1 - offset[0][1];
+ xi = xi - 2 * offset[1][0]; yi = yi - 2 * offset[1][1];
+ x4p = x4 - offset[2][0]; y4p = y4 - offset[2][1];
+
+ two_pi_m_p1_m_p4x = 2*xi - x1p - x4p;
+ two_pi_m_p1_m_p4y = 2*yi - y1p - y4p;
+ c1 = invdet43 * (dy4 * two_pi_m_p1_m_p4x - dx4 * two_pi_m_p1_m_p4y);
+ c2 = invdet43 * (dx1 * two_pi_m_p1_m_p4y - dy1 * two_pi_m_p1_m_p4x);
+
+ x2p = x1p + c1*dx1;
+ y2p = y1p + c1*dy1;
+ x3p = x4p + c2*dx4;
+ y3p = y4p + c2*dy4;
+
+ rightOff[0] = x1p; rightOff[1] = y1p;
+ rightOff[2] = x2p; rightOff[3] = y2p;
+ rightOff[4] = x3p; rightOff[5] = y3p;
+ rightOff[6] = x4p; rightOff[7] = y4p;
+ return 8;
+ }
+
+ // compute offset curves using bezier spline through t=0.5 (i.e.
+ // ComputedCurve(0.5) == IdealParallelCurve(0.5))
+ // return the kind of curve in the right and left arrays.
+ private int computeOffsetQuad(float[] pts, final int off,
+ float[] leftOff, float[] rightOff)
+ {
+ final float x1 = pts[off + 0], y1 = pts[off + 1];
+ final float x2 = pts[off + 2], y2 = pts[off + 3];
+ final float x3 = pts[off + 4], y3 = pts[off + 5];
+
+ float dx3 = x3 - x2;
+ float dy3 = y3 - y2;
+ float dx1 = x2 - x1;
+ float dy1 = y2 - y1;
+
+ // if p1=p2 or p3=p4 it means that the derivative at the endpoint
+ // vanishes, which creates problems with computeOffset. Usually
+ // this happens when this stroker object is trying to winden
+ // a curve with a cusp. What happens is that curveTo splits
+ // the input curve at the cusp, and passes it to this function.
+ // because of inaccuracies in the splitting, we consider points
+ // equal if they're very close to each other.
+
+ // if p1 == p2 && p3 == p4: draw line from p1->p4, unless p1 == p4,
+ // in which case ignore.
+ final boolean p1eqp2 = within(x1,y1,x2,y2, 6 * Math.ulp(y2));
+ final boolean p2eqp3 = within(x2,y2,x3,y3, 6 * Math.ulp(y3));
+ if (p1eqp2 || p2eqp3) {
+ getLineOffsets(x1, y1, x3, y3, leftOff, rightOff);
+ return 4;
}
- emitLineTo(sx0 - mx, sy0 - my);
- emitLineTo(x0 - mx, y0 - my);
- for (int i = rindex - 2; i >= 0; i -= 2) {
- emitLineTo(reverse[i], reverse[i + 1]);
+ // if p2-p1 and p4-p3 are parallel, that must mean this curve is a line
+ float dotsq = (dx1 * dx3 + dy1 * dy3);
+ dotsq = dotsq * dotsq;
+ float l1sq = dx1 * dx1 + dy1 * dy1, l3sq = dx3 * dx3 + dy3 * dy3;
+ if (Helpers.within(dotsq, l1sq * l3sq, 4 * Math.ulp(dotsq))) {
+ getLineOffsets(x1, y1, x3, y3, leftOff, rightOff);
+ return 4;
}
- this.x0 = this.sx0;
- this.y0 = this.sy0;
- this.rindex = 0;
- this.started = false;
- this.joinSegment = false;
- this.prev = CLOSE;
- emitClose();
+ // this computes the offsets at t=0, 0.5, 1, using the property that
+ // for any bezier curve the vectors p2-p1 and p4-p3 are parallel to
+ // the (dx/dt, dy/dt) vectors at the endpoints.
+ computeOffset(dx1, dy1, lineWidth2, offset[0]);
+ computeOffset(dx3, dy3, lineWidth2, offset[1]);
+ float x1p = x1 + offset[0][0]; // start
+ float y1p = y1 + offset[0][1]; // point
+ float x3p = x3 + offset[1][0]; // end
+ float y3p = y3 + offset[1][1]; // point
+
+ computeMiter(x1p, y1p, x1p+dx1, y1p+dy1, x3p, y3p, x3p-dx3, y3p-dy3, leftOff, 2);
+ leftOff[0] = x1p; leftOff[1] = y1p;
+ leftOff[4] = x3p; leftOff[5] = y3p;
+ x1p = x1 - offset[0][0]; y1p = y1 - offset[0][1];
+ x3p = x3 - offset[1][0]; y3p = y3 - offset[1][1];
+ computeMiter(x1p, y1p, x1p+dx1, y1p+dy1, x3p, y3p, x3p-dx3, y3p-dy3, rightOff, 2);
+ rightOff[0] = x1p; rightOff[1] = y1p;
+ rightOff[4] = x3p; rightOff[5] = y3p;
+ return 6;
}
- public void end() {
- // System.out.println("Stroker.end()");
+ // This is where the curve to be processed is put. We give it
+ // enough room to store 2 curves: one for the current subdivision, the
+ // other for the rest of the curve.
+ private float[][] middle = new float[2][8];
+ private float[] lp = new float[8];
+ private float[] rp = new float[8];
+ private static final int MAX_N_CURVES = 11;
+ private float[] subdivTs = new float[MAX_N_CURVES - 1];
+
+ private void somethingTo(final int type) {
+ // need these so we can update the state at the end of this method
+ final float xf = middle[0][type-2], yf = middle[0][type-1];
+ float dxs = middle[0][2] - middle[0][0];
+ float dys = middle[0][3] - middle[0][1];
+ float dxf = middle[0][type - 2] - middle[0][type - 4];
+ float dyf = middle[0][type - 1] - middle[0][type - 3];
+ switch(type) {
+ case 6:
+ if ((dxs == 0f && dys == 0f) ||
+ (dxf == 0f && dyf == 0f)) {
+ dxs = dxf = middle[0][4] - middle[0][0];
+ dys = dyf = middle[0][5] - middle[0][1];
+ }
+ break;
+ case 8:
+ boolean p1eqp2 = (dxs == 0f && dys == 0f);
+ boolean p3eqp4 = (dxf == 0f && dyf == 0f);
+ if (p1eqp2) {
+ dxs = middle[0][4] - middle[0][0];
+ dys = middle[0][5] - middle[0][1];
+ if (dxs == 0f && dys == 0f) {
+ dxs = middle[0][6] - middle[0][0];
+ dys = middle[0][7] - middle[0][1];
+ }
+ }
+ if (p3eqp4) {
+ dxf = middle[0][6] - middle[0][2];
+ dyf = middle[0][7] - middle[0][3];
+ if (dxf == 0f && dyf == 0f) {
+ dxf = middle[0][6] - middle[0][0];
+ dyf = middle[0][7] - middle[0][1];
+ }
+ }
+ }
+ if (dxs == 0f && dys == 0f) {
+ // this happens iff the "curve" is just a point
+ lineTo(middle[0][0], middle[0][1]);
+ return;
+ }
+ // if these vectors are too small, normalize them, to avoid future
+ // precision problems.
+ if (Math.abs(dxs) < 0.1f && Math.abs(dys) < 0.1f) {
+ double len = Math.hypot(dxs, dys);
+ dxs = (float)(dxs / len);
+ dys = (float)(dys / len);
+ }
+ if (Math.abs(dxf) < 0.1f && Math.abs(dyf) < 0.1f) {
+ double len = Math.hypot(dxf, dyf);
+ dxf = (float)(dxf / len);
+ dyf = (float)(dyf / len);
+ }
- if (lineToOrigin) {
- // not closing the path, do the previous lineTo
- lineToImpl(sx0, sy0, joinToOrigin);
- lineToOrigin = false;
+ computeOffset(dxs, dys, lineWidth2, offset[0]);
+ final float mx = offset[0][0];
+ final float my = offset[0][1];
+ drawJoin(cdx, cdy, cx0, cy0, dxs, dys, cmx, cmy, mx, my);
+
+ int nSplits = findSubdivPoints(middle[0], subdivTs, type,lineWidth2);
+
+ int kind = 0;
+ IteratorKeyTabEntry.
*/
public KeyTabEntry[] getEntries() {
- if (entries != null) {
- KeyTabEntry[] kentries = new KeyTabEntry[entries.size()];
- for (int i = 0; i < kentries.length; i++) {
- kentries[i] = entries.elementAt(i);
- }
- return kentries;
- } else {
- return null;
+ KeyTabEntry[] kentries = new KeyTabEntry[entries.size()];
+ for (int i = 0; i < kentries.length; i++) {
+ kentries[i] = entries.elementAt(i);
}
+ return kentries;
}
/**
@@ -464,29 +426,55 @@ public class KeyTab implements KeyTabConstants {
}
/**
- * Removes an entry from the key table.
+ * Removes entries from the key table.
* @param service the service PrincipalName.
- * @param etype the etype to match, first one if -1 provided
- * @return 1 if removed successfully, 0 otherwise
+ * @param etype the etype to match, remove all if -1
+ * @param kvno what kvno to remove, -1 for all, -2 for old
+ * @return the number of entries deleted
*/
- public int deleteEntry(PrincipalName service, int etype) {
- int result = retrieveEntry(service, etype);
- if (result != -1) {
- entries.removeElementAt(result);
- return 1;
+ public int deleteEntries(PrincipalName service, int etype, int kvno) {
+ int count = 0;
+
+ // Remember the highest KVNO for each etype. Used for kvno == -2
+ MapPrincipalName.
- * @return number of entries removed
- */
- public int deleteEntry(PrincipalName service) {
- int count = 0;
- while (deleteEntry(service, -1) > 0) {
- count++;
+ // Second round for kvno == -2, remove old entries
+ if (kvno == -2) {
+ for (int i = entries.size()-1; i >= 0; i--) {
+ KeyTabEntry e = entries.get(i);
+ if (service.match(e.getService())) {
+ if (etype == -1 || e.keyType == etype) {
+ int n = highest.get(e.keyType);
+ if (e.keyVersion != n) {
+ entries.removeElementAt(i);
+ count++;
+ }
+ }
+ }
+ }
}
return count;
}
diff --git a/src/share/classes/sun/security/pkcs11/SunPKCS11.java b/src/share/classes/sun/security/pkcs11/SunPKCS11.java
index 95be485b58a0a2fcef677e09bb46eb1287822e57..33691f87ef725f7c5a20788af6fc8b82f0d2e135 100644
--- a/src/share/classes/sun/security/pkcs11/SunPKCS11.java
+++ b/src/share/classes/sun/security/pkcs11/SunPKCS11.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -655,6 +655,25 @@ public final class SunPKCS11 extends AuthProvider {
d(SIG, "SHA512withRSA", P11Signature,
m(CKM_SHA512_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509));
+ /*
+ * TLS 1.2 uses a different hash algorithm than 1.0/1.1 for the
+ * PRF calculations. As of 2010, there is no PKCS11-level
+ * support for TLS 1.2 PRF calculations, and no known OS's have
+ * an internal variant we could use. Therefore for TLS 1.2, we
+ * are updating JSSE to request different provider algorithms
+ * (e.g. "SunTls12Prf"), and currently only SunJCE has these
+ * TLS 1.2 algorithms.
+ *
+ * If we reused the names such as "SunTlsPrf", the PKCS11
+ * providers would need be updated to fail correctly when
+ * presented with the wrong version number (via
+ * Provider.Service.supportsParameters()), and we would also
+ * need to add the appropriate supportsParamters() checks into
+ * KeyGenerators (not currently there).
+ *
+ * In the future, if PKCS11 support is added, we will restructure
+ * this.
+ */
d(KG, "SunTlsRsaPremasterSecret",
"sun.security.pkcs11.P11TlsRsaPremasterSecretGenerator",
m(CKM_SSL3_PRE_MASTER_KEY_GEN, CKM_TLS_PRE_MASTER_KEY_GEN));
@@ -887,7 +906,8 @@ public final class SunPKCS11 extends AuthProvider {
return (aliases == null) ? null : Arrays.asList(aliases);
}
- public Object newInstance(Object param) throws NoSuchAlgorithmException {
+ public Object newInstance(Object param)
+ throws NoSuchAlgorithmException {
if (token.isValid() == false) {
throw new NoSuchAlgorithmException("Token has been removed");
}
diff --git a/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java b/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java
index eb18820b2b8c9c0745ae0dbf781196ee7efd6a23..69e560ed4bf8489ea420808c9d73cf24af07893a 100644
--- a/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java
+++ b/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -25,95 +25,336 @@
package sun.security.provider.certpath;
-import java.util.Set;
+import java.security.AlgorithmConstraints;
+import java.security.CryptoPrimitive;
import java.util.Collection;
-import java.util.Locale;
+import java.util.Collections;
+import java.util.Set;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.math.BigInteger;
+import java.security.PublicKey;
+import java.security.KeyFactory;
+import java.security.AlgorithmParameters;
+import java.security.NoSuchAlgorithmException;
+import java.security.GeneralSecurityException;
import java.security.cert.Certificate;
-import java.security.cert.X509Certificate;
import java.security.cert.X509CRL;
-import java.security.cert.CertPathValidatorException;
+import java.security.cert.X509Certificate;
import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.TrustAnchor;
+import java.security.cert.CRLException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertPathValidatorException;
+import java.io.IOException;
+import java.security.interfaces.*;
+import java.security.spec.*;
+import sun.security.util.DisabledAlgorithmConstraints;
+import sun.security.x509.X509CertImpl;
+import sun.security.x509.X509CRLImpl;
import sun.security.x509.AlgorithmId;
/**
- * AlgorithmChecker is a PKIXCertPathChecker that checks that
- * the signature algorithm of the specified certificate is not disabled.
+ * A PKIXCertPathChecker implementation to check whether a
+ * specified certificate contains the required algorithm constraints.
+ * AlgorithmChecker with the algorithm
+ * constraints specified in security property
+ * "jdk.certpath.disabledAlgorithms".
+ *
+ * @param anchor the trust anchor selected to validate the target
+ * certificate
*/
- private AlgorithmChecker() {
- // do nothing
+ public AlgorithmChecker(TrustAnchor anchor) {
+ this(anchor, certPathDefaultConstraints);
}
/**
- * Return a AlgorithmChecker instance.
+ * Create a new AlgorithmChecker with the
+ * given {@code AlgorithmConstraints}.
+ * AlgorithmChecker with the
+ * given TrustAnchor and AlgorithmConstraints.
+ *
+ * @param anchor the trust anchor selected to validate the target
+ * certificate
+ * @param constraints the algorithm constraints (or null)
+ *
+ * @throws IllegalArgumentException if the anchor is null
*/
+ public AlgorithmChecker(TrustAnchor anchor,
+ AlgorithmConstraints constraints) {
+
+ if (anchor == null) {
+ throw new IllegalArgumentException(
+ "The trust anchor cannot be null");
+ }
+
+ if (anchor.getTrustedCert() != null) {
+ this.trustedPubKey = anchor.getTrustedCert().getPublicKey();
+ } else {
+ this.trustedPubKey = anchor.getCAPublicKey();
+ }
+
+ this.prevPubKey = trustedPubKey;
+ this.constraints = constraints;
+ }
+
+ @Override
public void init(boolean forward) throws CertPathValidatorException {
- // do nothing
+ // Note that this class does not support forward mode.
+ if (!forward) {
+ if (trustedPubKey != null) {
+ prevPubKey = trustedPubKey;
+ } else {
+ prevPubKey = null;
+ }
+ } else {
+ throw new
+ CertPathValidatorException("forward checking not supported");
+ }
}
+ @Override
public boolean isForwardCheckingSupported() {
+ // Note that as this class does not support forward mode, the method
+ // will always returns false.
return false;
}
+ @Override
public Set
+ * HandshakeHash hh = new HandshakeHash(...)
+ * hh.update(clientHelloBytes);
+ * hh.setFinishedAlg("SHA-256");
+ * hh.update(serverHelloBytes);
+ * ...
+ * hh.setCertificateVerifyAlg("SHA-384");
+ * hh.update(CertificateVerifyBytes);
+ * byte[] cvDigest = hh.getCertificateVerifyHash();
+ * ...
+ * hh.update(finished1);
+ * byte[] finDigest1 = hh.getFinishedHash();
+ * hh.update(finished2);
+ * byte[] finDigest2 = hh.getFinishedHash();
+ *
+ * If no CertificateVerify message is to be used, call
+ *
+ * hh.setCertificateVerifyAlg(null);
+ *
+ * This call can be made once you are certain that this message
+ * will never be used.
*/
final class HandshakeHash {
- private final MessageDigest md5, sha;
+ // Common
+
+ // -1: unknown
+ // 1: <=TLS 1.1
+ // 2: TLS 1.2
+ private int version = -1;
+ private ByteArrayOutputStream data = new ByteArrayOutputStream();
+ private final boolean isServer;
+
+ // For TLS 1.1
+ private MessageDigest md5, sha;
+ private final int clonesNeeded; // needs to be saved for later use
+
+ // For TLS 1.2
+ // cvAlgDetermined == true means setCertificateVerifyAlg() is called
+ private boolean cvAlgDetermined = false;
+ private String cvAlg;
+ private MessageDigest finMD;
/**
* Create a new HandshakeHash. needCertificateVerify indicates whether
- * a hash for the certificate verify message is required.
+ * a hash for the certificate verify message is required. The argument
+ * algs is a set of all possible hash algorithms that might be used in
+ * TLS 1.2. If the caller is sure that TLS 1.2 won't be used or no
+ * CertificateVerify message will be used, leave it null or empty.
*/
- HandshakeHash(boolean needCertificateVerify) {
- int n = needCertificateVerify ? 3 : 2;
- try {
- md5 = CloneableDigest.getDigest("MD5", n);
- sha = CloneableDigest.getDigest("SHA", n);
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException
- ("Algorithm MD5 or SHA not available", e);
-
- }
- }
-
- void update(byte b) {
- md5.update(b);
- sha.update(b);
+ HandshakeHash(boolean isServer, boolean needCertificateVerify,
+ SetprotocolVersion and the highest version of this
+ * protocol list, or null if no protocol version is available.
+ *
+ * The method is used by TLS server to negotiated the protocol
+ * version between client suggested protocol version in the
+ * client hello and protocol versions supported by the server.
+ */
+ ProtocolVersion selectProtocolVersion(ProtocolVersion protocolVersion) {
+ ProtocolVersion selectedVersion = null;
+ for (ProtocolVersion pv : protocols) {
+ if (pv.v > protocolVersion.v) {
+ break; // Safe to break here as this.protocols is sorted
+ }
+ selectedVersion = pv;
+ }
+
+ return selectedVersion;
+ }
+
/**
* Return an array with the names of the ProtocolVersions in this list.
*/
@@ -106,11 +156,18 @@ final class ProtocolList {
}
/**
- * Return the list of default enabled protocols. Currently, this
- * is identical to the supported protocols.
+ * Return the list of default enabled protocols.
*/
- static ProtocolList getDefault() {
- return SUPPORTED;
+ static ProtocolList getDefault(boolean isServer) {
+ return isServer ? SERVER_DEFAULT : CLIENT_DEFAULT;
+ }
+
+ /**
+ * Return whether a protocol list is the original default enabled
+ * protocols. See: SSLSocket/SSLEngine.setEnabledProtocols()
+ */
+ static boolean isDefaultProtocolList(ProtocolList protocols) {
+ return protocols == CLIENT_DEFAULT || protocols == SERVER_DEFAULT;
}
/**
@@ -123,6 +180,13 @@ final class ProtocolList {
static {
if (SunJSSE.isFIPS()) {
SUPPORTED = new ProtocolList(new String[] {
+ ProtocolVersion.TLS10.name,
+ ProtocolVersion.TLS11.name,
+ ProtocolVersion.TLS12.name
+ });
+
+ SERVER_DEFAULT = SUPPORTED;
+ CLIENT_DEFAULT = new ProtocolList(new String[] {
ProtocolVersion.TLS10.name
});
} else {
@@ -130,6 +194,24 @@ final class ProtocolList {
ProtocolVersion.SSL20Hello.name,
ProtocolVersion.SSL30.name,
ProtocolVersion.TLS10.name,
+ ProtocolVersion.TLS11.name,
+ ProtocolVersion.TLS12.name
+ });
+
+ SERVER_DEFAULT = SUPPORTED;
+
+ /*
+ * RFC 5246 says that sending SSLv2 backward-compatible
+ * hello SHOULD NOT be done any longer.
+ *
+ * We are not enabling TLS 1.1/1.2 by default yet on clients
+ * out of concern for interop with existing
+ * SSLv3/TLS1.0-only servers. When these versions of TLS
+ * gain more traction, we'll enable them.
+ */
+ CLIENT_DEFAULT = new ProtocolList(new String[] {
+ ProtocolVersion.SSL30.name,
+ ProtocolVersion.TLS10.name
});
}
}
diff --git a/src/share/classes/sun/security/ssl/ProtocolVersion.java b/src/share/classes/sun/security/ssl/ProtocolVersion.java
index 8cda729a97a9f00ff5e0346eb9287adfc40351fc..77c102a62901b166161e0420751ed026658d4871 100644
--- a/src/share/classes/sun/security/ssl/ProtocolVersion.java
+++ b/src/share/classes/sun/security/ssl/ProtocolVersion.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 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
@@ -45,9 +45,15 @@ package sun.security.ssl;
* @author Andreas Sterbenz
* @since 1.4.1
*/
-public final class ProtocolVersion {
+public final class ProtocolVersion implements ComparableSSLEngine.
@@ -1394,6 +1534,15 @@ final public class SSLEngineImpl extends SSLEngine {
return sess;
}
+ @Override
+ synchronized public SSLSession getHandshakeSession() {
+ return handshakeSession;
+ }
+
+ synchronized void setHandshakeSession(SSLSessionImpl session) {
+ handshakeSession = session;
+ }
+
/**
* Returns a delegated Runnable task for
* this SSLEngine.
@@ -1495,6 +1644,9 @@ final public class SSLEngineImpl extends SSLEngine {
inboundDone = true;
sess.invalidate();
+ if (handshakeSession != null) {
+ handshakeSession.invalidate();
+ }
/*
* If we haven't even started handshaking yet, no need
@@ -1594,10 +1746,18 @@ final public class SSLEngineImpl extends SSLEngine {
* Emit alerts. Caller must have synchronized with "this".
*/
private void sendAlert(byte level, byte description) {
+ // the connectionState cannot be cs_START
if (connectionState >= cs_CLOSED) {
return;
}
+ // For initial handshaking, don't send alert message to peer if
+ // handshaker has not started.
+ if (connectionState == cs_HANDSHAKE &&
+ (handshaker == null || !handshaker.started())) {
+ return;
+ }
+
EngineOutputRecord r = new EngineOutputRecord(Record.ct_alert, this);
r.setVersion(protocolVersion);
@@ -1647,7 +1807,7 @@ final public class SSLEngineImpl extends SSLEngine {
synchronized public void setEnableSessionCreation(boolean flag) {
enableSessionCreation = flag;
- if ((handshaker != null) && !handshaker.started()) {
+ if ((handshaker != null) && !handshaker.activated()) {
handshaker.setEnableSessionCreation(enableSessionCreation);
}
}
@@ -1675,7 +1835,7 @@ final public class SSLEngineImpl extends SSLEngine {
if ((handshaker != null) &&
(handshaker instanceof ServerHandshaker) &&
- !handshaker.started()) {
+ !handshaker.activated()) {
((ServerHandshaker) handshaker).setClientAuth(doClientAuth);
}
}
@@ -1698,7 +1858,7 @@ final public class SSLEngineImpl extends SSLEngine {
if ((handshaker != null) &&
(handshaker instanceof ServerHandshaker) &&
- !handshaker.started()) {
+ !handshaker.activated()) {
((ServerHandshaker) handshaker).setClientAuth(doClientAuth);
}
}
@@ -1717,6 +1877,16 @@ final public class SSLEngineImpl extends SSLEngine {
switch (connectionState) {
case cs_START:
+ /*
+ * If we need to change the engine mode and the enabled
+ * protocols haven't specifically been set by the user,
+ * change them to the corresponding default ones.
+ */
+ if (roleIsServer != (!flag) &&
+ ProtocolList.isDefaultProtocolList(enabledProtocols)) {
+ enabledProtocols = ProtocolList.getDefault(!flag);
+ }
+
roleIsServer = !flag;
serverModeSet = true;
break;
@@ -1730,7 +1900,17 @@ final public class SSLEngineImpl extends SSLEngine {
* have the streams.
*/
assert(handshaker != null);
- if (!handshaker.started()) {
+ if (!handshaker.activated()) {
+ /*
+ * If we need to change the engine mode and the enabled
+ * protocols haven't specifically been set by the user,
+ * change them to the corresponding default ones.
+ */
+ if (roleIsServer != (!flag) &&
+ ProtocolList.isDefaultProtocolList(enabledProtocols)) {
+ enabledProtocols = ProtocolList.getDefault(!flag);
+ }
+
roleIsServer = !flag;
connectionState = cs_START;
initHandshaker();
@@ -1786,8 +1966,8 @@ final public class SSLEngineImpl extends SSLEngine {
*/
synchronized public void setEnabledCipherSuites(String[] suites) {
enabledCipherSuites = new CipherSuiteList(suites);
- if ((handshaker != null) && !handshaker.started()) {
- handshaker.enabledCipherSuites = enabledCipherSuites;
+ if ((handshaker != null) && !handshaker.activated()) {
+ handshaker.setEnabledCipherSuites(enabledCipherSuites);
}
}
@@ -1809,7 +1989,7 @@ final public class SSLEngineImpl extends SSLEngine {
/**
* Returns the protocols that are supported by this implementation.
* A subset of the supported protocols may be enabled for this connection
- * @ returns an array of protocol names.
+ * @return an array of protocol names.
*/
public String[] getSupportedProtocols() {
return ProtocolList.getSupported().toStringArray();
@@ -1826,7 +2006,7 @@ final public class SSLEngineImpl extends SSLEngine {
*/
synchronized public void setEnabledProtocols(String[] protocols) {
enabledProtocols = new ProtocolList(protocols);
- if ((handshaker != null) && !handshaker.started()) {
+ if ((handshaker != null) && !handshaker.activated()) {
handshaker.setEnabledProtocols(enabledProtocols);
}
}
@@ -1836,28 +2016,31 @@ final public class SSLEngineImpl extends SSLEngine {
}
/**
- * Try to configure the endpoint identification algorithm of the engine.
- *
- * @param identificationAlgorithm the algorithm used to check the
- * endpoint identity.
- * @return true if the identification algorithm configuration success.
+ * Returns the SSLParameters in effect for this SSLEngine.
*/
- synchronized public boolean trySetHostnameVerification(
- String identificationAlgorithm) {
- if (sslContext.getX509TrustManager() instanceof
- X509ExtendedTrustManager) {
- this.identificationAlg = identificationAlgorithm;
- return true;
- } else {
- return false;
- }
+ synchronized public SSLParameters getSSLParameters() {
+ SSLParameters params = super.getSSLParameters();
+
+ // the super implementation does not handle the following parameters
+ params.setEndpointIdentificationAlgorithm(identificationProtocol);
+ params.setAlgorithmConstraints(algorithmConstraints);
+
+ return params;
}
/**
- * Returns the endpoint identification algorithm of the engine.
+ * Applies SSLParameters to this engine.
*/
- synchronized public String getHostnameVerification() {
- return identificationAlg;
+ synchronized public void setSSLParameters(SSLParameters params) {
+ super.setSSLParameters(params);
+
+ // the super implementation does not handle the following parameters
+ identificationProtocol = params.getEndpointIdentificationAlgorithm();
+ algorithmConstraints = params.getAlgorithmConstraints();
+ if ((handshaker != null) && !handshaker.started()) {
+ handshaker.setIdentificationProtocol(identificationProtocol);
+ handshaker.setAlgorithmConstraints(algorithmConstraints);
+ }
}
/**
diff --git a/src/share/classes/sun/security/ssl/SSLServerSocketImpl.java b/src/share/classes/sun/security/ssl/SSLServerSocketImpl.java
index 914406b2e4281d1672c8ca8a663801b8e74b4297..0ea3cfa9fbad805ca31047132bbc12405ddc32bb 100644
--- a/src/share/classes/sun/security/ssl/SSLServerSocketImpl.java
+++ b/src/share/classes/sun/security/ssl/SSLServerSocketImpl.java
@@ -31,11 +31,14 @@ import java.net.InetAddress;
import java.net.Socket;
import java.net.ServerSocket;
+import java.security.AlgorithmConstraints;
+
import java.util.*;
import javax.net.ServerSocketFactory;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLParameters;
/**
@@ -83,6 +86,12 @@ class SSLServerSocketImpl extends SSLServerSocket
/* could enabledCipherSuites ever complete handshaking? */
private boolean checkedEnabled = false;
+ // the endpoint identification protocol to use by default
+ private String identificationProtocol = null;
+
+ // The cryptographic algorithm constraints
+ private AlgorithmConstraints algorithmConstraints = null;
+
/**
* Create an SSL server socket on a port, using a non-default
* authentication context and a specified connection backlog.
@@ -145,7 +154,7 @@ class SSLServerSocketImpl extends SSLServerSocket
}
sslContext = context;
enabledCipherSuites = CipherSuiteList.getDefault();
- enabledProtocols = ProtocolList.getDefault();
+ enabledProtocols = ProtocolList.getDefault(true);
}
/**
@@ -238,6 +247,16 @@ class SSLServerSocketImpl extends SSLServerSocket
* rejoining the already-negotiated SSL connection.
*/
public void setUseClientMode(boolean flag) {
+ /*
+ * If we need to change the socket mode and the enabled
+ * protocols haven't specifically been set by the user,
+ * change them to the corresponding default ones.
+ */
+ if (useServerMode != (!flag) &&
+ ProtocolList.isDefaultProtocolList(enabledProtocols)) {
+ enabledProtocols = ProtocolList.getDefault(!flag);
+ }
+
useServerMode = !flag;
}
@@ -262,6 +281,29 @@ class SSLServerSocketImpl extends SSLServerSocket
return enableSessionCreation;
}
+ /**
+ * Returns the SSLParameters in effect for newly accepted connections.
+ */
+ synchronized public SSLParameters getSSLParameters() {
+ SSLParameters params = super.getSSLParameters();
+
+ // the super implementation does not handle the following parameters
+ params.setEndpointIdentificationAlgorithm(identificationProtocol);
+ params.setAlgorithmConstraints(algorithmConstraints);
+
+ return params;
+ }
+
+ /**
+ * Applies SSLParameters to newly accepted connections.
+ */
+ synchronized public void setSSLParameters(SSLParameters params) {
+ super.setSSLParameters(params);
+
+ // the super implementation does not handle the following parameters
+ identificationProtocol = params.getEndpointIdentificationAlgorithm();
+ algorithmConstraints = params.getAlgorithmConstraints();
+ }
/**
* Accept a new SSL connection. This server identifies itself with
@@ -269,67 +311,15 @@ class SSLServerSocketImpl extends SSLServerSocket
* presented during construction.
*/
public Socket accept() throws IOException {
- checkEnabledSuites();
-
SSLSocketImpl s = new SSLSocketImpl(sslContext, useServerMode,
enabledCipherSuites, doClientAuth, enableSessionCreation,
- enabledProtocols);
+ enabledProtocols, identificationProtocol, algorithmConstraints);
implAccept(s);
s.doneConnect();
return s;
}
-
- /*
- * This is a sometimes helpful diagnostic check that is performed
- * once for each ServerSocket to verify that the initial set of
- * enabled suites are capable of supporting a successful handshake.
- */
- private void checkEnabledSuites() throws IOException {
- //
- // We want to report an error if no cipher suites were actually
- // enabled, since this is an error users are known to make. Then
- // they get vastly confused by having clients report an error!
- //
- synchronized (this) {
- if (checkedEnabled) {
- return;
- }
- if (useServerMode == false) {
- return;
- }
-
- SSLSocketImpl tmp = new SSLSocketImpl(sslContext, useServerMode,
- enabledCipherSuites, doClientAuth,
- enableSessionCreation, enabledProtocols);
-
- try {
- ServerHandshaker handshaker = tmp.getServerHandshaker();
-
- for (Iterator