changeset 3014:bb30977193b0

Merge
author lana
date Tue, 09 Nov 2010 22:53:18 -0800
parents 565be51eb60e ddb39b2582b1
children b357910aa04a
files src/share/classes/java/nio/channels/AsynchronousDatagramChannel.java src/share/classes/sun/java2d/pisces/LineSink.java src/share/classes/sun/nio/ch/SimpleAsynchronousDatagramChannelImpl.java test/java/nio/channels/AsynchronousDatagramChannel/Basic.java
diffstat 275 files changed, 22754 insertions(+), 8211 deletions(-) [+]
line wrap: on
line diff
--- a/make/java/java/FILES_java.gmk	Tue Nov 09 11:45:00 2010 -0800
+++ b/make/java/java/FILES_java.gmk	Tue Nov 09 22:53:18 2010 -0800
@@ -413,6 +413,7 @@
     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 \
--- a/make/java/jli/Makefile	Tue Nov 09 11:45:00 2010 -0800
+++ b/make/java/jli/Makefile	Tue Nov 09 22:53:18 2010 -0800
@@ -148,14 +148,9 @@
 #
 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)
 
--- a/make/java/nio/FILES_java.gmk	Tue Nov 09 11:45:00 2010 -0800
+++ b/make/java/nio/FILES_java.gmk	Tue Nov 09 22:53:18 2010 -0800
@@ -33,7 +33,6 @@
 	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 @@
 	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 \
--- a/make/javax/sound/jsoundds/Makefile	Tue Nov 09 11:45:00 2010 -0800
+++ b/make/javax/sound/jsoundds/Makefile	Tue Nov 09 22:53:18 2010 -0800
@@ -53,7 +53,7 @@
 #
 # 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 \
--- a/make/netbeans/jmx/build.properties	Tue Nov 09 11:45:00 2010 -0800
+++ b/make/netbeans/jmx/build.properties	Tue Nov 09 22:53:18 2010 -0800
@@ -48,8 +48,8 @@
 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
--- a/make/sun/javazic/tzdata/VERSION	Tue Nov 09 11:45:00 2010 -0800
+++ b/make/sun/javazic/tzdata/VERSION	Tue Nov 09 22:53:18 2010 -0800
@@ -21,4 +21,4 @@
 # or visit www.oracle.com if you need additional information or have any
 # questions.
 #
-tzdata2010l
+tzdata2010o
--- a/make/sun/javazic/tzdata/asia	Tue Nov 09 11:45:00 2010 -0800
+++ b/make/sun/javazic/tzdata/asia	Tue Nov 09 22:53:18 2010 -0800
@@ -569,8 +569,8 @@
 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	-
--- a/make/sun/javazic/tzdata/australasia	Tue Nov 09 11:45:00 2010 -0800
+++ b/make/sun/javazic/tzdata/australasia	Tue Nov 09 22:53:18 2010 -0800
@@ -306,13 +306,26 @@
 # http://www.timeanddate.com/news/time/fiji-dst-ends-march-2010.html
 # </a>
 
+# 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:
+# <a href="http://www.fiji.gov.fj/index.php?option=com_content&view=article&id=2608:daylight-savings&catid=71:press-releases&Itemid=155">
+# http://www.fiji.gov.fj/index.php?option=com_content&view=article&id=2608:daylight-savings&catid=71:press-releases&Itemid=155
+# </a>
+# or
+# <a href="http://www.worldtimezone.com/dst_news/dst_news_fiji04.html">
+# http://www.worldtimezone.com/dst_news/dst_news_fiji04.html
+# </a>
+
 # 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 @@
 # http://www.parliament.gov.ws/documents/acts/Daylight%20Saving%20Act%20%202009%20%28English%29%20-%20Final%207-7-091.pdf
 # </a>
 
+# From Raymond Hughes (2010-10-07):
+# Please see
+# <a href="http://www.mcil.gov.ws">
+# http://www.mcil.gov.ws
+# </a>,
+# 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
--- a/make/sun/javazic/tzdata/zone.tab	Tue Nov 09 11:45:00 2010 -0800
+++ b/make/sun/javazic/tzdata/zone.tab	Tue Nov 09 22:53:18 2010 -0800
@@ -63,7 +63,7 @@
 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
--- a/src/share/bin/java.c	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/bin/java.c	Tue Nov 09 22:53:18 2010 -0800
@@ -355,7 +355,6 @@
 
     JavaVM *vm = 0;
     JNIEnv *env = 0;
-    jstring mainClassName;
     jclass mainClass;
     jmethodID mainID;
     jobjectArray mainArgs;
--- a/src/share/bin/parse_manifest.c	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/bin/parse_manifest.c	Tue Nov 09 22:53:18 2010 -0800
@@ -72,7 +72,7 @@
     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 @@
             return (NULL);
         }
         if (size_out) {
-            *size_out = entry->isize;
+            *size_out = (int)entry->isize;
         }
         return (out);
     } else
@@ -317,7 +317,7 @@
          * 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 @@
     }
     free(mp);
     close(fd);
-    if (rc == 0)
-        return (0);
-    else
-        return (-2);
+    return (rc == 0) ? 0 : -2;
 }
--- a/src/share/bin/wildcard.c	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/bin/wildcard.c	Tue Nov 09 22:53:18 2010 -0800
@@ -290,12 +290,12 @@
     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 @@
 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 @@
 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 @@
 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 @@
 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])) &&
--- a/src/share/classes/com/sun/crypto/provider/AESCrypt.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/com/sun/crypto/provider/AESCrypt.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 @@
             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++) {
--- a/src/share/classes/com/sun/crypto/provider/ARCFOURCipher.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/com/sun/crypto/provider/ARCFOURCipher.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 @@
     }
 
     // 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);
--- a/src/share/classes/com/sun/crypto/provider/DESedeCipher.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/com/sun/crypto/provider/DESedeCipher.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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.spec.*;
 
 /**
- * This class implements the DESede algorithm (DES-EDE, tripleDES) in its various
- * modes (<code>ECB</code>, <code>CFB</code>, <code>OFB</code>,
+ * This class implements the DESede algorithm (DES-EDE, tripleDES) in
+ * its various modes (<code>ECB</code>, <code>CFB</code>, <code>OFB</code>,
  * <code>CBC</code>, <code>PCBC</code>) and padding schemes
  * (<code>PKCS5Padding</code>, <code>NoPadding</code>,
  * <code>ISO10126Padding</code>).
--- a/src/share/classes/com/sun/crypto/provider/DHPrivateKey.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/com/sun/crypto/provider/DHPrivateKey.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 @@
             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 @@
             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;
         }
--- a/src/share/classes/com/sun/crypto/provider/DHPublicKey.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/com/sun/crypto/provider/DHPublicKey.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 @@
             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 @@
             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());
         }
     }
 
--- a/src/share/classes/com/sun/crypto/provider/JceKeyStore.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/com/sun/crypto/provider/JceKeyStore.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 @@
                                     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 @@
                     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");
                         }
                     }
                 }
--- a/src/share/classes/com/sun/crypto/provider/OAEPParameters.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/com/sun/crypto/provider/OAEPParameters.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 @@
                 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 @@
                 } 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
--- a/src/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 @@
         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 @@
                     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);
--- a/src/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 @@
                 (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 @@
             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);
--- a/src/share/classes/com/sun/crypto/provider/SunJCE.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/com/sun/crypto/provider/SunJCE.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 @@
 
                 /*
                  * 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");
+                        "com.sun.crypto.provider.TlsPrfGenerator$V10");
+                put("KeyGenerator.SunTls12Prf",
+                        "com.sun.crypto.provider.TlsPrfGenerator$V12");
+
+                put("KeyGenerator.SunTlsMasterSecret",
+                    "com.sun.crypto.provider.TlsMasterSecretGenerator");
+                put("Alg.Alias.KeyGenerator.SunTls12MasterSecret",
+                    "SunTlsMasterSecret");
+
+                put("KeyGenerator.SunTlsKeyMaterial",
+                    "com.sun.crypto.provider.TlsKeyMaterialGenerator");
+                put("Alg.Alias.KeyGenerator.SunTls12KeyMaterial",
+                    "SunTlsKeyMaterial");
+
                 put("KeyGenerator.SunTlsRsaPremasterSecret",
-                        "com.sun.crypto.provider.TlsRsaPremasterSecretGenerator");
-                put("KeyGenerator.SunTlsMasterSecret",
-                        "com.sun.crypto.provider.TlsMasterSecretGenerator");
-                put("KeyGenerator.SunTlsKeyMaterial",
-                        "com.sun.crypto.provider.TlsKeyMaterialGenerator");
+                    "com.sun.crypto.provider.TlsRsaPremasterSecretGenerator");
+                put("Alg.Alias.KeyGenerator.SunTls12RsaPremasterSecret",
+                    "SunTlsRsaPremasterSecret");
 
                 return null;
             }
--- a/src/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 @@
         }
         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 @@
 
     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 @@
         SecretKey clientMacKey = null;
         SecretKey serverMacKey = null;
         SecretKey clientCipherKey = null;
+        SecretKey serverCipherKey = null;
         IvParameterSpec clientIv = null;
-        SecretKey serverCipherKey = null;
         IvParameterSpec serverIv = null;
 
         int macLength = spec.getMacKeyLength();
@@ -109,21 +111,33 @@
         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 = doPRF(masterSecret, LABEL_KEY_EXPANSION, seed,
+            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 = 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 @@
 
         String alg = spec.getCipherAlgorithm();
 
+        // cipher keys
         byte[] clientKeyBytes = new byte[keyLength];
         System.arraycopy(keyBlock, ofs, clientKeyBytes, 0, keyLength);
         ofs += keyLength;
@@ -182,6 +197,7 @@
             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 @@
                 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 @@
                     serverIv = new IvParameterSpec(tmp);
                 }
             } else {
+                // SSLv3
                 tmp = new byte[expandedKeyLength];
 
                 md5.update(clientKeyBytes);
--- a/src/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 @@
         }
         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 @@
 
     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 @@
 
             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 @@
 
             }
 
-            return new TlsMasterSecretKey(master, premasterMajor, premasterMinor);
+            return new TlsMasterSecretKey(master, premasterMajor,
+                premasterMinor);
         } catch (NoSuchAlgorithmException e) {
             throw new ProviderException(e);
         } catch (DigestException e) {
--- a/src/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 @@
 
 /**
  * KeyGenerator implementation for the TLS PRF function.
+ * <p>
+ * 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 @@
      * 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 @@
         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 @@
         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 @@
         }
     }
 
-    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 @@
         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 @@
      * @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 @@
             }
             remaining -= k;
         }
-
     }
 
+    /**
+     * A KeyGenerator implementation that supports TLS 1.2.
+     * <p>
+     * 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);
+        }
+    }
 }
--- a/src/share/classes/com/sun/crypto/provider/TlsRsaPremasterSecretGenerator.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/com/sun/crypto/provider/TlsRsaPremasterSecretGenerator.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 @@
 
     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();
--- a/src/share/classes/com/sun/jmx/defaults/ServiceName.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/com/sun/jmx/defaults/ServiceName.java	Tue Nov 09 22:53:18 2010 -0800
@@ -76,9 +76,9 @@
     /**
      * The vendor of the JMX specification implemented by this product.
      * <BR>
-     * The value is <CODE>Sun Microsystems</CODE>.
+     * The value is <CODE>Oracle Corporation</CODE>.
      */
-    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 @@
      * The name of the vendor of this product implementing the
      * JMX specification.
      * <BR>
-     * The value is <CODE>Sun Microsystems</CODE>.
+     * The value is <CODE>Oracle Corporation</CODE>.
      */
-    public static final String JMX_IMPL_VENDOR = "Sun Microsystems";
+    public static final String JMX_IMPL_VENDOR = "Oracle Corporation";
 }
--- a/src/share/classes/com/sun/jmx/snmp/ServiceName.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/com/sun/jmx/snmp/ServiceName.java	Tue Nov 09 22:53:18 2010 -0800
@@ -27,7 +27,7 @@
 
 /**
  * Used for storing default values used by SNMP Runtime services.
- * <p><b>This API is a Sun Microsystems internal API  and is subject
+ * <p><b>This API is an Oracle Corporation internal API  and is subject
  * to change without notice.</b></p>
  */
 public class ServiceName {
@@ -144,16 +144,16 @@
     /**
      * The vendor of the JMX specification implemented by this product.
      * <BR>
-     * The value is <CODE>Sun Microsystems</CODE>.
+     * The value is <CODE>Oracle Corporation</CODE>.
      */
-    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.
      * <BR>
-     * The value is <CODE>Sun Microsystems</CODE>.
+     * The value is <CODE>Oracle Corporation</CODE>.
      */
-    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 <CODE>rXX</CODE>.
--- a/src/share/classes/com/sun/management/package.html	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/com/sun/management/package.html	Tue Nov 09 22:53:18 2010 -0800
@@ -30,7 +30,7 @@
 </head>
 <body bgcolor="white">
 
-This package contains Sun Microsystem's platform extension to
+This package contains Oracle Corporation's platform extension to
 the implementation of the
 <a href="{@docRoot}/../../../../api/java/lang/management/package-summary.html">
 java.lang.management</a> API and also defines the management
--- a/src/share/classes/java/awt/BasicStroke.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/awt/BasicStroke.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 <code>BasicStroke</code> class defines a basic set of rendering
  * attributes for the outlines of graphics primitives, which are rendered
@@ -183,6 +185,7 @@
      *         <code>dash</code> 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) {
--- a/src/share/classes/java/awt/GradientPaint.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/awt/GradientPaint.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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.Rectangle2D;
 import java.awt.geom.AffineTransform;
 import java.awt.image.ColorModel;
+import java.beans.ConstructorProperties;
 
 /**
  * The <code>GradientPaint</code> class provides a way to fill
@@ -166,6 +167,7 @@
      * @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,
--- a/src/share/classes/java/awt/GridBagConstraints.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/awt/GridBagConstraints.java	Tue Nov 09 22:53:18 2010 -0800
@@ -126,7 +126,7 @@
     /**
      * Place the component centered along the edge of its display area
      * associated with the start of a page for the current
-     * <code>ComponentOrienation</code>.  Equal to NORTH for horizontal
+     * {@code ComponentOrientation}.  Equal to NORTH for horizontal
      * orientations.
      */
     public static final int PAGE_START = 19;
@@ -134,7 +134,7 @@
     /**
      * Place the component centered along the edge of its display area
      * associated with the end of a page for the current
-     * <code>ComponentOrienation</code>.  Equal to SOUTH for horizontal
+     * {@code ComponentOrientation}.  Equal to SOUTH for horizontal
      * orientations.
      */
     public static final int PAGE_END = 20;
@@ -142,7 +142,7 @@
     /**
      * Place the component centered along the edge of its display area where
      * lines of text would normally begin for the current
-     * <code>ComponentOrienation</code>.  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 @@
     /**
      * Place the component centered along the edge of its display area where
      * lines of text would normally end for the current
-     * <code>ComponentOrienation</code>.  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 @@
     /**
      * 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
-     * <code>ComponentOrienation</code>.  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 @@
     /**
      * 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
-     * <code>ComponentOrienation</code>.  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 @@
     /**
      * 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
-     * <code>ComponentOrienation</code>.  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 @@
     /**
      * 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
-     * <code>ComponentOrienation</code>.  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 @@
      * <code>LINE_START</code>, <code>LINE_END</code>,
      * <code>FIRST_LINE_START</code>, <code>FIRST_LINE_END</code>,
      * <code>LAST_LINE_START</code> and <code>LAST_LINE_END</code>.  The
-     * baseline relvative values are:
+     * baseline relative values are:
      * <code>BASELINE</code>, <code>BASELINE_LEADING</code>,
      * <code>BASELINE_TRAILING</code>,
      * <code>ABOVE_BASELINE</code>, <code>ABOVE_BASELINE_LEADING</code>,
--- a/src/share/classes/java/awt/LinearGradientPaint.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/awt/LinearGradientPaint.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 @@
      * 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,
--- a/src/share/classes/java/awt/RadialGradientPaint.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/awt/RadialGradientPaint.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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.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 @@
      * 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,
--- a/src/share/classes/java/awt/Scrollbar.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/awt/Scrollbar.java	Tue Nov 09 22:53:18 2010 -0800
@@ -213,7 +213,8 @@
      * The size of the <code>Scrollbar</code>'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 @@
      * 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.
      * <p>
      * 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 @@
      * 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.
      * <p>
      * 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
--- a/src/share/classes/java/awt/Toolkit.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/awt/Toolkit.java	Tue Nov 09 22:53:18 2010 -0800
@@ -1831,7 +1831,11 @@
             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);
+        }
     }
 
     /**
--- a/src/share/classes/java/awt/geom/AffineTransform.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/awt/geom/AffineTransform.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 <code>AffineTransform</code> class represents a 2D affine transform
@@ -508,6 +509,7 @@
      * @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) {
--- a/src/share/classes/java/io/ObjectInputStream.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/io/ObjectInputStream.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 @@
      * 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 @@
     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 @@
                     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 @@
         }
     }
 
-    /**
-     * 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);
-        }
-    }
 }
--- a/src/share/classes/java/io/ObjectOutputStream.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/io/ObjectOutputStream.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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.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 @@
     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 @@
      *          <code>OutputStream</code>
      */
     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 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 @@
      * 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 @@
                 bout.writeByte(TC_ENDBLOCKDATA);
             }
         } finally {
+            curContext = oldContext;
             if (extendedDebugInfo) {
                 debugInfoStack.pop();
             }
         }
 
-        curObj = oldObj;
-        curDesc = oldDesc;
         curPut = oldPut;
     }
 
@@ -1461,12 +1465,9 @@
         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 @@
                         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);
--- a/src/share/classes/java/io/ObjectStreamClass.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/io/ObjectStreamClass.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 @@
         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 @@
         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<Class<?>> typeList = new ArrayList<Class<?>>();
+            Set<Long> usedKeys = new HashSet<Long>();
+
 
             for (int i = 0; i < nfields; i++) {
                 ObjectStreamField f = fields[i];
                 Field rf = f.getField();
-                keys[i] = (rf != null) ?
+                long key = (rf != null) ?
                     unsafe.objectFieldOffset(rf) : Unsafe.INVALID_FIELD_OFFSET;
+                readKeys[i] = key;
+                writeKeys[i] = usedKeys.add(key) ?
+                    key : Unsafe.INVALID_FIELD_OFFSET;
                 offsets[i] = f.getOffset();
                 typeCodes[i] = f.getTypeCode();
                 if (!f.isPrimitive()) {
@@ -1894,7 +1902,7 @@
              * in array should be equal to Unsafe.INVALID_FIELD_OFFSET.
              */
             for (int i = 0; i < numPrimFields; i++) {
-                long key = keys[i];
+                long key = readKeys[i];
                 int off = offsets[i];
                 switch (typeCodes[i]) {
                     case 'Z':
@@ -1945,7 +1953,7 @@
                 throw new NullPointerException();
             }
             for (int i = 0; i < numPrimFields; i++) {
-                long key = keys[i];
+                long key = writeKeys[i];
                 if (key == Unsafe.INVALID_FIELD_OFFSET) {
                     continue;           // discard value
                 }
@@ -2006,7 +2014,7 @@
                 switch (typeCodes[i]) {
                     case 'L':
                     case '[':
-                        vals[offsets[i]] = unsafe.getObject(obj, keys[i]);
+                        vals[offsets[i]] = unsafe.getObject(obj, readKeys[i]);
                         break;
 
                     default:
@@ -2027,7 +2035,7 @@
                 throw new NullPointerException();
             }
             for (int i = numPrimFields; i < fields.length; i++) {
-                long key = keys[i];
+                long key = writeKeys[i];
                 if (key == Unsafe.INVALID_FIELD_OFFSET) {
                     continue;           // discard value
                 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/io/SerialCallbackContext.java	Tue Nov 09 22:53:18 2010 -0800
@@ -0,0 +1,58 @@
+  /*
+   * %W% %E%
+   *
+   * Copyright (c) 2006, 2010  Oracle and/or its affiliates. All rights reserved.
+   * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
+   */
+
+  package java.io;
+
+  /**
+   * Context during upcalls from object stream to class-defined
+   * readObject/writeObject methods.
+   * Holds object currently being deserialized and descriptor for current class.
+   *
+   * This context keeps track of the thread it was constructed on, and allows
+   * only a single call of defaultReadObject, readFields, defaultWriteObject
+   * or writeFields which must be invoked on the same thread before the class's
+   * readObject/writeObject method has returned.
+   * If not set to the current thread, the getObj method throws NotActiveException.
+   */
+  final class SerialCallbackContext {
+      private final Object obj;
+      private final ObjectStreamClass desc;
+      /**
+       * Thread this context is in use by.
+       * As this only works in one thread, we do not need to worry about thread-safety.
+       */
+      private Thread thread;
+
+      public SerialCallbackContext(Object obj, ObjectStreamClass desc) {
+          this.obj = obj;
+          this.desc = desc;
+          this.thread = Thread.currentThread();
+      }
+
+      public Object getObj() throws NotActiveException {
+          checkAndSetUsed();
+          return obj;
+      }
+
+      public ObjectStreamClass getDesc() {
+          return desc;
+      }
+
+      private void checkAndSetUsed() throws NotActiveException {
+          if (thread != Thread.currentThread()) {
+               throw new NotActiveException(
+                "not in readObject invocation or fields already read");
+          }
+          thread = null;
+      }
+
+      public void setUsed() {
+          thread = null;
+      }
+  }
+
+
--- a/src/share/classes/java/lang/AbstractStringBuilder.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/lang/AbstractStringBuilder.java	Tue Nov 09 22:53:18 2010 -0800
@@ -100,7 +100,8 @@
      * @param   minimumCapacity   the minimum desired capacity.
      */
     public void ensureCapacity(int minimumCapacity) {
-        ensureCapacityInternal(minimumCapacity);
+        if (minimumCapacity > 0)
+            ensureCapacityInternal(minimumCapacity);
     }
 
     /**
@@ -108,6 +109,7 @@
      * never synchronized.
      */
     private void ensureCapacityInternal(int minimumCapacity) {
+        // overflow-conscious code
         if (minimumCapacity - value.length > 0)
             expandCapacity(minimumCapacity);
     }
--- a/src/share/classes/java/lang/ClassLoader.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/lang/ClassLoader.java	Tue Nov 09 22:53:18 2010 -0800
@@ -553,6 +553,13 @@
      *          If either <tt>off</tt> or <tt>len</tt> is negative, or if
      *          <tt>off+len</tt> is greater than <tt>b.length</tt>.
      *
+     * @throws  SecurityException
+     *          If an attempt is made to add this class to a package that
+     *          contains classes that were signed by a different set of
+     *          certificates than this class, or if an attempt is made
+     *          to define a class in a package with a fully-qualified name
+     *          that starts with "{@code java.}".
+     *
      * @see  #loadClass(String, boolean)
      * @see  #resolveClass(Class)
      *
--- a/src/share/classes/java/net/AbstractPlainSocketImpl.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/net/AbstractPlainSocketImpl.java	Tue Nov 09 22:53:18 2010 -0800
@@ -28,9 +28,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.io.InterruptedIOException;
 import java.io.FileDescriptor;
-import java.io.ByteArrayOutputStream;
 
 import sun.net.ConnectionResetException;
 import sun.net.NetHooks;
@@ -58,7 +56,7 @@
     protected int fdUseCount = 0;
 
     /* lock when increment/decrementing fdUseCount */
-    protected Object fdLock = new Object();
+    protected final Object fdLock = new Object();
 
     /* indicates a close is pending on the file descriptor */
     protected boolean closePending = false;
@@ -68,7 +66,7 @@
     private int CONNECTION_RESET_PENDING = 1;
     private int CONNECTION_RESET = 2;
     private int resetState;
-    private Object resetLock = new Object();
+    private final Object resetLock = new Object();
 
     /**
      * Load net library into runtime.
@@ -100,25 +98,24 @@
     protected void connect(String host, int port)
         throws UnknownHostException, IOException
     {
-        IOException pending = null;
+        boolean connected = false;
         try {
             InetAddress address = InetAddress.getByName(host);
             this.port = port;
             this.address = address;
 
-            try {
-                connectToAddress(address, port, timeout);
-                return;
-            } catch (IOException e) {
-                pending = e;
+            connectToAddress(address, port, timeout);
+            connected = true;
+        } finally {
+            if (!connected) {
+                try {
+                    close();
+                } catch (IOException ioe) {
+                    /* Do nothing. If connect threw an exception then
+                       it will be passed up the call stack */
+                }
             }
-        } catch (UnknownHostException e) {
-            pending = e;
         }
-
-        // everything failed
-        close();
-        throw pending;
     }
 
     /**
@@ -151,22 +148,29 @@
      *          SocketAddress subclass not supported by this socket
      * @since 1.4
      */
-    protected void connect(SocketAddress address, int timeout) throws IOException {
-        if (address == null || !(address instanceof InetSocketAddress))
-            throw new IllegalArgumentException("unsupported address type");
-        InetSocketAddress addr = (InetSocketAddress) address;
-        if (addr.isUnresolved())
-            throw new UnknownHostException(addr.getHostName());
-        this.port = addr.getPort();
-        this.address = addr.getAddress();
+    protected void connect(SocketAddress address, int timeout)
+            throws IOException {
+        boolean connected = false;
+        try {
+            if (address == null || !(address instanceof InetSocketAddress))
+                throw new IllegalArgumentException("unsupported address type");
+            InetSocketAddress addr = (InetSocketAddress) address;
+            if (addr.isUnresolved())
+                throw new UnknownHostException(addr.getHostName());
+            this.port = addr.getPort();
+            this.address = addr.getAddress();
 
-        try {
             connectToAddress(this.address, port, timeout);
-            return;
-        } catch (IOException e) {
-            // everything failed
-            close();
-            throw e;
+            connected = true;
+        } finally {
+            if (!connected) {
+                try {
+                    close();
+                } catch (IOException ioe) {
+                    /* Do nothing. If connect threw an exception then
+                       it will be passed up the call stack */
+                }
+            }
         }
     }
 
@@ -311,7 +315,7 @@
             }
         }
         try {
-            FileDescriptor fd = acquireFD();
+            acquireFD();
             try {
                 socketConnect(address, port, timeout);
                 /* socket may have been closed during poll/select */
@@ -370,7 +374,7 @@
      * @param s the connection
      */
     protected void accept(SocketImpl s) throws IOException {
-        FileDescriptor fd = acquireFD();
+        acquireFD();
         try {
             socketAccept(s);
         } finally {
@@ -562,7 +566,6 @@
         close();
     }
 
-
     /*
      * "Acquires" and returns the FileDescriptor for this impl
      *
--- a/src/share/classes/java/nio/Direct-X-Buffer.java.template	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/nio/Direct-X-Buffer.java.template	Tue Nov 09 22:53:18 2010 -0800
@@ -27,6 +27,7 @@
 
 package java.nio;
 
+import java.io.FileDescriptor;
 import sun.misc.Cleaner;
 import sun.misc.Unsafe;
 import sun.misc.VM;
@@ -114,7 +115,7 @@
     //
     Direct$Type$Buffer$RW$(int cap) {                   // package-private
 #if[rw]
-        super(-1, 0, cap, cap, false);
+        super(-1, 0, cap, cap);
         boolean pa = VM.isDirectMemoryPageAligned();
         int ps = Bits.pageSize();
         long size = Math.max(1L, (long)cap + (pa ? ps : 0));
@@ -145,7 +146,7 @@
     // Invoked only by JNI: NewDirectByteBuffer(void*, long)
     //
     private Direct$Type$Buffer(long addr, int cap) {
-        super(-1, 0, cap, cap, false);
+        super(-1, 0, cap, cap);
         address = addr;
         cleaner = null;
     }
@@ -154,14 +155,17 @@
 
     // For memory-mapped buffers -- invoked by FileChannelImpl via reflection
     //
-    protected Direct$Type$Buffer$RW$(int cap, long addr, Runnable unmapper) {
+    protected Direct$Type$Buffer$RW$(int cap, long addr,
+                                     FileDescriptor fd,
+                                     Runnable unmapper)
+    {
 #if[rw]
-        super(-1, 0, cap, cap, true);
+        super(-1, 0, cap, cap, fd);
         address = addr;
         viewedBuffer = null;
         cleaner = Cleaner.create(this, unmapper);
 #else[rw]
-        super(cap, addr, unmapper);
+        super(cap, addr, fd, unmapper);
 #end[rw]
     }
 
--- a/src/share/classes/java/nio/MappedByteBuffer.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/nio/MappedByteBuffer.java	Tue Nov 09 22:53:18 2010 -0800
@@ -25,6 +25,7 @@
 
 package java.nio;
 
+import java.io.FileDescriptor;
 import sun.misc.Unsafe;
 
 
@@ -71,26 +72,26 @@
     // for optimization purposes, it's easier to do it the other way around.
     // This works because DirectByteBuffer is a package-private class.
 
-    // Volatile to make sure that the finalization thread sees the current
-    // value of this so that a region is not accidentally unmapped again later.
-    volatile boolean isAMappedBuffer;                   // package-private
+    // For mapped buffers, a FileDescriptor that may be used for mapping
+    // operations if valid; null if the buffer is not mapped.
+    private final FileDescriptor fd;
 
     // This should only be invoked by the DirectByteBuffer constructors
     //
     MappedByteBuffer(int mark, int pos, int lim, int cap, // package-private
-                     boolean mapped)
+                     FileDescriptor fd)
     {
         super(mark, pos, lim, cap);
-        isAMappedBuffer = mapped;
+        this.fd = fd;
     }
 
     MappedByteBuffer(int mark, int pos, int lim, int cap) { // package-private
         super(mark, pos, lim, cap);
-        isAMappedBuffer = false;
+        this.fd = null;
     }
 
     private void checkMapped() {
-        if (!isAMappedBuffer)
+        if (fd == null)
             // Can only happen if a luser explicitly casts a direct byte buffer
             throw new UnsupportedOperationException();
     }
@@ -191,13 +192,12 @@
         checkMapped();
         if ((address != 0) && (capacity() != 0)) {
             long offset = mappingOffset();
-            force0(mappingAddress(offset), mappingLength(offset));
+            force0(fd, mappingAddress(offset), mappingLength(offset));
         }
         return this;
     }
 
     private native boolean isLoaded0(long address, long length, int pageCount);
     private native void load0(long address, long length);
-    private native void force0(long address, long length);
-
+    private native void force0(FileDescriptor fd, long address, long length);
 }
--- a/src/share/classes/java/nio/channels/AsynchronousDatagramChannel.java	Tue Nov 09 11:45:00 2010 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,572 +0,0 @@
-/*
- * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  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.nio.channels;
-
-import java.nio.channels.spi.*;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.Future;
-import java.io.IOException;
-import java.net.SocketOption;
-import java.net.SocketAddress;
-import java.net.ProtocolFamily;
-import java.nio.ByteBuffer;
-
-/**
- * An asynchronous channel for datagram-oriented sockets.
- *
- * <p> 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.
- *
- * <p> 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:
- * <blockquote>
- * <table border>
- *   <tr>
- *     <th>Option Name</th>
- *     <th>Description</th>
- *   </tr>
- *   <tr>
- *     <td> {@link java.net.StandardSocketOption#SO_SNDBUF SO_SNDBUF} </td>
- *     <td> The size of the socket send buffer </td>
- *   </tr>
- *   <tr>
- *     <td> {@link java.net.StandardSocketOption#SO_RCVBUF SO_RCVBUF} </td>
- *     <td> The size of the socket receive buffer </td>
- *   </tr>
- *   <tr>
- *     <td> {@link java.net.StandardSocketOption#SO_REUSEADDR SO_REUSEADDR} </td>
- *     <td> Re-use address </td>
- *   </tr>
- *   <tr>
- *     <td> {@link java.net.StandardSocketOption#SO_BROADCAST SO_BROADCAST} </td>
- *     <td> Allow transmission of broadcast datagrams </td>
- *   </tr>
- *   <tr>
- *     <td> {@link java.net.StandardSocketOption#IP_TOS IP_TOS} </td>
- *     <td> The Type of Service (ToS) octet in the Internet Protocol (IP) header </td>
- *   </tr>
- *   <tr>
- *     <td> {@link java.net.StandardSocketOption#IP_MULTICAST_IF IP_MULTICAST_IF} </td>
- *     <td> The network interface for Internet Protocol (IP) multicast datagrams </td>
- *   </tr>
- *   <tr>
- *     <td> {@link java.net.StandardSocketOption#IP_MULTICAST_TTL
- *       IP_MULTICAST_TTL} </td>
- *     <td> The <em>time-to-live</em> for Internet Protocol (IP) multicast
- *       datagrams </td>
- *   </tr>
- *   <tr>
- *     <td> {@link java.net.StandardSocketOption#IP_MULTICAST_LOOP
- *       IP_MULTICAST_LOOP} </td>
- *     <td> Loopback for Internet Protocol (IP) multicast datagrams </td>
- *   </tr>
- * </table>
- * </blockquote>
- * Additional (implementation specific) options may also be supported.
- *
- * <p> Asynchronous datagram channels allow more than one read/receive and
- * write/send to be oustanding at any given time.
- *
- * <p> <b>Usage Example:</b>
- * <pre>
- *  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&lt;SocketAddress,ByteBuffer&gt;() {
- *      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) {
- *          ...
- *      }
- *  });
- * </pre>
- *
- * @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.
-     *
-     * <p> 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}).
-     *
-     * <p> 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.
-     *
-     * <p> This method returns an asynchronous datagram channel that is
-     * bound to the <em>default group</em>. This method is equivalent to evaluating
-     * the expression:
-     * <blockquote><pre>
-     * open((ProtocolFamily)null,&nbsp;(AsynchronousChannelGroup)null);
-     * </pre></blockquote>
-     *
-     * @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 <T> AsynchronousDatagramChannel setOption(SocketOption<T> name, T value)
-        throws IOException;
-
-    /**
-     * Returns the remote address to which this channel is connected.
-     *
-     * <p> 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.
-     *
-     * <p> The channel's socket is configured so that it only receives
-     * datagrams from, and sends datagrams to, the given remote <i>peer</i>
-     * 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.
-     *
-     * <p> 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.
-     *
-     * <p> 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.
-     *
-     * <p> 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.
-     *
-     * <p> 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.
-     *
-     * <p> 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.
-     *
-     * <p> 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.
-     *
-     * <p> 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.
-     *
-     * <p> 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 <A> void receive(ByteBuffer dst,
-                                     long timeout,
-                                     TimeUnit unit,
-                                     A attachment,
-                                     CompletionHandler<SocketAddress,? super A> handler);
-
-    /**
-     * Receives a datagram via this channel.
-     *
-     * <p> 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.
-     *
-     * <p> 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 <A> void receive(ByteBuffer dst,
-                                  A attachment,
-                                  CompletionHandler<SocketAddress,? super A> handler)
-    {
-        receive(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler);
-    }
-
-    /**
-     * Receives a datagram via this channel.
-     *
-     * <p> 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<SocketAddress> receive(ByteBuffer dst);
-
-    /**
-     * Sends a datagram via this channel.
-     *
-     * <p> 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.
-     *
-     * <p> 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 <A> void send(ByteBuffer src,
-                                  SocketAddress target,
-                                  A attachment,
-                                  CompletionHandler<Integer,? super A> handler);
-
-    /**
-     * Sends a datagram via this channel.
-     *
-     * <p> 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<Integer> send(ByteBuffer src, SocketAddress target);
-
-    /**
-     * Receives a datagram via this channel.
-     *
-     * <p> 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.
-     *
-     * <p> 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.
-     *
-     * <p> 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 <A> void read(ByteBuffer dst,
-                                  long timeout,
-                                  TimeUnit unit,
-                                  A attachment,
-                                  CompletionHandler<Integer,? super A> handler);
-
-    /**
-     * @throws  NotYetConnectedException
-     *          If this channel is not connected
-     * @throws  ShutdownChannelGroupException
-     *          If the channel group has terminated
-     */
-    @Override
-    public final <A> void read(ByteBuffer dst,
-                               A attachment,
-                               CompletionHandler<Integer,? super A> handler)
-    {
-        read(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler);
-    }
-
-    /**
-     * @throws  NotYetConnectedException
-     *          If this channel is not connected
-     * @throws  ShutdownChannelGroupException
-     *          If the channel group has terminated
-     */
-    @Override
-    public abstract Future<Integer> read(ByteBuffer dst);
-
-    /**
-     * @throws  NotYetConnectedException
-     *          If this channel is not connected
-     * @throws  ShutdownChannelGroupException
-     *          If the channel group has terminated
-     */
-    @Override
-    public abstract <A> void  write(ByteBuffer src,
-                                    A attachment,
-                                    CompletionHandler<Integer,? super A> handler);
-
-
-    /**
-     * @throws  NotYetConnectedException
-     *          If this channel is not connected
-     * @throws  ShutdownChannelGroupException
-     *          If the channel group has terminated
-     */
-    @Override
-    public abstract Future<Integer> write(ByteBuffer src);
-}
--- a/src/share/classes/java/nio/channels/package-info.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/nio/channels/package-info.java	Tue Nov 09 22:53:18 2010 -0800
@@ -232,8 +232,6 @@
  *     <td>An asynchronous channel to a stream-oriented connecting socket</td></tr>
  * <tr><td valign=top><tt>{@link java.nio.channels.AsynchronousServerSocketChannel}&nbsp;&nbsp;</tt></td>
  *     <td>An asynchronous channel to a stream-oriented listening socket</td></tr>
- * <tr><td valign=top><tt>{@link java.nio.channels.AsynchronousDatagramChannel}</tt></td>
- *     <td>An asynchronous channel to a datagram-oriented socket</td></tr>
  * <tr><td valign=top><tt>{@link java.nio.channels.CompletionHandler}</tt></td>
  *     <td>A handler for consuming the result of an asynchronous operation</td></tr>
  * <tr><td valign=top><tt>{@link java.nio.channels.AsynchronousChannelGroup}</tt></td>
--- a/src/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 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;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/security/AlgorithmConstraints.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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.
+ * <p>
+ * {@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.
+ * <p>
+ * 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<CryptoPrimitive> primitives,
+            String algorithm, AlgorithmParameters parameters);
+
+    /**
+     * Determines whether a key is granted permission for the specified
+     * cryptographic primitives.
+     * <p>
+     * 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<CryptoPrimitive> primitives, Key key);
+
+    /**
+     * Determines whether an algorithm and the corresponding key are granted
+     * permission for the specified cryptographic primitives.
+     *
+     * @param primitives a set of cryptographic primitives
+     * @param algorithm the algorithm name
+     * @param key the key
+     * @param parameters the algorithm parameters, or null if no additional
+     *     parameters
+     *
+     * @return true if the key and the algorithm can be used for all of the
+     *     specified cryptographic primitives
+     *
+     * @throws IllegalArgumentException if primitives or algorithm is null
+     *     or empty, or the key is null
+     */
+    public boolean permits(Set<CryptoPrimitive> primitives,
+                String algorithm, Key key, AlgorithmParameters parameters);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/security/CryptoPrimitive.java	Tue Nov 09 22:53:18 2010 -0800
@@ -0,0 +1,83 @@
+/*
+ * 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;
+
+/**
+ * An enumeration of cryptographic primitives.
+ *
+ * @since 1.7
+ */
+public enum CryptoPrimitive {
+    /**
+     * Hash function
+     */
+    MESSAGE_DIGEST,
+
+    /**
+     * Cryptographic random number generator
+     */
+    SECURE_RANDOM,
+
+    /**
+     * Symmetric primitive: block cipher
+     */
+    BLOCK_CIPHER,
+
+    /**
+     * Symmetric primitive: stream cipher
+     */
+    STREAM_CIPHER,
+
+    /**
+     * Symmetric primitive: message authentication code
+     */
+    MAC,
+
+    /**
+     * Symmetric primitive: key wrap
+     */
+    KEY_WRAP,
+
+    /**
+     * Asymmetric primitive: public key encryption
+     */
+    PUBLIC_KEY_ENCRYPTION,
+
+    /**
+     * Asymmetric primitive: signature scheme
+     */
+    SIGNATURE,
+
+    /**
+     * Asymmetric primitive: key encapsulation mechanism
+     */
+    KEY_ENCAPSULATION,
+
+    /**
+     * Asymmetric primitive: key agreement and key distribution
+     */
+    KEY_AGREEMENT
+}
--- a/src/share/classes/java/text/DateFormatSymbols.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/text/DateFormatSymbols.java	Tue Nov 09 22:53:18 2010 -0800
@@ -44,11 +44,12 @@
 import java.lang.ref.SoftReference;
 import java.text.spi.DateFormatSymbolsProvider;
 import java.util.Arrays;
-import java.util.Hashtable;
 import java.util.List;
 import java.util.Locale;
 import java.util.ResourceBundle;
 import java.util.TimeZone;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 import java.util.spi.LocaleServiceProvider;
 import sun.util.LocaleServiceProviderPool;
 import sun.util.TimeZoneNameUtility;
@@ -321,20 +322,64 @@
      * @since 1.6
      */
     public static final DateFormatSymbols getInstance(Locale locale) {
+        DateFormatSymbols dfs = getProviderInstance(locale);
+        if (dfs != null) {
+            return dfs;
+        }
+        return (DateFormatSymbols) getCachedInstance(locale).clone();
+    }
+
+    /**
+     * Returns a DateFormatSymbols provided by a provider or found in
+     * the cache. Note that this method returns a cached instance,
+     * not its clone. Therefore, the instance should never be given to
+     * an application.
+     */
+    static final DateFormatSymbols getInstanceRef(Locale locale) {
+        DateFormatSymbols dfs = getProviderInstance(locale);
+        if (dfs != null) {
+            return dfs;
+        }
+        return getCachedInstance(locale);
+    }
+
+    private static DateFormatSymbols getProviderInstance(Locale locale) {
+        DateFormatSymbols providersInstance = null;
 
         // Check whether a provider can provide an implementation that's closer
         // to the requested locale than what the Java runtime itself can provide.
         LocaleServiceProviderPool pool =
             LocaleServiceProviderPool.getPool(DateFormatSymbolsProvider.class);
         if (pool.hasProviders()) {
-            DateFormatSymbols providersInstance = pool.getLocalizedObject(
-                                DateFormatSymbolsGetter.INSTANCE, locale);
-            if (providersInstance != null) {
-                return providersInstance;
+            providersInstance = pool.getLocalizedObject(
+                                    DateFormatSymbolsGetter.INSTANCE, locale);
+        }
+        return providersInstance;
+    }
+
+    /**
+     * Returns a cached DateFormatSymbols if it's found in the
+     * cache. Otherwise, this method returns a newly cached instance
+     * for the given locale.
+     */
+    private static DateFormatSymbols getCachedInstance(Locale locale) {
+        SoftReference<DateFormatSymbols> ref = cachedInstances.get(locale);
+        DateFormatSymbols dfs = null;
+        if (ref == null || (dfs = ref.get()) == null) {
+            dfs = new DateFormatSymbols(locale);
+            ref = new SoftReference<DateFormatSymbols>(dfs);
+            SoftReference<DateFormatSymbols> x = cachedInstances.putIfAbsent(locale, ref);
+            if (x != null) {
+                DateFormatSymbols y = x.get();
+                if (y != null) {
+                    dfs = y;
+                } else {
+                    // Replace the empty SoftReference with ref.
+                    cachedInstances.put(locale, ref);
+                }
             }
         }
-
-        return new DateFormatSymbols(locale);
+        return dfs;
     }
 
     /**
@@ -597,56 +642,44 @@
     static final int millisPerHour = 60*60*1000;
 
     /**
-     * Cache to hold the FormatData and TimeZoneNames ResourceBundles
-     * of a Locale.
+     * Cache to hold DateFormatSymbols instances per Locale.
      */
-    private static Hashtable cachedLocaleData = new Hashtable(3);
-
-    /**
-     * Look up resource data for the desiredLocale in the cache; update the
-     * cache if necessary.
-     */
-    private static ResourceBundle cacheLookup(Locale desiredLocale) {
-        ResourceBundle rb;
-        SoftReference data
-            = (SoftReference)cachedLocaleData.get(desiredLocale);
-        if (data == null) {
-            rb = LocaleData.getDateFormatData(desiredLocale);
-            data = new SoftReference(rb);
-            cachedLocaleData.put(desiredLocale, data);
-        } else {
-            if ((rb = (ResourceBundle)data.get()) == null) {
-                rb = LocaleData.getDateFormatData(desiredLocale);
-                data = new SoftReference(rb);
-            }
-        }
-        return rb;
-    }
+    private static final ConcurrentMap<Locale, SoftReference<DateFormatSymbols>> cachedInstances
+        = new ConcurrentHashMap<Locale, SoftReference<DateFormatSymbols>>(3);
 
     private void initializeData(Locale desiredLocale) {
-        int i;
-        ResourceBundle resource = cacheLookup(desiredLocale);
+        locale = desiredLocale;
 
-        // FIXME: cache only ResourceBundle. Hence every time, will do
-        // getObject(). This won't be necessary if the Resource itself
-        // is cached.
-        eras = (String[])resource.getObject("Eras");
+        // Copy values of a cached instance if any.
+        SoftReference<DateFormatSymbols> ref = cachedInstances.get(locale);
+        DateFormatSymbols dfs;
+        if (ref != null && (dfs = ref.get()) != null) {
+            copyMembers(dfs, this);
+            return;
+        }
+
+        // Initialize the fields from the ResourceBundle for locale.
+        ResourceBundle resource = LocaleData.getDateFormatData(locale);
+
+        eras = resource.getStringArray("Eras");
         months = resource.getStringArray("MonthNames");
         shortMonths = resource.getStringArray("MonthAbbreviations");
-        String[] lWeekdays = resource.getStringArray("DayNames");
-        weekdays = new String[8];
-        weekdays[0] = "";  // 1-based
-        for (i=0; i<lWeekdays.length; i++)
-            weekdays[i+1] = lWeekdays[i];
-        String[] sWeekdays = resource.getStringArray("DayAbbreviations");
-        shortWeekdays = new String[8];
-        shortWeekdays[0] = "";  // 1-based
-        for (i=0; i<sWeekdays.length; i++)
-            shortWeekdays[i+1] = sWeekdays[i];
         ampms = resource.getStringArray("AmPmMarkers");
         localPatternChars = resource.getString("DateTimePatternChars");
 
-        locale = desiredLocale;
+        // Day of week names are stored in a 1-based array.
+        weekdays = toOneBasedArray(resource.getStringArray("DayNames"));
+        shortWeekdays = toOneBasedArray(resource.getStringArray("DayAbbreviations"));
+    }
+
+    private static String[] toOneBasedArray(String[] src) {
+        int len = src.length;
+        String[] dst = new String[len + 1];
+        dst[0] = "";
+        for (int i = 0; i < len; i++) {
+            dst[i + 1] = src[i];
+        }
+        return dst;
     }
 
     /**
--- a/src/share/classes/java/text/DecimalFormat.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/text/DecimalFormat.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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
@@ -46,9 +46,10 @@
 import java.math.RoundingMode;
 import java.util.ArrayList;
 import java.util.Currency;
-import java.util.Hashtable;
 import java.util.Locale;
 import java.util.ResourceBundle;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 import sun.util.resources.LocaleData;
@@ -394,14 +395,14 @@
     public DecimalFormat() {
         Locale def = Locale.getDefault(Locale.Category.FORMAT);
         // try to get the pattern from the cache
-        String pattern = (String) cachedLocaleData.get(def);
+        String pattern = cachedLocaleData.get(def);
         if (pattern == null) {  /* cache miss */
             // Get the pattern for the default locale.
             ResourceBundle rb = LocaleData.getNumberFormatData(def);
             String[] all = rb.getStringArray("NumberPatterns");
             pattern = all[0];
             /* update cache */
-            cachedLocaleData.put(def, pattern);
+            cachedLocaleData.putIfAbsent(def, pattern);
         }
 
         // Always applyPattern after the symbols are set
@@ -3272,5 +3273,6 @@
     /**
      * Cache to hold the NumberPattern of a Locale.
      */
-    private static Hashtable cachedLocaleData = new Hashtable(3);
+    private static final ConcurrentMap<Locale, String> cachedLocaleData
+        = new ConcurrentHashMap<Locale, String>(3);
 }
--- a/src/share/classes/java/text/SimpleDateFormat.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/text/SimpleDateFormat.java	Tue Nov 09 22:53:18 2010 -0800
@@ -44,13 +44,14 @@
 import java.util.Calendar;
 import java.util.Date;
 import java.util.GregorianCalendar;
-import java.util.Hashtable;
 import java.util.Locale;
 import java.util.Map;
 import java.util.MissingResourceException;
 import java.util.ResourceBundle;
 import java.util.SimpleTimeZone;
 import java.util.TimeZone;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 import sun.util.calendar.CalendarUtils;
 import sun.util.calendar.ZoneInfoFile;
 import sun.util.resources.LocaleData;
@@ -503,14 +504,14 @@
     /**
      * Cache to hold the DateTimePatterns of a Locale.
      */
-    private static Hashtable<String,String[]> cachedLocaleData
-        = new Hashtable<String,String[]>(3);
+    private static final ConcurrentMap<String, String[]> cachedLocaleData
+        = new ConcurrentHashMap<String, String[]>(3);
 
     /**
      * Cache NumberFormat instances with Locale key.
      */
-    private static Hashtable<Locale,NumberFormat> cachedNumberFormatData
-        = new Hashtable<Locale,NumberFormat>(3);
+    private static final ConcurrentMap<Locale, NumberFormat> cachedNumberFormatData
+        = new ConcurrentHashMap<Locale, NumberFormat>(3);
 
     /**
      * The Locale used to instantiate this
@@ -579,7 +580,7 @@
 
         initializeCalendar(locale);
         this.pattern = pattern;
-        this.formatData = DateFormatSymbols.getInstance(locale);
+        this.formatData = DateFormatSymbols.getInstanceRef(locale);
         this.locale = locale;
         initialize(locale);
     }
@@ -632,9 +633,9 @@
                 dateTimePatterns = r.getStringArray("DateTimePatterns");
             }
             /* update cache */
-            cachedLocaleData.put(key, dateTimePatterns);
+            cachedLocaleData.putIfAbsent(key, dateTimePatterns);
         }
-        formatData = DateFormatSymbols.getInstance(loc);
+        formatData = DateFormatSymbols.getInstanceRef(loc);
         if ((timeStyle >= 0) && (dateStyle >= 0)) {
             Object[] dateTimeArgs = {dateTimePatterns[timeStyle],
                                      dateTimePatterns[dateStyle + 4]};
@@ -665,7 +666,7 @@
             numberFormat.setGroupingUsed(false);
 
             /* update cache */
-            cachedNumberFormatData.put(loc, numberFormat);
+            cachedNumberFormatData.putIfAbsent(loc, numberFormat);
         }
         numberFormat = (NumberFormat) numberFormat.clone();
 
@@ -897,7 +898,7 @@
      * so we can call it from readObject().
      */
     private void initializeDefaultCentury() {
-        calendar.setTime( new Date() );
+        calendar.setTimeInMillis(System.currentTimeMillis());
         calendar.add( Calendar.YEAR, -80 );
         parseAmbiguousDatesAsAfter(calendar.getTime());
     }
@@ -921,7 +922,7 @@
      * @since 1.2
      */
     public void set2DigitYearStart(Date startDate) {
-        parseAmbiguousDatesAsAfter(startDate);
+        parseAmbiguousDatesAsAfter(new Date(startDate.getTime()));
     }
 
     /**
@@ -934,7 +935,7 @@
      * @since 1.2
      */
     public Date get2DigitYearStart() {
-        return defaultCenturyStart;
+        return (Date) defaultCenturyStart.clone();
     }
 
     /**
--- a/src/share/classes/java/util/ArrayList.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/util/ArrayList.java	Tue Nov 09 22:53:18 2010 -0800
@@ -176,6 +176,11 @@
      * @param minCapacity the desired minimum capacity
      */
     public void ensureCapacity(int minCapacity) {
+        if (minCapacity > 0)
+            ensureCapacityInternal(minCapacity);
+    }
+
+    private void ensureCapacityInternal(int minCapacity) {
         modCount++;
         // overflow-conscious code
         if (minCapacity - elementData.length > 0)
@@ -403,7 +408,7 @@
      * @return <tt>true</tt> (as specified by {@link Collection#add})
      */
     public boolean add(E e) {
-        ensureCapacity(size + 1);  // Increments modCount!!
+        ensureCapacityInternal(size + 1);  // Increments modCount!!
         elementData[size++] = e;
         return true;
     }
@@ -420,7 +425,7 @@
     public void add(int index, E element) {
         rangeCheckForAdd(index);
 
-        ensureCapacity(size + 1);  // Increments modCount!!
+        ensureCapacityInternal(size + 1);  // Increments modCount!!
         System.arraycopy(elementData, index, elementData, index + 1,
                          size - index);
         elementData[index] = element;
@@ -524,7 +529,7 @@
     public boolean addAll(Collection<? extends E> c) {
         Object[] a = c.toArray();
         int numNew = a.length;
-        ensureCapacity(size + numNew);  // Increments modCount
+        ensureCapacityInternal(size + numNew);  // Increments modCount
         System.arraycopy(a, 0, elementData, size, numNew);
         size += numNew;
         return numNew != 0;
@@ -550,7 +555,7 @@
 
         Object[] a = c.toArray();
         int numNew = a.length;
-        ensureCapacity(size + numNew);  // Increments modCount
+        ensureCapacityInternal(size + numNew);  // Increments modCount
 
         int numMoved = size - index;
         if (numMoved > 0)
--- a/src/share/classes/java/util/Calendar.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/util/Calendar.java	Tue Nov 09 22:53:18 2010 -0800
@@ -51,6 +51,8 @@
 import java.security.ProtectionDomain;
 import java.text.DateFormat;
 import java.text.DateFormatSymbols;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 import sun.util.BuddhistCalendar;
 import sun.util.calendar.ZoneInfo;
 import sun.util.resources.LocaleData;
@@ -837,7 +839,8 @@
      * Cache to hold the firstDayOfWeek and minimalDaysInFirstWeek
      * of a Locale.
      */
-    private static Hashtable<Locale, int[]> cachedLocaleData = new Hashtable<Locale, int[]>(3);
+    private static final ConcurrentMap<Locale, int[]> cachedLocaleData
+        = new ConcurrentHashMap<Locale, int[]>(3);
 
     // Special values of stamp[]
     /**
@@ -1022,7 +1025,7 @@
             // returns a BuddhistCalendar instance.
             if ("th".equals(aLocale.getLanguage())
                     && ("TH".equals(aLocale.getCountry()))) {
-                    cal = new BuddhistCalendar(zone, aLocale);
+                cal = new BuddhistCalendar(zone, aLocale);
             } else {
                 cal = new GregorianCalendar(zone, aLocale);
             }
@@ -2588,7 +2591,7 @@
             data = new int[2];
             data[0] = Integer.parseInt(bundle.getString("firstDayOfWeek"));
             data[1] = Integer.parseInt(bundle.getString("minimalDaysInFirstWeek"));
-            cachedLocaleData.put(desiredLocale, data);
+            cachedLocaleData.putIfAbsent(desiredLocale, data);
         }
         firstDayOfWeek = data[0];
         minimalDaysInFirstWeek = data[1];
--- a/src/share/classes/java/util/Locale.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/util/Locale.java	Tue Nov 09 22:53:18 2010 -0800
@@ -758,7 +758,7 @@
     }
 
     private static void initDefault() {
-        String language, region, country, variant;
+        String language, region, script, country, variant;
         language = AccessController.doPrivileged(
             new GetPropertyAction("user.language", "en"));
         // for compatibility, check for old user.region property
@@ -774,43 +774,41 @@
                 country = region;
                 variant = "";
             }
+            script = "";
         } else {
+            script = AccessController.doPrivileged(
+                new GetPropertyAction("user.script", ""));
             country = AccessController.doPrivileged(
                 new GetPropertyAction("user.country", ""));
             variant = AccessController.doPrivileged(
                 new GetPropertyAction("user.variant", ""));
         }
-        defaultLocale = getInstance(language, country, variant);
+        defaultLocale = getInstance(language, script, country, variant, null);
     }
 
     private static void initDefault(Locale.Category category) {
-        String language, region, country, variant;
+        // make sure defaultLocale is initialized
+        if (defaultLocale == null) {
+            initDefault();
+        }
+
+        Locale defaultCategoryLocale = getInstance(
+            AccessController.doPrivileged(
+                new GetPropertyAction(category.languageKey, defaultLocale.getLanguage())),
+            AccessController.doPrivileged(
+                new GetPropertyAction(category.scriptKey, defaultLocale.getScript())),
+            AccessController.doPrivileged(
+                new GetPropertyAction(category.countryKey, defaultLocale.getCountry())),
+            AccessController.doPrivileged(
+                new GetPropertyAction(category.variantKey, defaultLocale.getVariant())),
+            null);
+
         switch (category) {
         case DISPLAY:
-            language = AccessController.doPrivileged(
-                new GetPropertyAction("user.language.display", ""));
-            if ("".equals(language)) {
-                defaultDisplayLocale = getDefault();
-            } else {
-                country = AccessController.doPrivileged(
-                    new GetPropertyAction("user.country.display", ""));
-                variant = AccessController.doPrivileged(
-                    new GetPropertyAction("user.variant.display", ""));
-                defaultDisplayLocale = getInstance(language, country, variant);
-            }
+            defaultDisplayLocale = defaultCategoryLocale;
             break;
         case FORMAT:
-            language = AccessController.doPrivileged(
-                new GetPropertyAction("user.language.format", ""));
-            if ("".equals(language)) {
-                defaultFormatLocale = getDefault();
-            } else {
-                country = AccessController.doPrivileged(
-                    new GetPropertyAction("user.country.format", ""));
-                variant = AccessController.doPrivileged(
-                    new GetPropertyAction("user.variant.format", ""));
-                defaultFormatLocale = getInstance(language, country, variant);
-            }
+            defaultFormatLocale = defaultCategoryLocale;
             break;
         }
     }
@@ -2124,13 +2122,31 @@
          * Category used to represent the default locale for
          * displaying user interfaces.
          */
-        DISPLAY,
+        DISPLAY("user.language.display",
+                "user.script.display",
+                "user.country.display",
+                "user.variant.display"),
 
         /**
          * Category used to represent the default locale for
          * formatting dates, numbers, and/or currencies.
          */
-        FORMAT,
+        FORMAT("user.language.format",
+               "user.script.format",
+               "user.country.format",
+               "user.variant.format");
+
+        Category(String languageKey, String scriptKey, String countryKey, String variantKey) {
+            this.languageKey = languageKey;
+            this.scriptKey = scriptKey;
+            this.countryKey = countryKey;
+            this.variantKey = variantKey;
+        }
+
+        final String languageKey;
+        final String scriptKey;
+        final String countryKey;
+        final String variantKey;
     }
 
     /**
--- a/src/share/classes/java/util/TimeZone.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/util/TimeZone.java	Tue Nov 09 22:53:18 2010 -0800
@@ -160,11 +160,6 @@
     private static final int ONE_HOUR   = 60*ONE_MINUTE;
     private static final int ONE_DAY    = 24*ONE_HOUR;
 
-    /**
-     * Cache to hold the SimpleDateFormat objects for a Locale.
-     */
-    private static Hashtable cachedLocaleData = new Hashtable(3);
-
     // Proclaim serialization compatibility with JDK 1.1
     static final long serialVersionUID = 3581463369166924961L;
 
--- a/src/share/classes/java/util/Vector.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/util/Vector.java	Tue Nov 09 22:53:18 2010 -0800
@@ -222,8 +222,10 @@
      * @param minCapacity the desired minimum capacity
      */
     public synchronized void ensureCapacity(int minCapacity) {
-        modCount++;
-        ensureCapacityHelper(minCapacity);
+        if (minCapacity > 0) {
+            modCount++;
+            ensureCapacityHelper(minCapacity);
+        }
     }
 
     /**
--- a/src/share/classes/java/util/logging/LogRecord.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/java/util/logging/LogRecord.java	Tue Nov 09 22:53:18 2010 -0800
@@ -529,8 +529,6 @@
         Throwable throwable = new Throwable();
         int depth = access.getStackTraceDepth(throwable);
 
-        String logClassName = "java.util.logging.Logger";
-        String plogClassName = "sun.util.logging.PlatformLogger";
         boolean lookingForLogger = true;
         for (int ix = 0; ix < depth; ix++) {
             // Calling getStackTraceElement directly prevents the VM
@@ -538,13 +536,14 @@
             StackTraceElement frame =
                 access.getStackTraceElement(throwable, ix);
             String cname = frame.getClassName();
+            boolean isLoggerImpl = isLoggerImplFrame(cname);
             if (lookingForLogger) {
                 // Skip all frames until we have found the first logger frame.
-                if (cname.equals(logClassName) || cname.startsWith(plogClassName)) {
+                if (isLoggerImpl) {
                     lookingForLogger = false;
                 }
             } else {
-                if (!cname.equals(logClassName) && !cname.startsWith(plogClassName)) {
+                if (!isLoggerImpl) {
                     // skip reflection call
                     if (!cname.startsWith("java.lang.reflect.") && !cname.startsWith("sun.reflect.")) {
                        // We've found the relevant frame.
@@ -558,4 +557,11 @@
         // We haven't found a suitable frame, so just punt.  This is
         // OK as we are only committed to making a "best effort" here.
     }
+
+    private boolean isLoggerImplFrame(String cname) {
+        // the log record could be created for a platform logger
+        return (cname.equals("java.util.logging.Logger") ||
+                cname.startsWith("java.util.logging.LoggingProxyImpl") ||
+                cname.startsWith("sun.util.logging."));
+    }
 }
--- a/src/share/classes/javax/management/ObjectName.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/management/ObjectName.java	Tue Nov 09 22:53:18 2010 -0800
@@ -211,8 +211,8 @@
  * reverse DNS name of the organization that specifies the MBeans,
  * followed by a period and a string whose interpretation is
  * determined by that organization.  For example, MBeans specified by
- * Sun Microsystems Inc., DNS name <code>sun.com</code>, would have
- * domains such as <code>com.sun.MyDomain</code>.  This is essentially
+ * <code>example.com</code>  would have
+ * domains such as <code>com.example.MyDomain</code>.  This is essentially
  * the same convention as for Java-language package names.</p>
  *
  * <p>The <b>serialVersionUID</b> of this class is <code>1081892073854801359L</code>.
--- a/src/share/classes/javax/management/build.xml	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/management/build.xml	Tue Nov 09 22:53:18 2010 -0800
@@ -35,18 +35,18 @@
      . Please also read the important comment on basedir definition below.
  -->
 
-<project name="JMX API Version 1.4 - Java SE 6 implementation" 
-	 default="jar" 
-	 basedir="../../../../.." 
+<project name="JMX API Version 1.4 - Java SE 6 implementation"
+	 default="jar"
+	 basedir="../../../../.."
 	 >
 
-    <!-- IMPORTANT: BASEDIR DEFINITION  
-         This file is assumed to be in: 
-         <src_bundle_dir>/j2se/src/share/classes/javax/management 
-         Thus the basedir for this project is defined above as: 
-         basedir="../../../../.."  
+    <!-- IMPORTANT: BASEDIR DEFINITION
+         This file is assumed to be in:
+         <src_bundle_dir>/j2se/src/share/classes/javax/management
+         Thus the basedir for this project is defined above as:
+         basedir="../../../../.."
          in order to be the parent dir of src subdir.
-	 Result of the build will be placed in ${basedir}/build_jmx 
+	 Result of the build will be placed in ${basedir}/build_jmx
 	 as defined by ${dir.build} property below.
      -->
 
@@ -163,14 +163,14 @@
         <echo message="   BUILD_DATE                  = ${BUILD_DATE}" />
 
     </target>
-    
+
 
 
     <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
     <!-- Call classes subtargets and rmic stubs generation -->
 
-    <target name="classes" depends="init,classes-javac,classes-rmic" 
-	    description="Call classes subtargets and rmic stubs generation" 
+    <target name="classes" depends="init,classes-javac,classes-rmic"
+	    description="Call classes subtargets and rmic stubs generation"
     />
 
 
@@ -183,13 +183,13 @@
         <mkdir dir="${dir.build.classes}" />
 
 	<javac 	srcdir="${dir.src}"
-		destdir="${dir.build.classes}" 
+		destdir="${dir.build.classes}"
 		source="${flag.javac.source}"
 		debug="${flag.debug}"
 		debuglevel="${flag.debug.level}"
 		optimize="${flag.optimize}"
 		includeAntRuntime="no"
-		includeJavaRuntime="no"	
+		includeJavaRuntime="no"
 	        >
 	    <include name="javax/management/**"/>
 	    <include name="com/sun/jmx/**"/>
@@ -253,7 +253,7 @@
 
        <mkdir dir="${dir.build.lib}" />
 
-       <jar jarfile="${dir.build.lib}/jmx.jar" 
+       <jar jarfile="${dir.build.lib}/jmx.jar"
 	    update="true"
 	    >
 
@@ -269,10 +269,10 @@
 		    <attribute name="Sealed"                 value="true" />
 		    <attribute name="Specification-Title"    value="JMX(TM) API" />
 		    <attribute name="Specification-Version"  value="1.4" />
-		    <attribute name="Specification-Vendor"   value="Sun Microsystems, Inc." />
+		    <attribute name="Specification-Vendor"   value="Oracle Corporation" />
 		    <attribute name="Implementation-Title"   value="JMX(TM) API, Java SE 6 implementation" />
-		    <attribute name="Implementation-Version" value="${BUILD_DATE} rebuild of Mustang JMX sources" /> 
-		    <attribute name="Implementation-Vendor"  value="Source bundle from Sun Microsystems, Inc. - Customer rebuilt" />
+		    <attribute name="Implementation-Version" value="${BUILD_DATE} rebuild of Java SE JMX sources" />
+		    <attribute name="Implementation-Vendor"  value="Source bundle from Oracle Corporation - Customer rebuilt" />
 		</section>
 	    </manifest>
        </jar>
@@ -295,16 +295,16 @@
     <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
     <!-- Delete build directory and all its contents -->
 
-    <target name="clean-all" 
+    <target name="clean-all"
             description="Delete build directory and all its contents" >
         <delete dir="${dir.build}" />
-    </target>               
-        
-  
+    </target>
+
+
     <!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
     <!-- Clean all and build everything -->
 
-    <target name="all" depends="clean-all,jar" 
+    <target name="all" depends="clean-all,jar"
 	    description="Clean all and build everything" />
 
 
--- a/src/share/classes/javax/management/modelmbean/ModelMBeanNotificationInfo.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/management/modelmbean/ModelMBeanNotificationInfo.java	Tue Nov 09 22:53:18 2010 -0800
@@ -92,8 +92,6 @@
  * @since 1.5
  */
 
-// Sun Microsystems, Sept. 2002: Revisited for JMX 1.2 (DF)
-//
 @SuppressWarnings("serial")  // serialVersionUID is not constant
 public class ModelMBeanNotificationInfo
     extends MBeanNotificationInfo
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/javax/net/ssl/ExtendedSSLSession.java	Tue Nov 09 22:53:18 2010 -0800
@@ -0,0 +1,86 @@
+/*
+ * 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;
+
+/**
+ * Extends the <code>SSLSession</code> 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.
+     * <p>
+     * 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.
+     * <p>
+     * The signature algorithm name must be a standard Java Security
+     * name (such as "SHA1withRSA", "SHA256withECDSA", and so on).
+     * See Appendix A in the <a href=
+     * "../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture API Specification &amp; Reference </a>
+     * for information about standard algorithm names.
+     * <p>
+     * Note: the local supported signature algorithms should conform to
+     * the algorithm constraints specified by
+     * {@link SSLParameters#getAlgorithmConstraints getAlgorithmConstraints()}
+     * method in <code>SSLParameters</code>.
+     *
+     * @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.
+     * <p>
+     * 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.
+     * <p>
+     * The signature algorithm name must be a standard Java Security
+     * name (such as "SHA1withRSA", "SHA256withECDSA", and so on).
+     * See Appendix A in the <a href=
+     * "../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     * Java Cryptography Architecture API Specification &amp; Reference </a>
+     * 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();
+}
--- a/src/share/classes/javax/net/ssl/HttpsURLConnection.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/net/ssl/HttpsURLConnection.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 @@
      * <p>
      * The default implementation will deny such connections.
      */
-    private static HostnameVerifier defaultHostnameVerifier;
-
-    /**
-     * Initialize the default <code>HostnameVerifier</code>.
-     */
-    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 <code>HostnameVerifier</code>.  Should be
--- a/src/share/classes/javax/net/ssl/SSLEngine.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/net/ssl/SSLEngine.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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
@@ -968,6 +968,47 @@
 
 
     /**
+     * Returns the {@code SSLSession} being constructed during a SSL/TLS
+     * handshake.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
      * <P>
      * This method is not needed for the initial handshake, as the
--- a/src/share/classes/javax/net/ssl/SSLParameters.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/net/ssl/SSLParameters.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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.
- *
- * <p>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.
+ * <p>
+ * SSLParameters can be created via the constructors in this class.
  * Objects can also be obtained using the <code>getSSLParameters()</code>
  * 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 <code>SSLContext</code>.
- *
- * <P>SSLParameters can be applied to a connection via the methods
+ * <p>
+ * 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 @@
     private String[] protocols;
     private boolean wantClientAuth;
     private boolean needClientAuth;
+    private String identificationAlgorithm;
+    private AlgorithmConstraints algorithmConstraints;
 
     /**
      * Constructs SSLParameters.
-     *
-     * <p>The cipherSuites and protocols values are set to <code>null</code>,
+     * <p>
+     * The cipherSuites and protocols values are set to <code>null</code>,
      * wantClientAuth and needClientAuth are set to <code>false</code>.
      */
     public SSLParameters() {
@@ -69,6 +76,7 @@
 
     /**
      * Constructs SSLParameters from the specified array of ciphersuites.
+     * <p>
      * Calling this constructor is equivalent to calling the no-args
      * constructor followed by
      * <code>setCipherSuites(cipherSuites);</code>.
@@ -82,6 +90,7 @@
     /**
      * Constructs SSLParameters from the specified array of ciphersuites
      * and protocols.
+     * <p>
      * Calling this constructor is equivalent to calling the no-args
      * constructor followed by
      * <code>setCipherSuites(cipherSuites); setProtocols(protocols);</code>.
@@ -178,4 +187,71 @@
         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.
+     * <p>
+     * If the <code>constraints</code> 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.
+     * <p>
+     * If the <code>algorithm</code> 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 <a href=
+     *     "../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
+     *     Java Cryptography Architecture API Specification &amp; Reference </a>
+     *     for information about standard algorithm names.
+     *
+     * @see X509ExtendedTrustManager
+     *
+     * @since 1.7
+     */
+    public void setEndpointIdentificationAlgorithm(String algorithm) {
+        this.identificationAlgorithm = algorithm;
+    }
+
 }
--- a/src/share/classes/javax/net/ssl/SSLServerSocket.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/net/ssl/SSLServerSocket.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 @@
  * @since 1.4
  * @author David Brownell
  */
-public abstract class SSLServerSocket extends ServerSocket
-{
+public abstract class SSLServerSocket extends ServerSocket {
+
     /**
      * Used only by subclasses.
      * <P>
@@ -449,8 +449,79 @@
      *
      * @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.
+     *
+     * <p>This means:
+     * <ul>
+     * <li>if <code>params.getCipherSuites()</code> is non-null,
+     *   <code>setEnabledCipherSuites()</code> is called with that value
+     * <li>if <code>params.getProtocols()</code> is non-null,
+     *   <code>setEnabledProtocols()</code> is called with that value
+     * <li>if <code>params.getNeedClientAuth()</code> or
+     *   <code>params.getWantClientAuth()</code> return <code>true</code>,
+     *   <code>setNeedClientAuth(true)</code> and
+     *   <code>setWantClientAuth(true)</code> are called, respectively;
+     *   otherwise <code>setWantClientAuth(false)</code> is called.
+     * </ul>
+     *
+     * @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);
+        }
+    }
+
 }
--- a/src/share/classes/javax/net/ssl/SSLSocket.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/net/ssl/SSLSocket.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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
@@ -371,6 +371,51 @@
 
 
     /**
+     * Returns the {@code SSLSession} being constructed during a SSL/TLS
+     * handshake.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
+     * <p>
+     * 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.
      *
--- a/src/share/classes/javax/net/ssl/SSLSocketFactory.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/net/ssl/SSLSocketFactory.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 javax.net.SocketFactory;
 import java.io.IOException;
 import java.security.*;
+import java.util.Locale;
 
 import sun.security.action.GetPropertyAction;
 
@@ -50,7 +51,8 @@
 
     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");
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/javax/net/ssl/X509ExtendedTrustManager.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 <code>X509TrustManager</code> interface to support
+ * SSL/TLS connection sensitive trust management.
+ * <p>
+ * 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.
+ * <p>
+ * 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.
+     * <p>
+     * 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.
+     * <p>
+     * If the <code>socket</code> parameter is an instance of
+     * {@link javax.net.SSLSocket}, and the endpoint identification
+     * algorithm of the <code>SSLParameters</code> is non-empty, to prevent
+     * man-in-the-middle attacks, the address that the <code>socket</code>
+     * connected to should be checked against the peer's identity presented
+     * in the end-entity X509 certificate, as specified in the endpoint
+     * identification algorithm.
+     * <p>
+     * If the <code>socket</code> parameter is an instance of
+     * {@link javax.net.SSLSocket}, and the algorithm constraints of the
+     * <code>SSLParameters</code> 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 <code>chain</code> parameter or if null or zero-length
+     *        string is passed in for the <code>authType</code> 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.
+     * <p>
+     * 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.
+     * <p>
+     * If the <code>socket</code> parameter is an instance of
+     * {@link javax.net.SSLSocket}, and the endpoint identification
+     * algorithm of the <code>SSLParameters</code> is non-empty, to prevent
+     * man-in-the-middle attacks, the address that the <code>socket</code>
+     * connected to should be checked against the peer's identity presented
+     * in the end-entity X509 certificate, as specified in the endpoint
+     * identification algorithm.
+     * <p>
+     * If the <code>socket</code> parameter is an instance of
+     * {@link javax.net.SSLSocket}, and the algorithm constraints of the
+     *  <code>SSLParameters</code> 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 <code>chain</code> parameter or if null or zero-length
+     *        string is passed in for the <code>authType</code> 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.
+     * <p>
+     * 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.
+     * <p>
+     * If the <code>engine</code> parameter is available, and the endpoint
+     * identification algorithm of the <code>SSLParameters</code> is
+     * non-empty, to prevent man-in-the-middle attacks, the address that
+     * the <code>engine</code> connected to should be checked against
+     * the peer's identity presented in the end-entity X509 certificate,
+     * as specified in the endpoint identification algorithm.
+     * <p>
+     * If the <code>engine</code> parameter is available, and the algorithm
+     * constraints of the <code>SSLParameters</code> 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 <code>chain</code> parameter or if null or zero-length
+     *        string is passed in for the <code>authType</code> 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.
+     * <p>
+     * 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.
+     * <p>
+     * If the <code>engine</code> parameter is available, and the endpoint
+     * identification algorithm of the <code>SSLParameters</code> is
+     * non-empty, to prevent man-in-the-middle attacks, the address that
+     * the <code>engine</code> connected to should be checked against
+     * the peer's identity presented in the end-entity X509 certificate,
+     * as specified in the endpoint identification algorithm.
+     * <p>
+     * If the <code>engine</code> parameter is available, and the algorithm
+     * constraints of the <code>SSLParameters</code> 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 <code>chain</code> parameter or if null or zero-length
+     *        string is passed in for the <code>authType</code> 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;
+
+}
--- a/src/share/classes/javax/swing/BorderFactory.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/swing/BorderFactory.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 @@
                                                 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;
+    }
 }
--- a/src/share/classes/javax/swing/DebugGraphics.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/swing/DebugGraphics.java	Tue Nov 09 22:53:18 2010 -0800
@@ -1322,13 +1322,11 @@
     }
 
     String toShortString() {
-        StringBuffer buffer = new StringBuffer("Graphics" + (isDrawingBuffer() ? "<B>" : "") + "(" + graphicsID + "-" + debugOptions + ")");
-        return buffer.toString();
+        return "Graphics" + (isDrawingBuffer() ? "<B>" : "") + "(" + 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
--- a/src/share/classes/javax/swing/JComponent.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/swing/JComponent.java	Tue Nov 09 22:53:18 2010 -0800
@@ -4783,21 +4783,11 @@
      * @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 @@
      * currently pending events have been dispatched.
      *
      * @param  r a <code>Rectangle</code> containing the dirty region
+     * @see #isPaintingOrigin()
      * @see java.awt.Component#isShowing
      * @see RepaintManager#addDirtyRegion
      */
@@ -4912,13 +4903,19 @@
     }
 
     /**
-     * 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.
+     * <p/>
+     * Calling {@link JComponent#repaint} on a Swing component will be delegated to
+     * the first ancestor which {@code isPaintingOrigin()} returns {@true},
+     * if there are any.
+     * <p/>
+     * {@code JComponent} subclasses that need to be repainted when any of their
+     * children are repainted should override this method to return {@code true}.
      *
-     * @return true if painting should originate from this Component or
-     *         one of its ancestors.
-     */
-    boolean isPaintingOrigin() {
+     * @return always returns {@code false}
+     */
+    protected boolean isPaintingOrigin() {
         return false;
     }
 
--- a/src/share/classes/javax/swing/JDialog.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/swing/JDialog.java	Tue Nov 09 22:53:18 2010 -0800
@@ -303,10 +303,9 @@
      * @param modal specifies whether dialog blocks user input to other top-level
      *     windows when shown. If {@code true}, the modality type property is set to
      *     {@code DEFAULT_MODALITY_TYPE}, otherwise the dialog is modeless.
-     * @param gc the {@code GraphicsConfiguration}
-     *     of the target screen device.  If {@code gc} is
-     *     {@code null}, the same
-     *     {@code GraphicsConfiguration} as the owning Frame is used.
+     * @param gc the {@code GraphicsConfiguration} of the target screen device;
+     *     if {@code null}, the default system {@code GraphicsConfiguration}
+     *     is assumed
      * @throws HeadlessException if {@code GraphicsEnvironment.isHeadless()}
      *     returns {@code true}.
      * @see java.awt.Dialog.ModalityType
@@ -441,10 +440,9 @@
      * @param modal specifies whether dialog blocks user input to other top-level
      *     windows when shown. If {@code true}, the modality type property is set to
      *     {@code DEFAULT_MODALITY_TYPE}, otherwise the dialog is modeless
-     * @param gc the {@code GraphicsConfiguration}
-     *     of the target screen device.  If {@code gc} is
-     *     {@code null}, the same
-     *     {@code GraphicsConfiguration} as the owning Dialog is used.
+     * @param gc the {@code GraphicsConfiguration} of the target screen device;
+     *     if {@code null}, the default system {@code GraphicsConfiguration}
+     *     is assumed
      * @throws HeadlessException if {@code GraphicsEnvironment.isHeadless()}
      *     returns {@code true}.
      * @see java.awt.Dialog.ModalityType
@@ -612,10 +610,8 @@
      *     windows when shown. {@code null} value and unsupported modality
      *     types are equivalent to {@code MODELESS}
      * @param gc the {@code GraphicsConfiguration} of the target screen device;
-     *     if {@code null}, the {@code GraphicsConfiguration} from the owning
-     *     window is used; if {@code owner} is also {@code null}, the
-     *     system default {@code GraphicsConfiguration} is assumed
-     *
+     *     if {@code null}, the default system {@code GraphicsConfiguration}
+     *     is assumed
      * @throws IllegalArgumentException
      *     if the {@code owner} is not an instance of {@link java.awt.Dialog Dialog}
      *     or {@link java.awt.Frame Frame}
--- a/src/share/classes/javax/swing/JLayer.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/swing/JLayer.java	Tue Nov 09 22:53:18 2010 -0800
@@ -384,7 +384,7 @@
      * @return true
      * @see JComponent#isPaintingOrigin()
      */
-    boolean isPaintingOrigin() {
+    protected boolean isPaintingOrigin() {
         return true;
     }
 
--- a/src/share/classes/javax/swing/JViewport.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/swing/JViewport.java	Tue Nov 09 22:53:18 2010 -0800
@@ -637,14 +637,14 @@
     }
 
     /**
-     * Returns true if scroll mode is a BACKINGSTORE_SCROLL_MODE to cause
-     * painting to originate from <code>JViewport</code>, 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;
     }
 
--- a/src/share/classes/javax/swing/RepaintManager.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/swing/RepaintManager.java	Tue Nov 09 22:53:18 2010 -0800
@@ -438,6 +438,7 @@
      * @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 @@
             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);
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/javax/swing/border/StrokeBorder.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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.
+ * <p>
+ * <strong>Warning:</strong>
+ * 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&trade;
+ * has been added to the <code>java.beans</code> 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;
+    }
+}
--- a/src/share/classes/javax/swing/plaf/basic/BasicScrollPaneUI.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/swing/plaf/basic/BasicScrollPaneUI.java	Tue Nov 09 22:53:18 2010 -0800
@@ -362,6 +362,14 @@
      * @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;
--- a/src/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/swing/plaf/synth/SynthTabbedPaneUI.java	Tue Nov 09 22:53:18 2010 -0800
@@ -115,10 +115,7 @@
         return new SynthTabbedPaneUI();
     }
 
-    private SynthTabbedPaneUI() {
-    }
-
-    private boolean scrollableTabLayoutEnabled() {
+     private boolean scrollableTabLayoutEnabled() {
         return (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT);
     }
 
--- a/src/share/classes/javax/swing/table/DefaultTableCellRenderer.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/swing/table/DefaultTableCellRenderer.java	Tue Nov 09 22:53:18 2010 -0800
@@ -186,6 +186,9 @@
      */
     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;
--- a/src/share/classes/javax/swing/text/DefaultCaret.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/swing/text/DefaultCaret.java	Tue Nov 09 22:53:18 2010 -0800
@@ -1334,13 +1334,13 @@
                     && 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 @@
                 }
                 return;
             }
-            int adjust = 0;
             int offset = e.getOffset();
             int length = e.getLength();
             int newDot = dot;
@@ -1759,7 +1758,6 @@
             }
             int offs0 = e.getOffset();
             int offs1 = offs0 + e.getLength();
-            int adjust = 0;
             int newDot = dot;
             boolean adjustDotBias = false;
             int newMark = mark;
--- a/src/share/classes/javax/swing/text/DefaultStyledDocument.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/swing/text/DefaultStyledDocument.java	Tue Nov 09 22:53:18 2010 -0800
@@ -132,7 +132,7 @@
             // 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 @@
             // 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) {
--- a/src/share/classes/javax/swing/text/InternationalFormatter.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/swing/text/InternationalFormatter.java	Tue Nov 09 22:53:18 2010 -0800
@@ -30,7 +30,6 @@
 import java.text.AttributedCharacterIterator.Attribute;
 import java.util.*;
 import javax.swing.*;
-import javax.swing.text.*;
 
 /**
  * <code>InternationalFormatter</code> extends <code>DefaultFormatter</code>,
@@ -875,7 +874,6 @@
                     (f instanceof AttributedCharacterIterator.Attribute)) {
             AttributedCharacterIterator.Attribute field =
                                    (AttributedCharacterIterator.Attribute)f;
-            int index = 0;
 
             iterator.first();
             while (iterator.getIndex() < start) {
--- a/src/share/classes/javax/swing/text/JTextComponent.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/swing/text/JTextComponent.java	Tue Nov 09 22:53:18 2010 -0800
@@ -35,10 +35,7 @@
 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 @@
 
     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 @@
                         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 @@
     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 @@
             strBuf.append(c);
         }
 
-        composedTextContent = new String(strBuf);
+        composedTextContent = strBuf.toString();
         composedTextAttribute = new SimpleAttributeSet();
         composedTextAttribute.addAttribute(StyleConstants.ComposedTextAttribute,
                 new AttributedString(text, composedIndex, text.getEndIndex()));
--- a/src/share/classes/javax/swing/text/MaskFormatter.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/swing/text/MaskFormatter.java	Tue Nov 09 22:53:18 2010 -0800
@@ -29,7 +29,6 @@
 import java.text.*;
 import java.util.*;
 import javax.swing.*;
-import javax.swing.text.*;
 
 /**
  * <code>MaskFormatter</code> is used to format and edit strings. The behavior
@@ -385,7 +384,7 @@
      */
     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 @@
      * Invokes <code>append</code> on the mask characters in
      * <code>mask</code>.
      */
-    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 @@
      * 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 @@
      */
     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 @@
                     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 @@
                         }
                     }
                     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 @@
                 else if (textIndex >= tl) {
                     // placeholder
                     if (replace == null) {
-                        replace = new StringBuffer();
+                        replace = new StringBuilder();
                         if (text != null) {
                             replace.append(text);
                         }
@@ -863,7 +862,7 @@
          * Appends the necessary character in <code>formatting</code> at
          * <code>index</code> to <code>buff</code>.
          */
-        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();
--- a/src/share/classes/javax/swing/text/NumberFormatter.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/swing/text/NumberFormatter.java	Tue Nov 09 22:53:18 2010 -0800
@@ -27,7 +27,6 @@
 import java.lang.reflect.*;
 import java.text.*;
 import java.util.*;
-import javax.swing.text.*;
 
 /**
  * <code>NumberFormatter</code> subclasses <code>InternationalFormatter</code>
@@ -132,7 +131,7 @@
         DecimalFormatSymbols dfs = getDecimalFormatSymbols();
 
         if (dfs != null) {
-            StringBuffer sb = new StringBuffer();
+            StringBuilder sb = new StringBuilder();
 
             sb.append(dfs.getCurrencySymbol());
             sb.append(dfs.getDecimalSeparator());
@@ -240,13 +239,6 @@
     }
 
     /**
-     */
-    private boolean isValidInsertionCharacter(char aChar) {
-        return (Character.isDigit(aChar) || specialChars.indexOf(aChar) != -1);
-    }
-
-
-    /**
      * Subclassed to return false if <code>text</code> contains in an invalid
      * character to insert, that is, it is not a digit
      * (<code>Character.isDigit()</code>) and
@@ -403,28 +395,6 @@
     }
 
     /**
-     * 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.
      */
--- a/src/share/classes/javax/swing/text/PlainDocument.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/swing/text/PlainDocument.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 @@
         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 @@
                 }
             }
             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();
--- a/src/share/classes/javax/swing/text/TabSet.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/swing/text/TabSet.java	Tue Nov 09 22:53:18 2010 -0800
@@ -199,7 +199,7 @@
      */
     public String toString() {
         int            tabCount = getTabCount();
-        StringBuffer   buffer = new StringBuffer("[ ");
+        StringBuilder buffer = new StringBuilder("[ ");
 
         for(int counter = 0; counter < tabCount; counter++) {
             if(counter > 0)
--- a/src/share/classes/javax/swing/text/html/FormView.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/swing/text/html/FormView.java	Tue Nov 09 22:53:18 2010 -0800
@@ -362,7 +362,7 @@
      */
     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 @@
      */
     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 @@
      * @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 @@
      * 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 @@
             }
             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 @@
      * 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 @@
      * 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('&');
         }
--- a/src/share/classes/javax/swing/text/html/MinimalHTMLWriter.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/swing/text/html/MinimalHTMLWriter.java	Tue Nov 09 22:53:18 2010 -0800
@@ -691,11 +691,11 @@
         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');
             }
--- a/src/share/classes/javax/swing/text/html/StyleSheet.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/swing/text/html/StyleSheet.java	Tue Nov 09 22:53:18 2010 -0800
@@ -998,7 +998,7 @@
     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(' ');
--- a/src/share/classes/javax/swing/text/html/parser/Parser.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/swing/text/html/parser/Parser.java	Tue Nov 09 22:53:18 2010 -0800
@@ -1470,7 +1470,7 @@
      */
     public String parseDTDMarkup() throws IOException {
 
-        StringBuffer strBuff = new StringBuffer();
+        StringBuilder strBuff = new StringBuilder();
         ch = readCh();
         while(true) {
             switch (ch) {
--- a/src/share/classes/javax/swing/text/rtf/AbstractFilter.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/javax/swing/text/rtf/AbstractFilter.java	Tue Nov 09 22:53:18 2010 -0800
@@ -160,7 +160,7 @@
     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 @@
           char ch = translationTable[b];
           if (ch != (char)0) {
             if (accumulator == null)
-              accumulator = new StringBuffer();
+              accumulator = new StringBuilder();
             accumulator.append(ch);
           }
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/java2d/pisces/Curve.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 Iterator<Float> instead.
+    // Doing this will also make dashing easier, since we could easily make
+    // LengthIterator an Iterator<Float> and feed it to this function to simplify
+    // the loop in Dasher.somethingTo.
+    static Iterator<float[]> breakPtsAtTs(final float[][] pts, final int type,
+                                          final float[] Ts, final int numTs)
+    {
+        assert pts.length >= 2 && pts[0].length >= 8 && numTs <= Ts.length;
+        return new Iterator<float[]>() {
+            int nextIdx = 0;
+            int nextCurveIdx = 0;
+            float prevT = 0;
+
+            @Override public boolean hasNext() {
+                return nextCurveIdx < numTs + 1;
+            }
+
+            @Override public float[] next() {
+                float[] ret;
+                if (nextCurveIdx < numTs) {
+                    float curT = Ts[nextCurveIdx];
+                    float splitT = (curT - prevT) / (1 - prevT);
+                    Helpers.subdivideAt(splitT,
+                                        pts[nextIdx], 0,
+                                        pts[nextIdx], 0,
+                                        pts[1-nextIdx], 0, type);
+                    updateTs(Ts, Ts[nextCurveIdx], nextCurveIdx + 1, numTs - nextCurveIdx - 1);
+                    ret = pts[nextIdx];
+                    nextIdx = 1 - nextIdx;
+                } else {
+                    ret = pts[nextIdx];
+                }
+                nextCurveIdx++;
+                return ret;
+            }
+
+            @Override public void remove() {}
+        };
+    }
+
+    // precondition: ts[off]...ts[off+len-1] must all be greater than t.
+    private static void updateTs(float[] ts, final float t, final int off, final int len) {
+        for (int i = off; i < off + len; i++) {
+            ts[i] = (ts[i] - t) / (1 - t);
+        }
+    }
+}
+
--- a/src/share/classes/sun/java2d/pisces/Dasher.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/sun/java2d/pisces/Dasher.java	Tue Nov 09 22:53:18 2010 -0800
@@ -25,6 +25,8 @@
 
 package sun.java2d.pisces;
 
+import sun.awt.geom.PathConsumer2D;
+
 /**
  * The <code>Dasher</code> class takes a series of linear commands
  * (<code>moveTo</code>, <code>lineTo</code>, <code>close</code> and
@@ -36,18 +38,16 @@
  * 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 @@
 
     private float sx, sy;
     private float x0, y0;
-    private float sx1, sy1;
 
+    // temporary storage for the current curve
+    private float[] curCurvepts;
 
     /**
      * Constructs a <code>Dasher</code>.
      *
-     * @param output an output <code>LineSink</code>.
-     * @param dash an array of <code>int</code>s containing the dash pattern
-     * @param phase an <code>int</code> containing the dash phase
-     * @param transform a <code>Transform4</code> 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 <code>PathConsumer2D</code>.
+     * @param dash an array of <code>float</code>s containing the dash pattern
+     * @param phase a <code>float</code> 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 @@
         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,88 +108,108 @@
         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 goTo(float x1, float y1) {
+    private void emitFirstSegments() {
+        for (int i = 0; i < firstSegidx; ) {
+            emitSeg(firstSegmentsBuffer, i+1, (int)firstSegmentsBuffer[i]);
+            i += (((int)firstSegmentsBuffer[i]) - 1);
+        }
+        firstSegidx = 0;
+    }
+
+    // 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);
 
-            origLen -= (dash[idx] - phase);
+            len -= leftInThisDashSegment;
             // Advance to next dash segment
             idx = (idx + 1) % dash.length;
             dashOn = !dashOn;
@@ -199,15 +217,289 @@
         }
     }
 
+    private LengthIterator li = null;
 
-    public void close() {
-        lineTo(sx, sy);
-        if (firstDashOn) {
-            output.lineTo(sx1, sy1);
+    // 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);
+
+        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;
         }
     }
 
-    public void end() {
-        output.end();
+    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<<limit curves, but this is an iterator and we
+    // don't need all the curves all at once, so what we carry out a
+    // lazy inorder traversal of the recursion tree (meaning we only move
+    // through the tree when we need the next subdivided curve). This saves
+    // us a lot of memory because at any one time we only need to store
+    // limit+1 curves - one for each level of the tree + 1.
+    // NOTE: the way we do things here is not enough to traverse a general
+    // tree; however, the trees we are interested in have the property that
+    // every non leaf node has exactly 2 children
+    private static class LengthIterator {
+        private enum Side {LEFT, RIGHT};
+        // Holds the curves at various levels of the recursion. The root
+        // (i.e. the original curve) is at recCurveStack[0] (but then it
+        // gets subdivided, the left half is put at 1, so most of the time
+        // only the right half of the original curve is at 0)
+        private float[][] recCurveStack;
+        // sides[i] indicates whether the node at level i+1 in the path from
+        // the root to the current leaf is a left or right child of its parent.
+        private Side[] sides;
+        private int curveType;
+        private final int limit;
+        private final float ERR;
+        private final float minTincrement;
+        // lastT and nextT delimit the current leaf.
+        private float nextT;
+        private float lenAtNextT;
+        private float lastT;
+        private float lenAtLastT;
+        private float lenAtLastSplit;
+        private float lastSegLen;
+        // the current level in the recursion tree. 0 is the root. limit
+        // is the deepest possible leaf.
+        private int recLevel;
+        private boolean done;
+
+        public LengthIterator(int reclimit, float err) {
+            this.limit = reclimit;
+            this.minTincrement = 1f / (1 << limit);
+            this.ERR = err;
+            this.recCurveStack = new float[reclimit+1][8];
+            this.sides = new Side[reclimit];
+            // if any methods are called without first initializing this object on
+            // a curve, we want it to fail ASAP.
+            this.nextT = Float.MAX_VALUE;
+            this.lenAtNextT = Float.MAX_VALUE;
+            this.lenAtLastSplit = Float.MIN_VALUE;
+            this.recLevel = Integer.MIN_VALUE;
+            this.lastSegLen = Float.MAX_VALUE;
+            this.done = true;
+        }
+
+        public void initializeIterationOnCurve(float[] pts, int type) {
+            System.arraycopy(pts, 0, recCurveStack[0], 0, type);
+            this.curveType = type;
+            this.recLevel = 0;
+            this.lastT = 0;
+            this.lenAtLastT = 0;
+            this.nextT = 0;
+            this.lenAtNextT = 0;
+            goLeft(); // initializes nextT and lenAtNextT properly
+            this.lenAtLastSplit = 0;
+            if (recLevel > 0) {
+                this.sides[0] = Side.LEFT;
+                this.done = false;
+            } else {
+                // the root of the tree is a leaf so we're done.
+                this.sides[0] = Side.RIGHT;
+                this.done = true;
+            }
+            this.lastSegLen = 0;
+        }
+
+        // returns the t value where the remaining curve should be split in
+        // order for the left subdivided curve to have length len. If len
+        // is >= than the length of the uniterated curve, it returns 1.
+        public float next(float len) {
+            float targetLength = lenAtLastSplit + len;
+            while(lenAtNextT < targetLength) {
+                if (done) {
+                    lastSegLen = lenAtNextT - lenAtLastSplit;
+                    return 1;
+                }
+                goToNextLeaf();
+            }
+            lenAtLastSplit = targetLength;
+            float t = binSearchForLen(lenAtLastSplit - lenAtLastT,
+                    recCurveStack[recLevel], curveType, lenAtNextT - lenAtLastT, ERR);
+            // t is relative to the current leaf, so we must make it a valid parameter
+            // of the original curve.
+            t = t * (nextT - lastT) + lastT;
+            if (t >= 1) {
+                t = 1;
+                done = true;
+            }
+            // even if done = true, if we're here, that means targetLength
+            // is equal to, or very, very close to the total length of the
+            // curve, so lastSegLen won't be too high. In cases where len
+            // overshoots the curve, this method will exit in the while
+            // loop, and lastSegLen will still be set to the right value.
+            lastSegLen = len;
+            return t;
+        }
+
+        public float lastSegLen() {
+            return lastSegLen;
+        }
+
+        // Returns t such that if leaf is subdivided at t the left
+        // curve will have length len. leafLen must be the length of leaf.
+        private static Curve bsc = new Curve();
+        private static float binSearchForLen(float len, float[] leaf, int type,
+                                             float leafLen, float err)
+        {
+            assert len <= leafLen;
+            bsc.set(leaf, type);
+            float errBound = err*len;
+            float left = 0, right = 1;
+            while (left < right) {
+                float m = (left + right) / 2;
+                if (m == left || m == right) {
+                    return m;
+                }
+                float x = bsc.xat(m);
+                float y = bsc.yat(m);
+                float leftLen = Helpers.linelen(leaf[0], leaf[1], x, y);
+                if (Math.abs(leftLen - len) < errBound) {
+                    return m;
+                }
+                if (leftLen < len) {
+                    left = m;
+                } else {
+                    right = m;
+                }
+            }
+            return left;
+        }
+
+        // go to the next leaf (in an inorder traversal) in the recursion tree
+        // preconditions: must be on a leaf, and that leaf must not be the root.
+        private void goToNextLeaf() {
+            // We must go to the first ancestor node that has an unvisited
+            // right child.
+            recLevel--;
+            while(sides[recLevel] == Side.RIGHT) {
+                if (recLevel == 0) {
+                    done = true;
+                    return;
+                }
+                recLevel--;
+            }
+
+            sides[recLevel] = Side.RIGHT;
+            System.arraycopy(recCurveStack[recLevel], 0, recCurveStack[recLevel+1], 0, curveType);
+            recLevel++;
+            goLeft();
+        }
+
+        // go to the leftmost node from the current node. Return its length.
+        private void goLeft() {
+            float len = onLeaf();
+            if (len >= 0) {
+                lastT = nextT;
+                lenAtLastT = lenAtNextT;
+                nextT += (1 << (limit - recLevel)) * minTincrement;
+                lenAtNextT += len;
+            } else {
+                Helpers.subdivide(recCurveStack[recLevel], 0,
+                                  recCurveStack[recLevel+1], 0,
+                                  recCurveStack[recLevel], 0, curveType);
+                sides[recLevel] = Side.LEFT;
+                recLevel++;
+                goLeft();
+            }
+        }
+
+        // this is a bit of a hack. It returns -1 if we're not on a leaf, and
+        // the length of the leaf if we are on a leaf.
+        private float onLeaf() {
+            float polylen = Helpers.polyLineLength(recCurveStack[recLevel], 0, curveType);
+            float linelen = Helpers.linelen(recCurveStack[recLevel][0], recCurveStack[recLevel][1],
+                    recCurveStack[recLevel][curveType - 2], recCurveStack[recLevel][curveType - 1]);
+            return (polylen - linelen < ERR || recLevel == limit) ?
+                   (polylen + linelen)/2 : -1;
+        }
+    }
+
+    @Override
+    public void curveTo(float x1, float y1,
+                        float x2, float y2,
+                        float x3, float y3)
+    {
+        curCurvepts[0] = x0;        curCurvepts[1] = y0;
+        curCurvepts[2] = x1;        curCurvepts[3] = y1;
+        curCurvepts[4] = x2;        curCurvepts[5] = y2;
+        curCurvepts[6] = x3;        curCurvepts[7] = y3;
+        somethingTo(8);
+    }
+
+    @Override
+    public void quadTo(float x1, float y1, float x2, float y2) {
+        curCurvepts[0] = x0;        curCurvepts[1] = y0;
+        curCurvepts[2] = x1;        curCurvepts[3] = y1;
+        curCurvepts[4] = x2;        curCurvepts[5] = y2;
+        somethingTo(6);
+    }
+
+    public void closePath() {
+        lineTo(sx, sy);
+        if (firstSegidx > 0) {
+            if (!dashOn || needsMoveTo) {
+                out.moveTo(sx, sy);
+            }
+            emitFirstSegments();
+        }
+        moveTo(sx, sy);
+    }
+
+    public void pathDone() {
+        if (firstSegidx > 0) {
+            out.moveTo(sx, sy);
+            emitFirstSegments();
+        }
+        out.pathDone();
+    }
+
+    @Override
+    public long getNativeConsumer() {
+        throw new InternalError("Dasher does not use a native consumer");
     }
 }
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/java2d/pisces/Helpers.java	Tue Nov 09 22:53:18 2010 -0800
@@ -0,0 +1,478 @@
+/*
+ * 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.Arrays;
+
+final class Helpers {
+    private Helpers() {
+        throw new Error("This is a non instantiable class");
+    }
+
+    static boolean within(final float x, final float y, final float err) {
+        final float d = y - x;
+        return (d <= err && d >= -err);
+    }
+
+    static boolean within(final double x, final double y, final double err) {
+        final double d = y - x;
+        return (d <= err && d >= -err);
+    }
+
+    static int quadraticRoots(final float a, final float b,
+                              final float c, float[] zeroes, final int off)
+    {
+        int ret = off;
+        float t;
+        if (a != 0f) {
+            final float dis = b*b - 4*a*c;
+            if (dis > 0) {
+                final float sqrtDis = (float)Math.sqrt(dis);
+                // depending on the sign of b we use a slightly different
+                // algorithm than the traditional one to find one of the roots
+                // so we can avoid adding numbers of different signs (which
+                // might result in loss of precision).
+                if (b >= 0) {
+                    zeroes[ret++] = (2 * c) / (-b - sqrtDis);
+                    zeroes[ret++] = (-b - sqrtDis) / (2 * a);
+                } else {
+                    zeroes[ret++] = (-b + sqrtDis) / (2 * a);
+                    zeroes[ret++] = (2 * c) / (-b + sqrtDis);
+                }
+            } else if (dis == 0f) {
+                t = (-b) / (2 * a);
+                zeroes[ret++] = t;
+            }
+        } else {
+            if (b != 0f) {
+                t = (-c) / b;
+                zeroes[ret++] = t;
+            }
+        }
+        return ret - off;
+    }
+
+    // find the roots of g(t) = a*t^3 + b*t^2 + c*t + d in [A,B)
+    // We will not use Cardano's method, since it is complicated and
+    // involves too many square and cubic roots. We will use Newton's method.
+    // TODO: this should probably return ALL roots. Then the user can do
+    // his own filtering of roots outside [A,B).
+    static int cubicRootsInAB(final float a, final float b,
+                              final float c, final float d,
+                              float[] pts, final int off, final float E,
+                              final float A, final float B)
+    {
+        if (a == 0) {
+            return quadraticRoots(b, c, d, pts, off);
+        }
+        // the coefficients of g'(t). no dc variable because dc=c
+        // we use these to get the critical points of g(t), which
+        // we then use to chose starting points for Newton's method. These
+        // should be very close to the actual roots.
+        final float da = 3 * a;
+        final float db = 2 * b;
+        int numCritPts = quadraticRoots(da, db, c, pts, off+1);
+        numCritPts = filterOutNotInAB(pts, off+1, numCritPts, A, B) - off - 1;
+        // need them sorted.
+        if (numCritPts == 2 && pts[off+1] > pts[off+2]) {
+            float tmp = pts[off+1];
+            pts[off+1] = pts[off+2];
+            pts[off+2] = tmp;
+        }
+
+        int ret = off;
+
+        // we don't actually care much about the extrema themselves. We
+        // only use them to ensure that g(t) is monotonic in each
+        // interval [pts[i],pts[i+1] (for i in off...off+numCritPts+1).
+        // This will allow us to determine intervals containing exactly
+        // one root.
+        // The end points of the interval are always local extrema.
+        pts[off] = A;
+        pts[off + numCritPts + 1] = B;
+        numCritPts += 2;
+
+        float x0 = pts[off], fx0 = evalCubic(a, b, c, d, x0);
+        for (int i = off; i < off + numCritPts - 1; i++) {
+            float x1 = pts[i+1], fx1 = evalCubic(a, b, c, d, x1);
+            if (fx0 == 0f) {
+                pts[ret++] = x0;
+            } else if (fx1 * fx0 < 0f) { // have opposite signs
+                pts[ret++] = CubicNewton(a, b, c, d,
+                        x0 + fx0 * (x1 - x0) / (fx0 - fx1), E);
+            }
+            x0 = x1;
+            fx0 = fx1;
+        }
+        return ret - off;
+    }
+
+    // precondition: the polynomial to be evaluated must not be 0 at x0.
+    static float CubicNewton(final float a, final float b,
+                             final float c, final float d,
+                             float x0, final float err)
+    {
+        // considering how this function is used, 10 should be more than enough
+        final int itlimit = 10;
+        float fx0 = evalCubic(a, b, c, d, x0);
+        float x1;
+        int count = 0;
+        while(true) {
+            x1 = x0 - (fx0 / evalCubic(0, 3 * a, 2 * b, c, x0));
+            if (Math.abs(x1 - x0) < err * Math.abs(x1 + x0) || count == itlimit) {
+                break;
+            }
+            x0 = x1;
+            fx0 = evalCubic(a, b, c, d, x0);
+            count++;
+        }
+        return x1;
+    }
+
+    // fills the input array with numbers 0, INC, 2*INC, ...
+    static void fillWithIdxes(final float[] data, final int[] idxes) {
+        if (idxes.length > 0) {
+            idxes[0] = 0;
+            for (int i = 1; i < idxes.length; i++) {
+                idxes[i] = idxes[i-1] + (int)data[idxes[i-1]];
+            }
+        }
+    }
+
+    static void fillWithIdxes(final int[] idxes, final int inc) {
+        if (idxes.length > 0) {
+            idxes[0] = 0;
+            for (int i = 1; i < idxes.length; i++) {
+                idxes[i] = idxes[i-1] + inc;
+            }
+        }
+    }
+
+    // These use a hardcoded factor of 2 for increasing sizes. Perhaps this
+    // should be provided as an argument.
+    static float[] widenArray(float[] in, final int cursize, final int numToAdd) {
+        if (in == null) {
+            return new float[5 * numToAdd];
+        }
+        if (in.length >= cursize + numToAdd) {
+            return in;
+        }
+        return Arrays.copyOf(in, 2 * (cursize + numToAdd));
+    }
+    static int[] widenArray(int[] in, final int cursize, final int numToAdd) {
+        if (in.length >= cursize + numToAdd) {
+            return in;
+        }
+        return Arrays.copyOf(in, 2 * (cursize + numToAdd));
+    }
+
+    static float evalCubic(final float a, final float b,
+                           final float c, final float d,
+                           final float t)
+    {
+        return t * (t * (t * a + b) + c) + d;
+    }
+
+    static float evalQuad(final float a, final float b,
+                          final float c, final float t)
+    {
+        return t * (t * a + b) + c;
+    }
+
+    // returns the index 1 past the last valid element remaining after filtering
+    static int filterOutNotInAB(float[] nums, final int off, final int len,
+                                final float a, final float b)
+    {
+        int ret = off;
+        for (int i = off; i < off + len; i++) {
+            if (nums[i] > a && nums[i] < b) {
+                nums[ret++] = nums[i];
+            }
+        }
+        return ret;
+    }
+
+    static float polyLineLength(float[] poly, final int off, final int nCoords) {
+        assert nCoords % 2 == 0 && poly.length >= off + nCoords : "";
+        float acc = 0;
+        for (int i = off + 2; i < off + nCoords; i += 2) {
+            acc += linelen(poly[i], poly[i+1], poly[i-2], poly[i-1]);
+        }
+        return acc;
+    }
+
+    static float linelen(float x1, float y1, float x2, float y2) {
+        return (float)Math.hypot(x2 - x1, y2 - y1);
+    }
+
+    static void subdivide(float[] src, int srcoff, float[] left, int leftoff,
+                          float[] right, int rightoff, int type)
+    {
+        switch(type) {
+        case 6:
+            Helpers.subdivideQuad(src, srcoff, left, leftoff, right, rightoff);
+            break;
+        case 8:
+            Helpers.subdivideCubic(src, srcoff, left, leftoff, right, rightoff);
+            break;
+        default:
+            throw new InternalError("Unsupported curve type");
+        }
+    }
+
+    static void isort(float[] a, int off, int len) {
+        for (int i = off + 1; i < off + len; i++) {
+            float ai = a[i];
+            int j = i - 1;
+            for (; j >= off && a[j] > ai; j--) {
+                a[j+1] = a[j];
+            }
+            a[j+1] = ai;
+        }
+    }
+
+    // Most of these are copied from classes in java.awt.geom because we need
+    // float versions of these functions, and Line2D, CubicCurve2D,
+    // QuadCurve2D don't provide them.
+    /**
+     * Subdivides the cubic curve specified by the coordinates
+     * stored in the <code>src</code> array at indices <code>srcoff</code>
+     * through (<code>srcoff</code>&nbsp;+&nbsp;7) and stores the
+     * resulting two subdivided curves into the two result arrays at the
+     * corresponding indices.
+     * Either or both of the <code>left</code> and <code>right</code>
+     * arrays may be <code>null</code> or a reference to the same array
+     * as the <code>src</code> 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 <code>left</code>
+     * and <code>right</code> and to use offsets, such as <code>rightoff</code>
+     * equals (<code>leftoff</code> + 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;
+        }
+    }
+}
--- a/src/share/classes/sun/java2d/pisces/LineSink.java	Tue Nov 09 11:45:00 2010 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -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 <code>LineSink</code> interface accepts a series of line
- * drawing commands: <code>moveTo</code>, <code>lineTo</code>,
- * <code>close</code> (equivalent to a <code>lineTo</code> command
- * with an argument equal to the argument of the last
- * <code>moveTo</code> command), and <code>end</code>.
- *
- * <p> A <code>Flattener</code> may be used to connect a general path
- * source to a <code>LineSink</code>.
- *
- * <p> The <code>Renderer</code> class implements the
- * <code>LineSink</code> interface.
- *
- */
-public interface LineSink {
-
-    /**
-     * Moves the current drawing position to the point <code>(x0,
-     * y0)</code>.
-     *
-     * @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.
-     *
-     * <p> An application-generated path will generally have no need
-     * to contain calls to this method; they are typically introduced
-     * by a <code>Flattener</code> to mark segment divisions that
-     * appear in its input, and consumed by a <code>Stroker</code>
-     * that is responsible for emitting the miter or round join
-     * segments.
-     *
-     * <p> Other <code>LineSink</code> 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
-     * <code>(x1, y1)</code> and sets the current drawing position to
-     * <code>(x1, y1)</code>.
-     *
-     * @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
-     * <code>moveTo</code> 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();
-
-}
--- a/src/share/classes/sun/java2d/pisces/PiscesCache.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/sun/java2d/pisces/PiscesCache.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 @@
  */
 public final class PiscesCache {
 
-    int bboxX0, bboxY0, bboxX1, bboxY1;
+    final int bboxX0, bboxY0, bboxX1, bboxY1;
 
-    byte[] rowAARLE;
-    int alphaRLELength;
+    // 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;
 
-    int[] rowOffsetsRLE;
-    int[] minTouched;
-    int alphaRows;
+    // 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;
 
-    private PiscesCache() {}
+    // 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;
 
-    public static PiscesCache createInstance() {
-        return new PiscesCache();
+    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];
     }
 
-    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;
+    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;
         }
     }
 
-    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;
-        }
+    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 <=
+
+        y0 = y - bboxY0;
+        // this should be a new, uninitialized row.
+        assert rowAARLE[y0][1] == 0;
+
+        x0 = x - bboxX0;
+        assert x0 >= 0 : "Input must not be to the left of bbox bounds";
+
+        // 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;
     }
 
-    void addRLERun(byte val, int runLen) {
-        reallocRowAARLE(alphaRLELength + 2);
-        rowAARLE[alphaRLELength++] = val;
-        rowAARLE[alphaRLELength++] = (byte)runLen;
+    int alphaSumInTile(int x, int y) {
+        x -= bboxX0;
+        y -= bboxY0;
+        return touchedTile[y>>TILE_SIZE_LG][x>>TILE_SIZE_LG];
     }
 
-    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++;
+    int minTouched(int rowidx) {
+        return rowAARLE[rowidx][0];
+    }
+
+    int rowLength(int rowidx) {
+        return rowAARLE[rowidx][1];
+    }
+
+    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;
+    }
+
+    @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";
             }
         }
-        reallocRowInfo(alphaRows+1);
-        minTouched[alphaRows] = x0;
-        rowOffsetsRLE[alphaRows] = alphaRLELength;
-        alphaRows++;
-    }
-
-    public synchronized void dispose() {
-        rowAARLE = null;
-        alphaRLELength = 0;
-
-        minTouched = null;
-        rowOffsetsRLE = null;
-        alphaRows = 0;
-
-        bboxX0 = bboxY0 = bboxX1 = bboxY1 = 0;
-    }
-
-    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));
-        }
-    }
+        return ret;
     }
 }
--- a/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java	Tue Nov 09 22:53:18 2010 -0800
@@ -27,7 +27,7 @@
 
 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.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 @@
                  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 @@
         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 @@
                   boolean thin,
                   NormMode normalize,
                   boolean antialias,
-                  LineSink lsink)
+                  PathConsumer2D pc2d)
     {
         float lw;
         if (thin) {
@@ -178,7 +170,7 @@
                  bs.getMiterLimit(),
                  bs.getDashArray(),
                  bs.getDashPhase(),
-                 lsink);
+                 pc2d);
     }
 
     private float userSpaceLineWidth(AffineTransform at, float lw) {
@@ -256,28 +248,113 @@
                   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);
+            pc2d = new Dasher(pc2d, dashes, dashphase);
         }
-        PathIterator pi;
-        if (normalize != NormMode.OFF) {
-            pi = new FlatteningPathIterator(
-                    new NormalizingPathIterator(src.getPathIterator(at), normalize),
-                    defaultFlat);
-        } else {
-            pi = src.getPathIterator(at, defaultFlat);
-        }
-        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 @@
             }
 
             // 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 @@
         }
     }
 
-    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 @@
                                               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;
     }
--- a/src/share/classes/sun/java2d/pisces/PiscesTileGenerator.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/sun/java2d/pisces/PiscesTileGenerator.java	Tue Nov 09 22:53:18 2010 -0800
@@ -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 Map<Integer, byte[]> alphaMapsCache = new
+                   ConcurrentHashMap<Integer, byte[]>();
 
     PiscesCache cache;
     int x, y;
-    int maxalpha;
+    final int maxalpha;
+    private final int maxTileAlphaSum;
+
+    // The alpha map used by this object (taken out of our map cache) to convert
+    // pixel coverage counts gotten from PiscesCache (which are in the range
+    // [0, maxalpha]) into alpha values, which are in [0,256).
     byte alphaMap[];
 
-    public PiscesTileGenerator(PiscesCache cache, int maxalpha) {
-        this.cache = cache;
+    public PiscesTileGenerator(Renderer r, int maxalpha) {
+        this.cache = r.getCache();
         this.x = cache.bboxX0;
         this.y = cache.bboxY0;
         this.alphaMap = getAlphaMap(maxalpha);
         this.maxalpha = maxalpha;
+        this.maxTileAlphaSum = TILE_SIZE*TILE_SIZE*maxalpha;
     }
 
-    static int prevMaxAlpha;
-    static byte prevAlphaMap[];
+    private static byte[] buildAlphaMap(int maxalpha) {
+        byte[] alMap = new byte[maxalpha+1];
+        int halfmaxalpha = maxalpha>>2;
+        for (int i = 0; i <= maxalpha; i++) {
+            alMap[i] = (byte) ((i * 255 + halfmaxalpha) / maxalpha);
+        }
+        return alMap;
+    }
 
-    public synchronized static byte[] getAlphaMap(int maxalpha) {
-        if (maxalpha != prevMaxAlpha) {
-            prevAlphaMap = new byte[maxalpha+300];
-            int halfmaxalpha = maxalpha>>2;
-            for (int i = 0; i <= maxalpha; i++) {
-                prevAlphaMap[i] = (byte) ((i * 255 + halfmaxalpha) / maxalpha);
-            }
-            for (int i = maxalpha; i < prevAlphaMap.length; i++) {
-                prevAlphaMap[i] = (byte) 255;
-            }
-            prevMaxAlpha = maxalpha;
+    public static byte[] getAlphaMap(int maxalpha) {
+        if (!alphaMapsCache.containsKey(maxalpha)) {
+            alphaMapsCache.put(maxalpha, buildAlphaMap(maxalpha));
         }
-        return prevAlphaMap;
+        return alphaMapsCache.get(maxalpha);
     }
 
     public void getBbox(int bbox[]) {
@@ -96,53 +110,24 @@
      *         value for partial coverage of the tile
      */
     public int getTypicalAlpha() {
-        if (true) return 0x80;
-        // Decode run-length encoded alpha mask data
-        // The data for row j begins at cache.rowOffsetsRLE[j]
-        // and is encoded as a set of 2-byte pairs (val, runLen)
-        // terminated by a (0, 0) pair.
-
-        int x0 = this.x;
-        int x1 = x0 + TILE_SIZE;
-        int y0 = this.y;
-        int y1 = y0 + TILE_SIZE;
-        if (x1 > cache.bboxX1) x1 = cache.bboxX1;
-        if (y1 > cache.bboxY1) y1 = cache.bboxY1;
-        y0 -= cache.bboxY0;
-        y1 -= cache.bboxY0;
-
-        int ret = -1;
-        for (int cy = y0; cy < y1; cy++) {
-            int pos = cache.rowOffsetsRLE[cy];
-            int cx = cache.minTouched[cy];
-
-            if (cx > x0) {
-                if (ret > 0) return 0x80;
-                ret = 0x00;
-            }
-            while (cx < x1) {
-                int runLen = cache.rowAARLE[pos + 1] & 0xff;
-                if (runLen == 0) {
-                    if (ret > 0) return 0x80;
-                    ret = 0x00;
-                    break;
-                }
-                cx += runLen;
-                if (cx > x0) {
-                    int val = cache.rowAARLE[pos] & 0xff;
-                    if (ret != val) {
-                        if (ret < 0) {
-                            if (val != 0x00 && val != maxalpha) return 0x80;
-                            ret = val;
-                        } else {
-                            return 0x80;
-                        }
-                    }
-                }
-                pos += 2;
-            }
-        }
-        return ret;
+        int al = cache.alphaSumInTile(x, y);
+        // Note: if we have a filled rectangle that doesn't end on a tile
+        // border, we could still return 0xff, even though al!=maxTileAlphaSum
+        // This is because if we return 0xff, our users will fill a rectangle
+        // starting at x,y that has width = Math.min(TILE_SIZE, bboxX1-x),
+        // and height min(TILE_SIZE,bboxY1-y), which is what should happen.
+        // However, to support this, we would have to use 2 Math.min's
+        // and 2 multiplications per tile, instead of just 2 multiplications
+        // to compute maxTileAlphaSum. The savings offered would probably
+        // not be worth it, considering how rare this case is.
+        // Note: I have not tested this, so in the future if it is determined
+        // that it is worth it, it should be implemented. Perhaps this method's
+        // interface should be changed to take arguments the width and height
+        // of the current tile. This would eliminate the 2 Math.min calls that
+        // would be needed here, since our caller needs to compute these 2
+        // values anyway.
+        return (al == 0x00 ? 0x00 :
+            (al == maxTileAlphaSum ? 0xff : 0x80));
     }
 
     /**
@@ -179,22 +164,24 @@
 
         int idx = offset;
         for (int cy = y0; cy < y1; cy++) {
-            int pos = cache.rowOffsetsRLE[cy];
-            int cx = cache.minTouched[cy];
+            int[] row = cache.rowAARLE[cy];
+            assert row != null;
+            int cx = cache.minTouched(cy);
             if (cx > x1) cx = x1;
 
-            if (cx > x0) {
-                //System.out.println("L["+(cx-x0)+"]");
-                for (int i = x0; i < cx; i++) {
-                    tile[idx++] = 0x00;
-                }
+            for (int i = x0; i < cx; i++) {
+                tile[idx++] = 0x00;
             }
-            while (cx < x1) {
+
+            int pos = 2;
+            while (cx < x1 && pos < row[1]) {
                 byte val;
                 int runLen = 0;
+                assert row[1] > 2;
                 try {
-                    val = alphaMap[cache.rowAARLE[pos] & 0xff];
-                    runLen = cache.rowAARLE[pos + 1] & 0xff;
+                    val = alphaMap[row[pos]];
+                    runLen = row[pos + 1];
+                    assert runLen > 0;
                 } catch (RuntimeException e0) {
                     System.out.println("maxalpha = "+maxalpha);
                     System.out.println("tile["+x0+", "+y0+
@@ -202,14 +189,12 @@
                     System.out.println("cx = "+cx+", cy = "+cy);
                     System.out.println("idx = "+idx+", pos = "+pos);
                     System.out.println("len = "+runLen);
-                    cache.print(System.out);
+                    System.out.print(cache.toString());
                     e0.printStackTrace();
                     System.exit(1);
                     return;
                 }
-                if (runLen == 0) {
-                    break;
-                }
+
                 int rx0 = cx;
                 cx += runLen;
                 int rx1 = cx;
@@ -228,7 +213,7 @@
                         System.out.println("idx = "+idx+", pos = "+pos);
                         System.out.println("rx0 = "+rx0+", rx1 = "+rx1);
                         System.out.println("len = "+runLen);
-                        cache.print(System.out);
+                        System.out.print(cache.toString());
                         e.printStackTrace();
                         System.exit(1);
                         return;
@@ -265,4 +250,4 @@
      * No further calls will be made on this instance.
      */
     public void dispose() {}
-}
+}
\ No newline at end of file
--- a/src/share/classes/sun/java2d/pisces/Renderer.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/sun/java2d/pisces/Renderer.java	Tue Nov 09 22:53:18 2010 -0800
@@ -26,250 +26,552 @@
 package sun.java2d.pisces;
 
 import java.util.Arrays;
+import java.util.Iterator;
 
-public class Renderer implements LineSink {
+import sun.awt.geom.PathConsumer2D;
 
-///////////////////////////////////////////////////////////////////////////////
-// Scan line iterator and edge crossing data.
-//////////////////////////////////////////////////////////////////////////////
+public class Renderer implements PathConsumer2D {
 
-    private int[] crossings;
+    private class ScanlineIterator {
 
-    // This is an array of indices into the edge array. It is initialized to
-    // [i * SIZEOF_STRUCT_EDGE for i in range(0, edgesSize/SIZEOF_STRUCT_EDGE)]
-    // (where range(i, j) is i,i+1,...,j-1 -- just like in python).
-    // The reason for keeping this is because we need the edges array sorted
-    // by y0, but we don't want to move all that data around, so instead we
-    // sort the indices into the edge array, and use edgeIndices to access
-    // the edges array. This is meant to simulate a pointer array (hence the name)
-    private int[] edgePtrs;
+        private int[] crossings;
 
-    // crossing bounds. The bounds are not necessarily tight (the scan line
-    // at minY, for example, might have no crossings). The x bounds will
-    // be accumulated as crossings are computed.
-    private int minY, maxY;
-    private int minX, maxX;
-    private int nextY;
+        // crossing bounds. The bounds are not necessarily tight (the scan line
+        // at minY, for example, might have no crossings). The x bounds will
+        // be accumulated as crossings are computed.
+        private int minY, maxY;
+        private int nextY;
 
-    // indices into the edge pointer list. They indicate the "active" sublist in
-    // the edge list (the portion of the list that contains all the edges that
-    // cross the next scan line).
-    private int lo, hi;
+        // indices into the segment pointer lists. They indicate the "active"
+        // sublist in the segment lists (the portion of the list that contains
+        // all the segments that cross the next scan line).
+        private int elo, ehi;
+        private final int[] edgePtrs;
+        private int qlo, qhi;
+        private final int[] quadPtrs;
+        private int clo, chi;
+        private final int[] curvePtrs;
 
-    private static final int INIT_CROSSINGS_SIZE = 50;
-    private void ScanLineItInitialize() {
-        crossings = new int[INIT_CROSSINGS_SIZE];
-        edgePtrs = new int[edgesSize / SIZEOF_STRUCT_EDGE];
-        for (int i = 0; i < edgePtrs.length; i++) {
-            edgePtrs[i] = i * SIZEOF_STRUCT_EDGE;
+        private static final int INIT_CROSSINGS_SIZE = 10;
+
+        private ScanlineIterator() {
+            crossings = new int[INIT_CROSSINGS_SIZE];
+
+            edgePtrs = new int[numEdges];
+            Helpers.fillWithIdxes(edgePtrs, SIZEOF_EDGE);
+            qsort(edges, edgePtrs, YMIN, 0, numEdges - 1);
+
+            quadPtrs = new int[numQuads];
+            Helpers.fillWithIdxes(quadPtrs, SIZEOF_QUAD);
+            qsort(quads, quadPtrs, YMIN, 0, numQuads - 1);
+
+            curvePtrs = new int[numCurves];
+            Helpers.fillWithIdxes(curvePtrs, SIZEOF_CURVE);
+            qsort(curves, curvePtrs, YMIN, 0, numCurves - 1);
+
+            // We don't care if we clip some of the line off with ceil, since
+            // no scan line crossings will be eliminated (in fact, the ceil is
+            // the y of the first scan line crossing).
+            nextY = minY = Math.max(boundsMinY, (int)Math.ceil(edgeMinY));
+            maxY = Math.min(boundsMaxY, (int)Math.ceil(edgeMaxY));
+
+            for (elo = 0; elo < numEdges && edges[edgePtrs[elo]+YMAX] <= minY; elo++)
+                ;
+            // the active list is *edgePtrs[lo] (inclusive) *edgePtrs[hi] (exclusive)
+            for (ehi = elo; ehi < numEdges && edges[edgePtrs[ehi]+YMIN] <= minY; ehi++)
+                edgeSetCurY(edgePtrs[ehi], minY);// TODO: make minY a float to avoid casts
+
+            for (qlo = 0; qlo < numQuads && quads[quadPtrs[qlo]+YMAX] <= minY; qlo++)
+                ;
+            for (qhi = qlo; qhi < numQuads && quads[quadPtrs[qhi]+YMIN] <= minY; qhi++)
+                quadSetCurY(quadPtrs[qhi], minY);
+
+            for (clo = 0; clo < numCurves && curves[curvePtrs[clo]+YMAX] <= minY; clo++)
+                ;
+            for (chi = clo; chi < numCurves && curves[curvePtrs[chi]+YMIN] <= minY; chi++)
+                curveSetCurY(curvePtrs[chi], minY);
         }
 
-        qsort(0, edgePtrs.length - 1);
+        private int next() {
+            // we go through the active lists and remove segments that don't cross
+            // the nextY scanline.
+            int crossingIdx = 0;
+            for (int i = elo; i < ehi; i++) {
+                if (edges[edgePtrs[i]+YMAX] <= nextY) {
+                    edgePtrs[i] = edgePtrs[elo++];
+                }
+            }
+            for (int i = qlo; i < qhi; i++) {
+                if (quads[quadPtrs[i]+YMAX] <= nextY) {
+                    quadPtrs[i] = quadPtrs[qlo++];
+                }
+            }
+            for (int i = clo; i < chi; i++) {
+                if (curves[curvePtrs[i]+YMAX] <= nextY) {
+                    curvePtrs[i] = curvePtrs[clo++];
+                }
+            }
 
-        // We don't care if we clip some of the line off with ceil, since
-        // no scan line crossings will be eliminated (in fact, the ceil is
-        // the y of the first scan line crossing).
-        nextY = minY = Math.max(boundsMinY, (int)Math.ceil(edgeMinY));
-        maxY = Math.min(boundsMaxY, (int)Math.ceil(edgeMaxY));
+            crossings = Helpers.widenArray(crossings, 0, ehi-elo+qhi-qlo+chi-clo);
 
-        for (lo = 0; lo < edgePtrs.length && edges[edgePtrs[lo]+Y1] <= nextY; lo++)
-            ;
-        for (hi = lo; hi < edgePtrs.length && edges[edgePtrs[hi]+CURY] <= nextY; hi++)
-            ; // the active list is *edgePtrs[lo] (inclusive) *edgePtrs[hi] (exclusive)
-        for (int i = lo; i < hi; i++) {
-            setCurY(edgePtrs[i], nextY);
+            // Now every edge between lo and hi crosses nextY. Compute it's
+            // crossing and put it in the crossings array.
+            for (int i = elo; i < ehi; i++) {
+                int ptr = edgePtrs[i];
+                addCrossing(nextY, (int)edges[ptr+CURX], edges[ptr+OR], crossingIdx);
+                edgeGoToNextY(ptr);
+                crossingIdx++;
+            }
+            for (int i = qlo; i < qhi; i++) {
+                int ptr = quadPtrs[i];
+                addCrossing(nextY, (int)quads[ptr+CURX], quads[ptr+OR], crossingIdx);
+                quadGoToNextY(ptr);
+                crossingIdx++;
+            }
+            for (int i = clo; i < chi; i++) {
+                int ptr = curvePtrs[i];
+                addCrossing(nextY, (int)curves[ptr+CURX], curves[ptr+OR], crossingIdx);
+                curveGoToNextY(ptr);
+                crossingIdx++;
+            }
+
+            nextY++;
+            // Expand active lists to include new edges.
+            for (; ehi < numEdges && edges[edgePtrs[ehi]+YMIN] <= nextY; ehi++) {
+                edgeSetCurY(edgePtrs[ehi], nextY);
+            }
+            for (; qhi < numQuads && quads[quadPtrs[qhi]+YMIN] <= nextY; qhi++) {
+                quadSetCurY(quadPtrs[qhi], nextY);
+            }
+            for (; chi < numCurves && curves[curvePtrs[chi]+YMIN] <= nextY; chi++) {
+                curveSetCurY(curvePtrs[chi], nextY);
+            }
+            Arrays.sort(crossings, 0, crossingIdx);
+            return crossingIdx;
         }
 
-        // We accumulate X in the iterator because accumulating it in addEdge
-        // like we do with Y does not do much good: if there's an edge
-        // (0,0)->(1000,10000), and if y gets clipped to 1000, then the x
-        // bound should be 100, but the accumulator from addEdge would say 1000,
-        // so we'd still have to accumulate the X bounds as we add crossings.
-        minX = boundsMinX;
-        maxX = boundsMaxX;
-    }
-
-    private int ScanLineItCurrentY() {
-        return nextY - 1;
-    }
-
-    private int ScanLineItGoToNextYAndComputeCrossings() {
-        // we go through the active list and remove the ones that don't cross
-        // the nextY scanline.
-        int crossingIdx = 0;
-        for (int i = lo; i < hi; i++) {
-            if (edges[edgePtrs[i]+Y1] <= nextY) {
-                edgePtrs[i] = edgePtrs[lo++];
-            }
-        }
-        if (hi - lo > crossings.length) {
-            int newSize = Math.max(hi - lo, crossings.length * 2);
-            crossings = Arrays.copyOf(crossings, newSize);
-        }
-        // Now every edge between lo and hi crosses nextY. Compute it's
-        // crossing and put it in the crossings array.
-        for (int i = lo; i < hi; i++) {
-            addCrossing(nextY, getCurCrossing(edgePtrs[i]), (int)edges[edgePtrs[i]+OR], crossingIdx);
-            gotoNextY(edgePtrs[i]);
-            crossingIdx++;
+        private boolean hasNext() {
+            return nextY < maxY;
         }
 
-        nextY++;
-        // Expand active list to include new edges.
-        for (; hi < edgePtrs.length && edges[edgePtrs[hi]+CURY] <= nextY; hi++) {
-            setCurY(edgePtrs[hi], nextY);
+        private int curY() {
+            return nextY - 1;
         }
 
-        Arrays.sort(crossings, 0, crossingIdx);
-        return crossingIdx;
+        private void addCrossing(int y, int x, float or, int idx) {
+            x <<= 1;
+            crossings[idx] = ((or > 0) ? (x | 0x1) : x);
+        }
     }
-
-    private boolean ScanLineItHasNext() {
-        return nextY < maxY;
-    }
-
-    private void addCrossing(int y, int x, int or, int idx) {
-        if (x < minX) {
-            minX = x;
-        }
-        if (x > maxX) {
-            maxX = x;
-        }
-        x <<= 1;
-        crossings[idx] = ((or == 1) ? (x | 0x1) : x);
-    }
-
-
     // quicksort implementation for sorting the edge indices ("pointers")
     // by increasing y0. first, last are indices into the "pointer" array
     // It sorts the pointer array from first (inclusive) to last (inclusive)
-    private void qsort(int first, int last) {
+    private static void qsort(final float[] data, final int[] ptrs,
+                              final int fieldForCmp, int first, int last)
+    {
         if (last > first) {
-            int p = partition(first, last);
+            int p = partition(data, ptrs, fieldForCmp, first, last);
             if (first < p - 1) {
-                qsort(first, p - 1);
+                qsort(data, ptrs, fieldForCmp, first, p - 1);
             }
             if (p < last) {
-                qsort(p, last);
+                qsort(data, ptrs, fieldForCmp, p, last);
             }
         }
     }
 
     // i, j are indices into edgePtrs.
-    private int partition(int i, int j) {
-        int pivotVal = edgePtrs[i];
+    private static int partition(final float[] data, final int[] ptrs,
+                                 final int fieldForCmp, int i, int j)
+    {
+        int pivotValFieldForCmp = ptrs[i]+fieldForCmp;
         while (i <= j) {
             // edges[edgePtrs[i]+1] is equivalent to (*(edgePtrs[i])).y0 in C
-            while (edges[edgePtrs[i]+CURY] < edges[pivotVal+CURY]) { i++; }
-            while (edges[edgePtrs[j]+CURY] > edges[pivotVal+CURY]) { j--; }
+            while (data[ptrs[i]+fieldForCmp] < data[pivotValFieldForCmp])
+                i++;
+            while (data[ptrs[j]+fieldForCmp] > data[pivotValFieldForCmp])
+                j--;
             if (i <= j) {
-                int tmp = edgePtrs[i];
-                edgePtrs[i] = edgePtrs[j];
-                edgePtrs[j] = tmp;
+                int tmp = ptrs[i];
+                ptrs[i] = ptrs[j];
+                ptrs[j] = tmp;
                 i++;
                 j--;
             }
         }
         return i;
     }
-
 //============================================================================
 
 
 //////////////////////////////////////////////////////////////////////////////
 //  EDGE LIST
 //////////////////////////////////////////////////////////////////////////////
+// TODO(maybe): very tempting to use fixed point here. A lot of opportunities
+// for shifts and just removing certain operations altogether.
+// TODO: it might be worth it to make an EdgeList class. It would probably
+// clean things up a bit and not impact performance much.
 
-    private static final int INIT_NUM_EDGES = 1000;
-    private static final int SIZEOF_STRUCT_EDGE = 5;
+    // common to all types of input path segments.
+    private static final int YMIN = 0;
+    private static final int YMAX = 1;
+    private static final int CURX = 2;
+    // this and OR are meant to be indeces into "int" fields, but arrays must
+    // be homogenous, so every field is a float. However floats can represent
+    // exactly up to 26 bit ints, so we're ok.
+    private static final int CURY = 3;
+    private static final int OR   = 4;
 
-    // The following array is a poor man's struct array:
-    // it simulates a struct array by having
-    // edges[SIZEOF_STRUCT_EDGE * i + j] be the jth field in the ith element
-    // of an array of edge structs.
-    private float[] edges;
-    private int edgesSize; // size of the edge list.
-    private static final int Y1    = 0;
-    private static final int SLOPE = 1;
-    private static final int OR    = 2; // the orientation. This can be -1 or 1.
-                                     // -1 means up, 1 means down.
-    private static final int CURY  = 3; // j = 5 corresponds to the "current Y".
-                             // Each edge keeps track of the last scanline
-                             // crossing it computed, and this is the y coord of
-                             // that scanline.
-    private static final int CURX = 4; //the x coord of the current crossing.
+    // for straight lines only:
+    private static final int SLOPE = 5;
 
-    // Note that while the array is declared as a float[] not all of it's
-    // elements should be floats. currentY and Orientation should be ints (or int and
-    // byte respectively), but they all need to be the same type. This isn't
-    // really a problem because floats can represent exactly all 23 bit integers,
-    // which should be more than enough.
-    // Note, also, that we only need x1 for slope computation, so we don't need
-    // to store it. x0, y0 don't need to be stored either. They can be put into
-    // curx, cury, and it's ok if they're lost when curx and cury are changed.
-    // We take this undeniably ugly and error prone approach (instead of simply
-    // making an Edge class) for performance reasons. Also, it would probably be nicer
-    // to have one array for each field, but that would defeat the purpose because
-    // it would make poor use of the processor cache, since we tend to access
-    // all the fields for one edge at a time.
+    // for quads and cubics:
+    private static final int X0 = 5;
+    private static final int Y0 = 6;
+    private static final int XL = 7;
+    private static final int COUNT = 8;
+    private static final int CURSLOPE = 9;
+    private static final int DX = 10;
+    private static final int DY = 11;
+    private static final int DDX = 12;
+    private static final int DDY = 13;
 
-    private float edgeMinY;
-    private float edgeMaxY;
+    // for cubics only
+    private static final int DDDX = 14;
+    private static final int DDDY = 15;
 
+    private float edgeMinY = Float.POSITIVE_INFINITY;
+    private float edgeMaxY = Float.NEGATIVE_INFINITY;
+    private float edgeMinX = Float.POSITIVE_INFINITY;
+    private float edgeMaxX = Float.NEGATIVE_INFINITY;
 
-    private void addEdge(float x0, float y0, float x1, float y1) {
-        float or = (y0 < y1) ? 1f : -1f; // orientation: 1 = UP; -1 = DOWN
-        if (or == -1) {
-            float tmp = y0;
-            y0 = y1;
-            y1 = tmp;
-            tmp = x0;
-            x0 = x1;
-            x1 = tmp;
+    private static final int SIZEOF_EDGE = 6;
+    private float[] edges = null;
+    private int numEdges;
+    // these are static because we need them to be usable from ScanlineIterator
+    private void edgeSetCurY(final int idx, int y) {
+        edges[idx+CURX] += (y - edges[idx+CURY]) * edges[idx+SLOPE];
+        edges[idx+CURY] = y;
+    }
+    private void edgeGoToNextY(final int idx) {
+        edges[idx+CURY] += 1;
+        edges[idx+CURX] += edges[idx+SLOPE];
+    }
+
+
+    private static final int SIZEOF_QUAD = 14;
+    private float[] quads = null;
+    private int numQuads;
+    // This function should be called exactly once, to set the first scanline
+    // of the curve. Before it is called, the curve should think its first
+    // scanline is CEIL(YMIN).
+    private void quadSetCurY(final int idx, final int y) {
+        assert y < quads[idx+YMAX];
+        assert (quads[idx+CURY] > y);
+        assert (quads[idx+CURY] == Math.ceil(quads[idx+CURY]));
+
+        while (quads[idx+CURY] < ((float)y)) {
+            quadGoToNextY(idx);
         }
-        // skip edges that don't cross a scanline
-        if (Math.ceil(y0) >= Math.ceil(y1)) {
+    }
+    private void quadGoToNextY(final int idx) {
+        quads[idx+CURY] += 1;
+        // this will get overriden if the while executes.
+        quads[idx+CURX] += quads[idx+CURSLOPE];
+        int count = (int)quads[idx+COUNT];
+        // this loop should never execute more than once because our
+        // curve is monotonic in Y. Still we put it in because you can
+        // never be too sure when dealing with floating point.
+        while(quads[idx+CURY] >= quads[idx+Y0] && count > 0) {
+            float x0 = quads[idx+X0], y0 = quads[idx+Y0];
+            count = executeQuadAFDIteration(idx);
+            float x1 = quads[idx+X0], y1 = quads[idx+Y0];
+            // our quads are monotonic, so this shouldn't happen, but
+            // it is conceivable that for very flat quads with different
+            // y values at their endpoints AFD might give us a horizontal
+            // segment.
+            if (y1 == y0) {
+                continue;
+            }
+            quads[idx+CURSLOPE] = (x1 - x0) / (y1 - y0);
+            quads[idx+CURX] = x0 + (quads[idx+CURY] - y0) * quads[idx+CURSLOPE];
+        }
+    }
+
+
+    private static final int SIZEOF_CURVE = 16;
+    private float[] curves = null;
+    private int numCurves;
+    private void curveSetCurY(final int idx, final int y) {
+        assert y < curves[idx+YMAX];
+        assert (curves[idx+CURY] > y);
+        assert (curves[idx+CURY] == Math.ceil(curves[idx+CURY]));
+
+        while (curves[idx+CURY] < ((float)y)) {
+            curveGoToNextY(idx);
+        }
+    }
+    private void curveGoToNextY(final int idx) {
+        curves[idx+CURY] += 1;
+        // this will get overriden if the while executes.
+        curves[idx+CURX] += curves[idx+CURSLOPE];
+        int count = (int)curves[idx+COUNT];
+        // this loop should never execute more than once because our
+        // curve is monotonic in Y. Still we put it in because you can
+        // never be too sure when dealing with floating point.
+        while(curves[idx+CURY] >= curves[idx+Y0] && count > 0) {
+            float x0 = curves[idx+X0], y0 = curves[idx+Y0];
+            count = executeCurveAFDIteration(idx);
+            float x1 = curves[idx+X0], y1 = curves[idx+Y0];
+            // our curves are monotonic, so this shouldn't happen, but
+            // it is conceivable that for very flat curves with different
+            // y values at their endpoints AFD might give us a horizontal
+            // segment.
+            if (y1 == y0) {
+                continue;
+            }
+            curves[idx+CURSLOPE] = (x1 - x0) / (y1 - y0);
+            curves[idx+CURX] = x0 + (curves[idx+CURY] - y0) * curves[idx+CURSLOPE];
+        }
+    }
+
+
+    private static final float DEC_BND = 20f;
+    private static final float INC_BND = 8f;
+    // Flattens using adaptive forward differencing. This only carries out
+    // one iteration of the AFD loop. All it does is update AFD variables (i.e.
+    // X0, Y0, D*[X|Y], COUNT; not variables used for computing scanline crossings).
+    private int executeQuadAFDIteration(int idx) {
+        int count = (int)quads[idx+COUNT];
+        float ddx = quads[idx+DDX];
+        float ddy = quads[idx+DDY];
+        float dx = quads[idx+DX];
+        float dy = quads[idx+DY];
+
+        while (Math.abs(ddx) > DEC_BND || Math.abs(ddy) > DEC_BND) {
+            ddx = ddx / 4;
+            ddy = ddy / 4;
+            dx = (dx - ddx) / 2;
+            dy = (dy - ddy) / 2;
+            count <<= 1;
+        }
+        // can only do this on even "count" values, because we must divide count by 2
+        while (count % 2 == 0 && Math.abs(dx) <= INC_BND && Math.abs(dy) <= INC_BND) {
+            dx = 2 * dx + ddx;
+            dy = 2 * dy + ddy;
+            ddx = 4 * ddx;
+            ddy = 4 * ddy;
+            count >>= 1;
+        }
+        count--;
+        if (count > 0) {
+            quads[idx+X0] += dx;
+            dx += ddx;
+            quads[idx+Y0] += dy;
+            dy += ddy;
+        } else {
+            quads[idx+X0] = quads[idx+XL];
+            quads[idx+Y0] = quads[idx+YMAX];
+        }
+        quads[idx+COUNT] = count;
+        quads[idx+DDX] = ddx;
+        quads[idx+DDY] = ddy;
+        quads[idx+DX] = dx;
+        quads[idx+DY] = dy;
+        return count;
+    }
+    private int executeCurveAFDIteration(int idx) {
+        int count = (int)curves[idx+COUNT];
+        float ddx = curves[idx+DDX];
+        float ddy = curves[idx+DDY];
+        float dx = curves[idx+DX];
+        float dy = curves[idx+DY];
+        float dddx = curves[idx+DDDX];
+        float dddy = curves[idx+DDDY];
+
+        while (Math.abs(ddx) > DEC_BND || Math.abs(ddy) > DEC_BND) {
+            dddx /= 8;
+            dddy /= 8;
+            ddx = ddx/4 - dddx;
+            ddy = ddy/4 - dddy;
+            dx = (dx - ddx) / 2;
+            dy = (dy - ddy) / 2;
+            count <<= 1;
+        }
+        // can only do this on even "count" values, because we must divide count by 2
+        while (count % 2 == 0 && Math.abs(dx) <= INC_BND && Math.abs(dy) <= INC_BND) {
+            dx = 2 * dx + ddx;
+            dy = 2 * dy + ddy;
+            ddx = 4 * (ddx + dddx);
+            ddy = 4 * (ddy + dddy);
+            dddx = 8 * dddx;
+            dddy = 8 * dddy;
+            count >>= 1;
+        }
+        count--;
+        if (count > 0) {
+            curves[idx+X0] += dx;
+            dx += ddx;
+            ddx += dddx;
+            curves[idx+Y0] += dy;
+            dy += ddy;
+            ddy += dddy;
+        } else {
+            curves[idx+X0] = curves[idx+XL];
+            curves[idx+Y0] = curves[idx+YMAX];
+        }
+        curves[idx+COUNT] = count;
+        curves[idx+DDDX] = dddx;
+        curves[idx+DDDY] = dddy;
+        curves[idx+DDX] = ddx;
+        curves[idx+DDY] = ddy;
+        curves[idx+DX] = dx;
+        curves[idx+DY] = dy;
+        return count;
+    }
+
+
+    private void initLine(final int idx, float[] pts, int or) {
+        edges[idx+SLOPE] = (pts[2] - pts[0]) / (pts[3] - pts[1]);
+        edges[idx+CURX] = pts[0] + (edges[idx+CURY] - pts[1]) * edges[idx+SLOPE];
+    }
+
+    private void initQuad(final int idx, float[] points, int or) {
+        final int countlg = 3;
+        final int count = 1 << countlg;
+
+        // the dx and dy refer to forward differencing variables, not the last
+        // coefficients of the "points" polynomial
+        final float ddx, ddy, dx, dy;
+        c.set(points, 6);
+
+        ddx = c.dbx / (1 << (2 * countlg));
+        ddy = c.dby / (1 << (2 * countlg));
+        dx = c.bx / (1 << (2 * countlg)) + c.cx / (1 << countlg);
+        dy = c.by / (1 << (2 * countlg)) + c.cy / (1 << countlg);
+
+        quads[idx+DDX] = ddx;
+        quads[idx+DDY] = ddy;
+        quads[idx+DX] = dx;
+        quads[idx+DY] = dy;
+        quads[idx+COUNT] = count;
+        quads[idx+XL] = points[4];
+        quads[idx+X0] = points[0];
+        quads[idx+Y0] = points[1];
+        executeQuadAFDIteration(idx);
+        float x1 = quads[idx+X0], y1 = quads[idx+Y0];
+        quads[idx+CURSLOPE] = (x1 - points[0]) / (y1 - points[1]);
+        quads[idx+CURX] = points[0] + (quads[idx+CURY] - points[1])*quads[idx+CURSLOPE];
+    }
+
+    private void initCurve(final int idx, float[] points, int or) {
+        final int countlg = 3;
+        final int count = 1 << countlg;
+
+        // the dx and dy refer to forward differencing variables, not the last
+        // coefficients of the "points" polynomial
+        final float dddx, dddy, ddx, ddy, dx, dy;
+        c.set(points, 8);
+        dddx = 2f * c.dax / (1 << (3 * countlg));
+        dddy = 2f * c.day / (1 << (3 * countlg));
+
+        ddx = dddx + c.dbx / (1 << (2 * countlg));
+        ddy = dddy + c.dby / (1 << (2 * countlg));
+        dx = c.ax / (1 << (3 * countlg)) + c.bx / (1 << (2 * countlg)) + c.cx / (1 << countlg);
+        dy = c.ay / (1 << (3 * countlg)) + c.by / (1 << (2 * countlg)) + c.cy / (1 << countlg);
+
+        curves[idx+DDDX] = dddx;
+        curves[idx+DDDY] = dddy;
+        curves[idx+DDX] = ddx;
+        curves[idx+DDY] = ddy;
+        curves[idx+DX] = dx;
+        curves[idx+DY] = dy;
+        curves[idx+COUNT] = count;
+        curves[idx+XL] = points[6];
+        curves[idx+X0] = points[0];
+        curves[idx+Y0] = points[1];
+        executeCurveAFDIteration(idx);
+        float x1 = curves[idx+X0], y1 = curves[idx+Y0];
+        curves[idx+CURSLOPE] = (x1 - points[0]) / (y1 - points[1]);
+        curves[idx+CURX] = points[0] + (curves[idx+CURY] - points[1])*curves[idx+CURSLOPE];
+    }
+
+    private void addPathSegment(float[] pts, final int type, final int or) {
+        int idx;
+        float[] addTo;
+        switch (type) {
+        case 4:
+            idx = numEdges * SIZEOF_EDGE;
+            addTo = edges = Helpers.widenArray(edges, numEdges*SIZEOF_EDGE, SIZEOF_EDGE);
+            numEdges++;
+            break;
+        case 6:
+            idx = numQuads * SIZEOF_QUAD;
+            addTo = quads = Helpers.widenArray(quads, numQuads*SIZEOF_QUAD, SIZEOF_QUAD);
+            numQuads++;
+            break;
+        case 8:
+            idx = numCurves * SIZEOF_CURVE;
+            addTo = curves = Helpers.widenArray(curves, numCurves*SIZEOF_CURVE, SIZEOF_CURVE);
+            numCurves++;
+            break;
+        default:
+            throw new InternalError();
+        }
+        // set the common fields, except CURX, for which we must know the kind
+        // of curve. NOTE: this must be done before the type specific fields
+        // are initialized, because those depend on the common ones.
+        addTo[idx+YMIN] = pts[1];
+        addTo[idx+YMAX] = pts[type-1];
+        addTo[idx+OR] = or;
+        addTo[idx+CURY] = (float)Math.ceil(pts[1]);
+        switch (type) {
+        case 4:
+            initLine(idx, pts, or);
+            break;
+        case 6:
+            initQuad(idx, pts, or);
+            break;
+        case 8:
+            initCurve(idx, pts, or);
+            break;
+        default:
+            throw new InternalError();
+        }
+    }
+
+    // precondition: the curve in pts must be monotonic and increasing in y.
+    private void somethingTo(float[] pts, final int type, final int or) {
+        // NOTE: it's very important that we check for or >= 0 below (as
+        // opposed to or == 1, or or > 0, or anything else). That's
+        // because if we check for or==1, when the curve being added
+        // is a horizontal line, or will be 0 so or==1 will be false and
+        // x0 and y0 will be updated to pts[0] and pts[1] instead of pts[type-2]
+        // and pts[type-1], which is the correct thing to do.
+        this.x0 = or >= 0 ? pts[type - 2] : pts[0];
+        this.y0 = or >= 0 ? pts[type - 1] : pts[1];
+
+        float minY = pts[1], maxY = pts[type - 1];
+        if (Math.ceil(minY) >= Math.ceil(maxY) ||
+            Math.ceil(minY) >= boundsMaxY || maxY < boundsMinY)
+        {
             return;
         }
 
-        int newSize = edgesSize + SIZEOF_STRUCT_EDGE;
-        if (edges.length < newSize) {
-            edges = Arrays.copyOf(edges, newSize * 2);
-        }
-        edges[edgesSize+CURX] = x0;
-        edges[edgesSize+CURY] = y0;
-        edges[edgesSize+Y1] = y1;
-        edges[edgesSize+SLOPE] = (x1 - x0) / (y1 - y0);
-        edges[edgesSize+OR] = or;
-        // the crossing values can't be initialized meaningfully yet. This
-        // will have to wait until setCurY is called
-        edgesSize += SIZEOF_STRUCT_EDGE;
+        if (minY < edgeMinY) { edgeMinY = minY; }
+        if (maxY > edgeMaxY) { edgeMaxY = maxY; }
 
-        // Accumulate edgeMinY and edgeMaxY
-        if (y0 < edgeMinY) { edgeMinY = y0; }
-        if (y1 > edgeMaxY) { edgeMaxY = y1; }
+        int minXidx = (pts[0] < pts[type-2] ? 0 : type - 2);
+        float minX = pts[minXidx];
+        float maxX = pts[type - 2 - minXidx];
+        if (minX < edgeMinX) { edgeMinX = minX; }
+        if (maxX > edgeMaxX) { edgeMaxX = maxX; }
+        addPathSegment(pts, type, or);
     }
 
-    // As far as the following methods care, this edges extends to infinity.
-    // They can compute the x intersect of any horizontal line.
-    // precondition: idx is the index to the start of the desired edge.
-    // So, if the ith edge is wanted, idx should be SIZEOF_STRUCT_EDGE * i
-    private void setCurY(int idx, int y) {
-        // compute the x crossing of edge at idx and horizontal line y
-        // currentXCrossing = (y - y0)*slope + x0
-        edges[idx + CURX] = (y - edges[idx + CURY]) * edges[idx + SLOPE] + edges[idx+CURX];
-        edges[idx + CURY] = (float)y;
-    }
+// END EDGE LIST
+//////////////////////////////////////////////////////////////////////////////
 
-    private void gotoNextY(int idx) {
-        edges[idx + CURY] += 1f; // i.e. curY += 1
-        edges[idx + CURX] += edges[idx + SLOPE]; // i.e. curXCrossing += slope
-    }
-
-    private int getCurCrossing(int idx) {
-        return (int)edges[idx + CURX];
-    }
-//====================================================================================
 
     public static final int WIND_EVEN_ODD = 0;
     public static final int WIND_NON_ZERO = 1;
@@ -284,16 +586,13 @@
     final int MAX_AA_ALPHA;
 
     // Cache to store RLE-encoded coverage mask of the current primitive
-    final PiscesCache cache;
+    PiscesCache cache;
 
     // Bounds of the drawing region, at subpixel precision.
-    final private int boundsMinX, boundsMinY, boundsMaxX, boundsMaxY;
-
-    // Pixel bounding box for current primitive
-    private int pix_bboxX0, pix_bboxY0, pix_bboxX1, pix_bboxY1;
+    private final int boundsMinX, boundsMinY, boundsMaxX, boundsMaxY;
 
     // Current winding rule
-    final private int windingRule;
+    private final int windingRule;
 
     // Current drawing position, i.e., final point of last segment
     private float x0, y0;
@@ -304,8 +603,8 @@
     public Renderer(int subpixelLgPositionsX, int subpixelLgPositionsY,
                     int pix_boundsX, int pix_boundsY,
                     int pix_boundsWidth, int pix_boundsHeight,
-                    int windingRule,
-                    PiscesCache cache) {
+                    int windingRule)
+    {
         this.SUBPIXEL_LG_POSITIONS_X = subpixelLgPositionsX;
         this.SUBPIXEL_LG_POSITIONS_Y = subpixelLgPositionsY;
         this.SUBPIXEL_MASK_X = (1 << (SUBPIXEL_LG_POSITIONS_X)) - 1;
@@ -314,23 +613,12 @@
         this.SUBPIXEL_POSITIONS_Y = 1 << (SUBPIXEL_LG_POSITIONS_Y);
         this.MAX_AA_ALPHA = (SUBPIXEL_POSITIONS_X * SUBPIXEL_POSITIONS_Y);
 
-        this.edges = new float[SIZEOF_STRUCT_EDGE * INIT_NUM_EDGES];
-        edgeMinY = Float.POSITIVE_INFINITY;
-        edgeMaxY = Float.NEGATIVE_INFINITY;
-        edgesSize = 0;
-
         this.windingRule = windingRule;
-        this.cache = cache;
 
         this.boundsMinX = pix_boundsX * SUBPIXEL_POSITIONS_X;
         this.boundsMinY = pix_boundsY * SUBPIXEL_POSITIONS_Y;
         this.boundsMaxX = (pix_boundsX + pix_boundsWidth) * SUBPIXEL_POSITIONS_X;
         this.boundsMaxY = (pix_boundsY + pix_boundsHeight) * SUBPIXEL_POSITIONS_Y;
-
-        this.pix_bboxX0 = pix_boundsX;
-        this.pix_bboxY0 = pix_boundsY;
-        this.pix_bboxX1 = pix_boundsX + pix_boundsWidth;
-        this.pix_bboxY1 = pix_boundsY + pix_boundsHeight;
     }
 
     private float tosubpixx(float pix_x) {
@@ -341,7 +629,7 @@
     }
 
     public void moveTo(float pix_x0, float pix_y0) {
-        close();
+        closePath();
         this.pix_sx0 = pix_x0;
         this.pix_sy0 = pix_y0;
         this.y0 = tosubpixy(pix_y0);
@@ -350,39 +638,102 @@
 
     public void lineJoin() { /* do nothing */ }
 
-    public void lineTo(float pix_x1, float pix_y1) {
-        float x1 = tosubpixx(pix_x1);
-        float y1 = tosubpixy(pix_y1);
+    private final float[][] pts = new float[2][8];
+    private final float[] ts = new float[4];
 
-        // Ignore horizontal lines
-        if (y0 == y1) {
-            this.x0 = x1;
-            return;
+    private static void invertPolyPoints(float[] pts, int off, int type) {
+        for (int i = off, j = off + type - 2; i < j; i += 2, j -= 2) {
+            float tmp = pts[i];
+            pts[i] = pts[j];
+            pts[j] = tmp;
+            tmp = pts[i+1];
+            pts[i+1] = pts[j+1];
+            pts[j+1] = tmp;
         }
-
-        addEdge(x0, y0, x1, y1);
-
-        this.x0 = x1;
-        this.y0 = y1;
     }
 
-    public void close() {
+    // return orientation before making the curve upright.
+    private static int makeMonotonicCurveUpright(float[] pts, int off, int type) {
+        float y0 = pts[off + 1];
+        float y1 = pts[off + type - 1];
+        if (y0 > y1) {
+            invertPolyPoints(pts, off, type);
+            return -1;
+        } else if (y0 < y1) {
+            return 1;
+        }
+        return 0;
+    }
+
+    public void lineTo(float pix_x1, float pix_y1) {
+        pts[0][0] = x0; pts[0][1] = y0;
+        pts[0][2] = tosubpixx(pix_x1); pts[0][3] = tosubpixy(pix_y1);
+        int or = makeMonotonicCurveUpright(pts[0], 0, 4);
+        somethingTo(pts[0], 4, or);
+    }
+
+    Curve c = new Curve();
+    private void curveOrQuadTo(int type) {
+        c.set(pts[0], type);
+        int numTs = c.dxRoots(ts, 0);
+        numTs += c.dyRoots(ts, numTs);
+        numTs = Helpers.filterOutNotInAB(ts, 0, numTs, 0, 1);
+        Helpers.isort(ts, 0, numTs);
+
+        Iterator<float[]> it = Curve.breakPtsAtTs(pts, type, ts, numTs);
+        while(it.hasNext()) {
+            float[] curCurve = it.next();
+            int or = makeMonotonicCurveUpright(curCurve, 0, type);
+            somethingTo(curCurve, type, or);
+        }
+    }
+
+    @Override public void curveTo(float x1, float y1,
+                                  float x2, float y2,
+                                  float x3, float y3)
+    {
+        pts[0][0] = x0; pts[0][1] = y0;
+        pts[0][2] = tosubpixx(x1); pts[0][3] = tosubpixy(y1);
+        pts[0][4] = tosubpixx(x2); pts[0][5] = tosubpixy(y2);
+        pts[0][6] = tosubpixx(x3); pts[0][7] = tosubpixy(y3);
+        curveOrQuadTo(8);
+    }
+
+    @Override public void quadTo(float x1, float y1, float x2, float y2) {
+        pts[0][0] = x0; pts[0][1] = y0;
+        pts[0][2] = tosubpixx(x1); pts[0][3] = tosubpixy(y1);
+        pts[0][4] = tosubpixx(x2); pts[0][5] = tosubpixy(y2);
+        curveOrQuadTo(6);
+    }
+
+    public void closePath() {
         // lineTo expects its input in pixel coordinates.
         lineTo(pix_sx0, pix_sy0);
     }
 
-    public void end() {
-        close();
+    public void pathDone() {
+        closePath();
     }
 
-    private void _endRendering() {
+
+    @Override
+    public long getNativeConsumer() {
+        throw new InternalError("Renderer does not use a native consumer.");
+    }
+
+    private void _endRendering(final int pix_bboxx0, final int pix_bboxy0,
+                               final int pix_bboxx1, final int pix_bboxy1)
+    {
         // Mask to determine the relevant bit of the crossing sum
         // 0x1 if EVEN_ODD, all bits if NON_ZERO
         int mask = (windingRule == WIND_EVEN_ODD) ? 0x1 : ~0x0;
 
         // add 1 to better deal with the last pixel in a pixel row.
-        int width = ((boundsMaxX - boundsMinX) >> SUBPIXEL_LG_POSITIONS_X) + 1;
-        byte[] alpha = new byte[width+1];
+        int width = pix_bboxx1 - pix_bboxx0 + 1;
+        int[] alpha = new int[width+1];
+
+        int bboxx0 = pix_bboxx0 << SUBPIXEL_LG_POSITIONS_X;
+        int bboxx1 = pix_bboxx1 << SUBPIXEL_LG_POSITIONS_X;
 
         // Now we iterate through the scanlines. We must tell emitRow the coord
         // of the first non-transparent pixel, so we must keep accumulators for
@@ -394,33 +745,34 @@
         int pix_minX = Integer.MAX_VALUE;
 
         int y = boundsMinY; // needs to be declared here so we emit the last row properly.
-        ScanLineItInitialize();
-        for ( ; ScanLineItHasNext(); ) {
-            int numCrossings = ScanLineItGoToNextYAndComputeCrossings();
-            y = ScanLineItCurrentY();
+        ScanlineIterator it = this.new ScanlineIterator();
+        for ( ; it.hasNext(); ) {
+            int numCrossings = it.next();
+            int[] crossings = it.crossings;
+            y = it.curY();
 
             if (numCrossings > 0) {
                 int lowx = crossings[0] >> 1;
                 int highx = crossings[numCrossings - 1] >> 1;
-                int x0 = Math.max(lowx, boundsMinX);
-                int x1 = Math.min(highx, boundsMaxX);
+                int x0 = Math.max(lowx, bboxx0);
+                int x1 = Math.min(highx, bboxx1);
 
                 pix_minX = Math.min(pix_minX, x0 >> SUBPIXEL_LG_POSITIONS_X);
                 pix_maxX = Math.max(pix_maxX, x1 >> SUBPIXEL_LG_POSITIONS_X);
             }
 
             int sum = 0;
-            int prev = boundsMinX;
+            int prev = bboxx0;
             for (int i = 0; i < numCrossings; i++) {
                 int curxo = crossings[i];
                 int curx = curxo >> 1;
                 int crorientation = ((curxo & 0x1) == 0x1) ? 1 : -1;
                 if ((sum & mask) != 0) {
-                    int x0 = Math.max(prev, boundsMinX);
-                    int x1 = Math.min(curx, boundsMaxX);
+                    int x0 = Math.max(prev, bboxx0);
+                    int x1 = Math.min(curx, bboxx1);
                     if (x0 < x1) {
-                        x0 -= boundsMinX; // turn x0, x1 from coords to indeces
-                        x1 -= boundsMinX; // in the alpha array.
+                        x0 -= bboxx0; // turn x0, x1 from coords to indeces
+                        x1 -= bboxx0; // in the alpha array.
 
                         int pix_x = x0 >> SUBPIXEL_LG_POSITIONS_X;
                         int pix_xmaxm1 = (x1 - 1) >> SUBPIXEL_LG_POSITIONS_X;
@@ -442,6 +794,9 @@
                 prev = curx;
             }
 
+            // even if this last row had no crossings, alpha will be zeroed
+            // from the last emitRow call. But this doesn't matter because
+            // maxX < minX, so no row will be emitted to the cache.
             if ((y & SUBPIXEL_MASK_Y) == SUBPIXEL_MASK_Y) {
                 emitRow(alpha, y >> SUBPIXEL_LG_POSITIONS_Y, pix_minX, pix_maxX);
                 pix_minX = Integer.MAX_VALUE;
@@ -453,47 +808,53 @@
         if (pix_maxX >= pix_minX) {
             emitRow(alpha, y >> SUBPIXEL_LG_POSITIONS_Y, pix_minX, pix_maxX);
         }
-        pix_bboxX0 = minX >> SUBPIXEL_LG_POSITIONS_X;
-        pix_bboxX1 = maxX >> SUBPIXEL_LG_POSITIONS_X;
-        pix_bboxY0 = minY >> SUBPIXEL_LG_POSITIONS_Y;
-        pix_bboxY1 = maxY >> SUBPIXEL_LG_POSITIONS_Y;
     }
 
+    public void endRendering() {
+        final int bminx = boundsMinX >> SUBPIXEL_LG_POSITIONS_X;
+        final int bmaxx = boundsMaxX >> SUBPIXEL_LG_POSITIONS_X;
+        final int bminy = boundsMinY >> SUBPIXEL_LG_POSITIONS_Y;
+        final int bmaxy = boundsMaxY >> SUBPIXEL_LG_POSITIONS_Y;
+        final int eminx = ((int)Math.floor(edgeMinX)) >> SUBPIXEL_LG_POSITIONS_X;
+        final int emaxx = ((int)Math.ceil(edgeMaxX)) >> SUBPIXEL_LG_POSITIONS_X;
+        final int eminy = ((int)Math.floor(edgeMinY)) >> SUBPIXEL_LG_POSITIONS_Y;
+        final int emaxy = ((int)Math.ceil(edgeMaxY)) >> SUBPIXEL_LG_POSITIONS_Y;
 
-    public void endRendering() {
-        // Set up the cache to accumulate the bounding box
-        if (cache != null) {
-            cache.bboxX0 = Integer.MAX_VALUE;
-            cache.bboxY0 = Integer.MAX_VALUE;
-            cache.bboxX1 = Integer.MIN_VALUE;
-            cache.bboxY1 = Integer.MIN_VALUE;
+        final int minX = Math.max(bminx, eminx);
+        final int maxX = Math.min(bmaxx, emaxx);
+        final int minY = Math.max(bminy, eminy);
+        final int maxY = Math.min(bmaxy, emaxy);
+        if (minX > maxX || minY > maxY) {
+            this.cache = new PiscesCache(bminx, bminy, bmaxx, bmaxy);
+            return;
         }
 
-        _endRendering();
+        this.cache = new PiscesCache(minX, minY, maxX, maxY);
+        _endRendering(minX, minY, maxX, maxY);
     }
 
-    public void getBoundingBox(int[] pix_bbox) {
-        pix_bbox[0] = pix_bboxX0;
-        pix_bbox[1] = pix_bboxY0;
-        pix_bbox[2] = pix_bboxX1 - pix_bboxX0;
-        pix_bbox[3] = pix_bboxY1 - pix_bboxY0;
+    public PiscesCache getCache() {
+        if (cache == null) {
+            throw new InternalError("cache not yet initialized");
+        }
+        return cache;
     }
 
-    private void emitRow(byte[] alphaRow, int pix_y, int pix_from, int pix_to) {
+    private void emitRow(int[] alphaRow, int pix_y, int pix_from, int pix_to) {
         // Copy rowAA data into the cache if one is present
         if (cache != null) {
             if (pix_to >= pix_from) {
-                cache.startRow(pix_y, pix_from, pix_to);
+                cache.startRow(pix_y, pix_from);
 
                 // Perform run-length encoding and store results in the cache
-                int from = pix_from - (boundsMinX >> SUBPIXEL_LG_POSITIONS_X);
-                int to = pix_to - (boundsMinX >> SUBPIXEL_LG_POSITIONS_X);
+                int from = pix_from - cache.bboxX0;
+                int to = pix_to - cache.bboxX0;
 
                 int runLen = 1;
-                byte startVal = alphaRow[from];
+                int startVal = alphaRow[from];
                 for (int i = from + 1; i <= to; i++) {
-                    byte nextVal = (byte)(startVal + alphaRow[i]);
-                    if (nextVal == startVal && runLen < 255) {
+                    int nextVal = startVal + alphaRow[i];
+                    if (nextVal == startVal) {
                         runLen++;
                     } else {
                         cache.addRLERun(startVal, runLen);
@@ -502,9 +863,8 @@
                     }
                 }
                 cache.addRLERun(startVal, runLen);
-                cache.addRLERun((byte)0, 0);
             }
         }
-        java.util.Arrays.fill(alphaRow, (byte)0);
+        java.util.Arrays.fill(alphaRow, 0);
     }
 }
--- a/src/share/classes/sun/java2d/pisces/Stroker.java	Tue Nov 09 11:45:00 2010 -0800
+++ b/src/share/classes/sun/java2d/pisces/Stroker.java	Tue Nov 09 22:53:18 2010 -0800
@@ -25,10 +25,18 @@
 
 package sun.java2d.pisces;
 
-public class Stroker implements LineSink {
+import java.util.Arrays;
+import java.util.Iterator;
+
+import sun.awt.geom.PathConsumer2D;
+
+// TODO: some of the arithmetic here is too verbose and prone to hard to
+// debug typos. We should consider making a small Point/Vector class that
+// has methods like plus(Point), minus(Point), dot(Point), cross(Point)and such
+public class Stroker implements PathConsumer2D {
 
     private static final int MOVE_TO = 0;
-    private static final int LINE_TO = 1;
+    private static final int DRAWING_OP_TO = 1; // ie. curve, line, or quad
     private static final int CLOSE = 2;
 
     /**
@@ -61,57 +69,37 @@
      */
     public static final int CAP_SQUARE = 2;
 
-    private final LineSink output;
+    private final PathConsumer2D out;
 
     private final int capStyle;
     private final int joinStyle;
 
-    private final float m00, m01, m10, m11, det;
+    private final float lineWidth2;
 
-    private final float lineWidth2;
-    private final float scaledLineWidth2;
-
-    // For any pen offset (pen_dx, pen_dy) that does not depend on
-    // the line orientation, the pen should be transformed so that:
-    //
-    // pen_dx' = m00*pen_dx + m01*pen_dy
-    // pen_dy' = m10*pen_dx + m11*pen_dy
-    //
-    // For a round pen, this means:
-    //
-    // pen_dx(r, theta) = r*cos(theta)
-    // pen_dy(r, theta) = r*sin(theta)
-    //
-    // pen_dx'(r, theta) = r*(m00*cos(theta) + m01*sin(theta))
-    // pen_dy'(r, theta) = r*(m10*cos(theta) + m11*sin(theta))
-    private int numPenSegments;
-    private final float[] pen_dx;
-    private final float[] pen_dy;
-    private boolean[] penIncluded;
-    private final float[] join;
-
-    private final float[] offset = new float[2];
-    private float[] reverse = new float[100];
+    private final float[][] offset = new float[3][2];
     private final float[] miter = new float[2];
     private final float miterLimitSq;
 
     private int prev;
-    private int rindex;
-    private boolean started;
-    private boolean lineToOrigin;
-    private boolean joinToOrigin;
 
-    private float sx0, sy0, sx1, sy1, x0, y0, px0, py0;
-    private float mx0, my0, omx, omy;
+    // The starting point of the path, and the slope there.
+    private float sx0, sy0, sdx, sdy;
+    // the current point and the slope there.
+    private float cx0, cy0, cdx, cdy; // c stands for current
+    // vectors that when added to (sx0,sy0) and (cx0,cy0) respectively yield the
+    // first and last points on the left parallel path. Since this path is
+    // parallel, it's slope at any point is parallel to the slope of the
+    // original path (thought they may have different directions), so these
+    // could be computed from sdx,sdy and cdx,cdy (and vice versa), but that
+    // would be error prone and hard to read, so we keep these anyway.
+    private float smx, smy, cmx, cmy;
 
-    private float m00_2_m01_2;
-    private float m10_2_m11_2;
-    private float m00_m10_m01_m11;
+    private final PolyStack reverse = new PolyStack();
 
     /**
      * Constructs a <code>Stroker</code>.
      *
-     * @param output an output <code>LineSink</code>.
+     * @param pc2d an output <code>PathConsumer2D</code>.
      * @param lineWidth the desired line width in pixels
      * @param capStyle the desired end cap style, one of
      * <code>CAP_BUTT</code>, <code>CAP_ROUND</code> or
@@ -120,183 +108,61 @@
      * <code>JOIN_MITER</code>, <code>JOIN_ROUND</code> or
      * <code>JOIN_BEVEL</code>.
      * @param miterLimit the desired miter limit
-     * @param transform a <code>Transform4</code> 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 @@
             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;
 
-        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);
+        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;
         }
     }
 
-    // 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) {
+    // 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);
+    }
+
+    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 @@
             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;</