changeset 2185:3819833c0c51 8.0-b72

branch merge
author David Grieve<david.grieve@oracle.com>
date Wed, 09 Jan 2013 17:07:00 -0500
parents db5a24110e22 47cab056c6f3
children 77f24088cf92 6abab59e4fa1
files deploy/.classpath deploy/.project javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TextAreaBehavior.java javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextAreaSkin.java javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextFieldSkin.java javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TreeTableRowSkin.java
diffstat 26 files changed, 1808 insertions(+), 824 deletions(-) [+]
line wrap: on
line diff
--- a/.classpath	Thu Jan 10 10:20:41 2013 +1300
+++ b/.classpath	Wed Jan 09 17:07:00 2013 -0500
@@ -2,6 +2,10 @@
 <classpath>
 	<classpathentry kind="src" path="decora-compiler/build/gensrc"/>
 	<classpathentry kind="src" path="decora-compiler/src"/>
+	<classpathentry kind="src" path="deploy/javafx-deploy/src"/>
+	<classpathentry kind="src" path="deploy/javafx-launcher/src"/>
+	<classpathentry kind="src" path="deploy/packager/src"/>
+	<classpathentry kind="src" path="deploy/packager/test"/>	
 	<classpathentry kind="src" path="javafx-anim/src"/>
 	<classpathentry kind="src" path="javafx-anim/build/builders"/>
 	<classpathentry kind="src" path="javafx-anim/test/unit"/>
@@ -44,6 +48,7 @@
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
 	<classpathentry kind="lib" path="../import/antlr-3.1.3/antlr-3.1.3/lib/antlr-3.1.3.jar"/>
+	<classpathentry kind="lib" path="../import/findbugs-2.0.1/findbugs-2.0.1/lib/ant.jar"/>
 	<classpathentry kind="src" path="/rt-closed"/>
 	<classpathentry kind="src" path="/media"/>
 	<classpathentry kind="output" path="bin"/>
--- a/.hgtags	Thu Jan 10 10:20:41 2013 +1300
+++ b/.hgtags	Wed Jan 09 17:07:00 2013 -0500
@@ -58,3 +58,4 @@
 5e68c3c1e45f962c756e57109dc853c94ec9e1a7 8.0-b68
 81dc4ec05f628f1cf925f2b08eb66ba96ae40573 8.0-b69
 cb178c197204c27013eb658d80dbb0f4e17ca1fb 8.0-b70
+c80842bf169ab1d4d2232069dfed37f016bdb239 8.0-b71
--- a/decora-compiler/src/com/sun/scenario/effect/compiler/backend/hw/ES2Backend.java	Thu Jan 10 10:20:41 2013 +1300
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/hw/ES2Backend.java	Wed Jan 09 17:07:00 2013 -0500
@@ -81,7 +81,7 @@
         // shader functions to have lower precision
         String name = d.getFunction().getName();
         if ("mask".equals(name) || "paint".equals(name)) {
-            output("LOWP ");
+            output("lowp ");
         }
         super.visitFuncDef(d);
     }
@@ -112,13 +112,10 @@
         sb.append("#extension GL_OES_standard_derivatives : enable\n");
         sb.append("precision highp float;\n");
         sb.append("precision highp int;\n");
-        sb.append("#define HIGHP highp\n");
-        sb.append("#define MEDIUMP mediump\n");
-        sb.append("#define LOWP lowp\n");
         sb.append("#else\n");
-        sb.append("#define HIGHP\n");
-        sb.append("#define MEDIUMP\n");
-        sb.append("#define LOWP\n");
+        sb.append("#define highp\n");
+        sb.append("#define mediump\n");
+        sb.append("#define lowp\n");
         sb.append("#endif\n");
 
         // output varying value declarations (passed from the vertex shader)
@@ -129,7 +126,7 @@
             sb.append("varying vec2 texCoord1;\n");
         }
         if (isVertexColorReferenced) {
-            sb.append("varying LOWP vec4 perVertexColor;\n");
+            sb.append("varying lowp vec4 perVertexColor;\n");
         }
 
         // output special pixcoord offset uniform variable declaration
--- a/deploy/.classpath	Thu Jan 10 10:20:41 2013 +1300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
-	<classpathentry kind="src" path="lib"/>
-	<classpathentry kind="src" path="javafx-deploy/src"/>
-	<classpathentry kind="src" path="javafx-launcher/src"/>
-	<classpathentry kind="src" path="packager/src"/>
-	<!--
-	<classpathentry kind="src" path="packager/test"/>
-	-->
-	<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
-	<classpathentry combineaccessrules="false" kind="src" path="/rt"/>
-	<classpathentry combineaccessrules="false" kind="src" path="/rt-closed"/>
-	<classpathentry combineaccessrules="false" kind="src" path="/media"/>
-	<classpathentry combineaccessrules="false" kind="src" path="/webnode"/>
-	<classpathentry kind="output" path="bin"/>
-</classpath>
--- a/deploy/.project	Thu Jan 10 10:20:41 2013 +1300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-	<name>deploy</name>
-	<comment></comment>
-	<projects>
-	</projects>
-	<buildSpec>
-		<buildCommand>
-			<name>org.eclipse.jdt.core.javabuilder</name>
-			<arguments>
-			</arguments>
-		</buildCommand>
-	</buildSpec>
-	<natures>
-		<nature>org.eclipse.jdt.core.javanature</nature>
-	</natures>
-</projectDescription>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-annotation-processor/src/javafx/builder/processor/AnnotationUtils.java	Wed Jan 09 17:07:00 2013 -0500
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 javafx.builder.processor;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.TypeParameterElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.*;
+import javax.lang.model.util.Elements;
+import javax.lang.model.util.Types;
+import javax.tools.Diagnostic;
+
+final class AnnotationUtils {
+
+    public static final String inputOption = "javafx.builders.input";
+    public static final String outputOption = "javafx.builders.output";
+    public static final String verboseOption = "javafx.builders.verbose";
+
+    public Types types;
+    public Elements elements; // TODO ? private?
+
+    private NoType voidType;
+    private PrimitiveType booleanType;
+    private TypeMirror rawCollectionType;
+    private TypeMirror rawObservableListType;
+    private ProcessingEnvironment processingEnv;
+    public boolean verbose = false;
+    public Pattern inputPat = Pattern.compile("(javafx\\..*)");
+    private String outputRepl = "$1Builder";
+
+    public AnnotationUtils(ProcessingEnvironment processingEnv) {
+        this.processingEnv = processingEnv;
+
+        types = processingEnv.getTypeUtils();
+        elements = processingEnv.getElementUtils();
+        voidType = types.getNoType(TypeKind.VOID);
+        booleanType = types.getPrimitiveType(TypeKind.BOOLEAN);
+        rawCollectionType = types.getDeclaredType(elements.getTypeElement(Collection.class.getName()));
+        TypeElement observableArrayListType = elements.getTypeElement("javafx.collections.ObservableList");
+        if (observableArrayListType != null) {
+            this.rawObservableListType = types.getDeclaredType(observableArrayListType);
+        }
+        Map<String, String> options = processingEnv.getOptions();
+        if (options.containsKey(verboseOption)) {
+            verbose = Boolean.parseBoolean(options.get(verboseOption));
+        }
+        String input = options.get(inputOption);
+        if (input != null) {
+            try {
+                inputPat = Pattern.compile(input);
+            } catch (PatternSyntaxException e) {
+                error("Value for option " + inputOption + " is not a valid regular expression: " + e.getMessage());
+                throw e;
+            }
+        }
+        if (options.containsKey(outputOption)) {
+            outputRepl = options.get(outputOption);
+        }
+    }
+
+    public void note(String msg) {
+        if (verbose) {
+            processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, msg);
+        }
+    }
+
+    public void warn(String msg) {
+        processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, msg);
+    }
+
+    public void error(String msg) {
+        processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg);
+    }
+
+    public boolean isCollection(TypeMirror type) {
+        return types.isSubtype(types.erasure(type), rawCollectionType);
+    }
+
+    public boolean isObservableList(TypeMirror type) {
+        return (rawObservableListType != null)
+                && types.isSubtype(types.erasure(type), rawObservableListType);
+    }
+
+    public boolean isVoidType(TypeMirror type) {
+        return types.isSameType(voidType, type);
+    }
+
+    public boolean isBooleanType(TypeMirror type) {
+        return types.isSameType(booleanType, type);
+    }
+    
+    public boolean isSameType(TypeMirror t1, TypeMirror t2) {
+        return types.isSameType(t1, t2);
+    }
+
+    public String getBuilderName(String type) {
+        Matcher m = inputPat.matcher(type);
+        if (m.matches()) {
+            String name = m.replaceAll(outputRepl);
+            return name;
+        } else {
+            error("Internal error: pattern does not match " + type);
+            return type + "Builder";
+        }
+    }
+    
+    
+    public TypeElement getBuilderExtension(TypeElement type) {        
+        return elements.getTypeElement("com.sun." + type.getQualifiedName() + "BuilderExtension");
+    }
+
+    // A string of the type parameters of this type, without the enclosing <>. For List<E>, it will be "E";
+    // for Integer, it will be ""; for Map<K, V>, it will be "K, V".
+    // If there is an "extends" clause it will be included, so for example
+    // ValueAxis<T extends Number> will return "T extends Number"
+    public static String typeParameterString(TypeElement type) {
+        String s = "";
+        for (TypeParameterElement p : type.getTypeParameters()) {
+            if (!s.isEmpty()) {
+                s += ", ";
+            }
+            s += p;
+            String b = p.getBounds().toString();
+            if (b.startsWith("[") && b.endsWith("]")) {
+                b = b.substring(1, b.length() - 1).trim();
+            }
+            if (!b.equals("java.lang.Object")) {
+                s += " extends " + b;
+            }
+        }
+        return s;
+    }
+
+    // A string of the type arguments of this type. Given ValueAxis<T> extends Axis<T>, if we ask about
+    // Axis<T> then the returned string will be "T".
+    public static String typeArgumentString(TypeMirror type0) {
+        DeclaredType type = (DeclaredType) type0;
+        String s = "";
+        for (TypeMirror p : type.getTypeArguments()) {
+            if (!s.isEmpty()) {
+                s += ", ";
+            }
+            s += p;
+        }
+        return s;
+    }
+
+    // returns String with arguments of a method
+    // E.g. for resize(x, y) it returns "x, y"
+    public static String methodCallParameterString(ExecutableElement type) {
+        StringBuilder sb = new StringBuilder();
+
+        for (VariableElement p : type.getParameters()) {
+            if (sb.length() > 0) {
+                sb.append(", ");
+            }
+            sb.append(p.getSimpleName());
+        }
+        return sb.toString();
+    }
+
+    // returns String with arguments with types of a method
+    // E.g. for resize(int x, int y) it returns "int x, int y"
+    public static String methodParameterString(ExecutableElement type) {
+        StringBuilder sb = new StringBuilder();
+        for (VariableElement p : type.getParameters()) {
+            if (sb.length() > 0) {
+                sb.append(", ");
+            }
+
+            TypeMirror paramType = p.asType();
+            if (paramType.getKind() == TypeKind.ARRAY) {
+                sb.append(((ArrayType) paramType).getComponentType());
+                sb.append(type.isVarArgs() ? "..." : "[]");
+            } else {
+                sb.append(p.asType());
+            }
+
+            sb.append(" ");
+            sb.append(p.getSimpleName());
+        }
+
+        return sb.toString();
+    }
+
+    // Returns parameters of typed create()
+    // e.g. for this create:
+    // public static <T> ChoiceBoxBuilder<T, ?> create(final Class<T> type1)
+    // it returns final Class<T> type1
+    public static String typedCreateParamString(TypeElement type) {
+        StringBuilder sb = new StringBuilder();
+        int i = 0;
+        for (TypeParameterElement p : type.getTypeParameters()) {
+            if (sb.length() > 0) {
+                sb.append("> type");
+                sb.append(i);
+                sb.append(" , ");
+            }
+            sb.append("final Class<");
+            sb.append(p);
+            i++;
+        }
+        sb.append("> type");
+        sb.append(i);
+
+        return sb.toString();
+    }
+
+    // Returns a string of the type arguments for non-typed create()
+    // e.g. <?, ?> in
+    // public static javafx.scene.control.ChoiceBoxBuilder<?, ?> create()
+    public static String nonTypedCreateArgumentString(TypeElement type, boolean isFinal) {
+        StringBuilder sb = new StringBuilder();
+        for (int j = 1; j <= type.getTypeParameters().size(); j++) {
+            if (sb.length() > 0) {
+                sb.append(", ");
+            }
+            sb.append("?");
+        }
+        if (!isFinal) {
+            sb.append(", ?");
+        }
+        return sb.toString();
+    }
+
+    public static boolean hasOneArgument(TypeMirror type) {
+        return (type instanceof DeclaredType) 
+                && (((DeclaredType) type).getTypeArguments().size() == 1);
+    }
+
+    // Returns true, if the type is a "wildcard type" e.g.
+    // List<? extend Color>
+    public static boolean isWildcardType(TypeMirror type) {
+        boolean result = false;
+        if (type instanceof DeclaredType) {
+            DeclaredType dType = (DeclaredType) type;
+            for (TypeMirror typeArg : dType.getTypeArguments()) {
+                if (typeArg instanceof WildcardType) {
+                    result = true;
+                    break;
+                }
+            }
+        }
+        return result;
+    }
+}
--- a/javafx-annotation-processor/src/javafx/builder/processor/BuilderProcessor.java	Thu Jan 10 10:20:41 2013 +1300
+++ b/javafx-annotation-processor/src/javafx/builder/processor/BuilderProcessor.java	Wed Jan 09 17:07:00 2013 -0500
@@ -24,12 +24,7 @@
  */
 package javafx.builder.processor;
 
-import com.sun.javafx.beans.annotations.DuplicateInBuilderProperties;
-import com.sun.javafx.beans.annotations.Default;
 import com.sun.javafx.beans.annotations.NoBuilder;
-import com.sun.javafx.beans.annotations.NoInit;
-import com.sun.javafx.collections.annotations.ReturnsUnmodifiableCollection;
-import java.beans.Introspector;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.Writer;
@@ -37,26 +32,18 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
-import java.util.Collection;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.PropertyResourceBundle;
 import java.util.ResourceBundle;
 import java.util.Set;
-import java.util.SortedSet;
 import java.util.TreeMap;
-import java.util.TreeSet;
-import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-import java.util.regex.PatternSyntaxException;
 import javax.annotation.Generated;
 import javax.annotation.processing.AbstractProcessor;
-import javax.annotation.processing.Filer;
 import javax.annotation.processing.RoundEnvironment;
 import javax.annotation.processing.SupportedAnnotationTypes;
 import javax.annotation.processing.SupportedOptions;
@@ -65,18 +52,11 @@
 import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.Modifier;
 import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.TypeParameterElement;
 import javax.lang.model.element.VariableElement;
 import javax.lang.model.type.DeclaredType;
 import javax.lang.model.type.NoType;
-import javax.lang.model.type.PrimitiveType;
-import javax.lang.model.type.TypeKind;
 import javax.lang.model.type.TypeMirror;
-import javax.lang.model.type.WildcardType;
 import javax.lang.model.util.ElementFilter;
-import javax.lang.model.util.Elements;
-import javax.lang.model.util.Types;
-import javax.tools.Diagnostic;
 import javax.tools.JavaFileObject;
 
 /**
@@ -96,40 +76,13 @@
  */
 @SupportedAnnotationTypes("*")
 @SupportedOptions({
-    BuilderProcessor.inputOption, BuilderProcessor.outputOption, BuilderProcessor.verboseOption
+    AnnotationUtils.inputOption, AnnotationUtils.outputOption, AnnotationUtils.verboseOption
 })
 public class BuilderProcessor extends AbstractProcessor {
-    static final String inputOption = "javafx.builders.input";
-    static final String outputOption = "javafx.builders.output";
-    static final String verboseOption = "javafx.builders.verbose";
-
-    private Types types;
-    private Elements elements;
-    private NoType voidType;
-    private PrimitiveType booleanType;
-    private Filer filer;
-    private Pattern inputPat = Pattern.compile("(javafx\\..*)");
-    private String outputRepl = "$1Builder";
-    private boolean verbose;
-    private TypeMirror rawCollectionType;
-    private TypeMirror rawObservableListType;
+    private AnnotationUtils utils;
 
     private final Set<String> builderNames = new HashSet<String>();
 
-    private void note(String msg) {
-        if (verbose) {
-            processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, msg);
-        }
-    }
-
-    private void warn(String msg) {
-        processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, msg);
-    }
-
-    private void error(String msg) {
-        processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, msg);
-    }
-
     // We are asserting here that this processor can handle anything that new versions of the language can
     // throw at it.  That's probably true, and even if it isn't we can always rewrite.
     @Override
@@ -153,157 +106,26 @@
     // the method is called with an empty set of root elements.
     @Override
     public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
-        Map<String, String> options = processingEnv.getOptions();
-        if (options.containsKey(verboseOption)) {
-            verbose = Boolean.parseBoolean(options.get(verboseOption));
-        }
-        note("BuilderProcessor runs");
-        String input = options.get(inputOption);
-        if (input != null) {
-            try {
-                inputPat = Pattern.compile(input);
-            } catch (PatternSyntaxException e) {
-                error("Value for option " + inputOption + " is not a valid regular expression: " + e.getMessage());
-                return false;
-            }
-        }
-        if (options.containsKey(outputOption)) {
-            outputRepl = options.get(outputOption);
-        }
-        types = processingEnv.getTypeUtils();
-        elements = processingEnv.getElementUtils();
-        voidType = types.getNoType(TypeKind.VOID);
-        booleanType = types.getPrimitiveType(TypeKind.BOOLEAN);
-        filer = processingEnv.getFiler();
-        rawCollectionType = types.getDeclaredType(elements.getTypeElement(Collection.class.getName()));
-        TypeElement observableArrayListType = elements.getTypeElement("javafx.collections.ObservableList");
-        if (observableArrayListType != null) {
-            rawObservableListType = types.getDeclaredType(observableArrayListType);
-        }
+        utils = new AnnotationUtils(processingEnv);
+        utils.note("BuilderProcessor runs");
 
-        processTypes(ElementFilter.typesIn(roundEnv.getRootElements()));
-        return false;
-    }
-
-    private void processTypes(Set<TypeElement> types) {
-        for (TypeElement type : types) {
+        for (TypeElement type : ElementFilter.typesIn(roundEnv.getRootElements())) {
             if (isCandidateType(type)) {
                 processType(type);
             }
         }
+        return false;
     }
 
     private boolean isCandidateType(TypeElement type) {
         String typeName = type.toString();
         return (!builderNames.contains(typeName) &&
-                inputPat.matcher(type.toString()).matches() &&
+                utils.inputPat.matcher(type.toString()).matches() &&
+                !typeName.endsWith("BuilderExtension") &&
                 type.getKind() == ElementKind.CLASS &&
                 type.getModifiers().contains(Modifier.PUBLIC));
     }
 
-    // The result of scanning a class.
-    private static class Scanned {
-        // The properties that are defined in this class or inherited from the superclass.
-        // The name of each property is mapped to its getter.
-        final Map<String, ExecutableElement> properties = new TreeMap<String, ExecutableElement>(String.CASE_INSENSITIVE_ORDER);
-
-        // The properties (local or inherited) that are set by the chosen constructor of this class.
-        // Each property is mapped to an initializer-expression string specified by @Default, or empty string if none
-        final Map<String, String> constructorProperties = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
-
-        // Since constructorProperties loses the original order of the constructor arguments, we save them separately.
-        // We originally used a LinkedHashMap to keep the original order, but that didn't give us an easy way to ensure
-        // case-insensitivity.
-        final List<String> constructorParameters = new ArrayList<String>();
-
-        // Which properties (local or inherited) have setters.
-        final Set<String> propertiesWithSetters = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
-
-        // Which local properties are of type Collection or a subtype, meaning that they can be changed by
-        // changing the Collection rather than calling a setter.
-        final Set<String> collectionProperties = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
-
-        // Which local properties were marked as @ReturnsUnmodifiableCollection.
-        // We will only generate a method for such a property in the builder
-        // if it is one of the properties set by the constructor.
-        final Set<String> unmodifiableCollectionProperties = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
-
-        // Which properties were marked with @MovedFromSubclass annotation.
-        // Methods for these properties will be generated both for the superclass
-        // and for subclasses
-        final Set<String> movedProperties = new HashSet<String>();
-
-        // The result of scanning the superclass if it exists and is available; otherwise null.
-        final Scanned superScanned;
-
-        // True if the class is abstract or "effectively abstract" (has no public constructor).
-        boolean isAbstract;
-
-        // The expression to produce an instance of the class, an invocation either of a constructor or a factory method.
-        // Does not include arguments, so for example it might be "new javafx.scene.shape.Rectangle".
-        String constructorCall;
-
-        Scanned(Scanned superScanned) {
-            this.superScanned = superScanned;
-        }
-
-        boolean inherits(String property) {
-            return inheritedProperties().contains(property);
-        }
-
-        Set<String> inheritedProperties() {
-            if (superScanned == null) {
-                return Collections.emptySet();
-            } else {
-                return superScanned.properties.keySet();
-            }
-        }
-
-        Set<String> inheritedSetters() {
-            if (superScanned == null) {
-                return Collections.emptySet();
-            } else {
-                return superScanned.propertiesWithSetters;
-            }
-        }
-
-        // Fills the movedProperties set with properties from
-        // @MovedFromSubclass annotation
-        // Also adds these properties into appropriate collections for this
-        // scan class as they need to be processed when making the builder
-        void buildMovedProperties(TypeElement type) {
-            if (superScanned != null) {
-                DuplicateInBuilderProperties annotation = type.getAnnotation(DuplicateInBuilderProperties.class);
-                if (annotation != null) {
-                    for (int i = 0; i < annotation.properties().length; i++) {
-                        String propertyName = annotation.properties()[i];
-                        if (superScanned.propertiesWithSetters.contains(propertyName)) {
-                            propertiesWithSetters.add(propertyName);
-                            movedProperties.add(propertyName);
-                        }
-                        if (superScanned.collectionProperties.contains(propertyName)) {
-                            collectionProperties.add(propertyName);
-                            movedProperties.add(propertyName);
-                        }
-                        if (superScanned.constructorProperties.containsKey(propertyName)) {
-                            constructorProperties.put(propertyName, superScanned.constructorProperties.get(propertyName));
-                            movedProperties.add(propertyName);
-                        }
-                    }
-                }
-            }
-        }
-
-        TypeMirror typeOf(String property) {
-            ExecutableElement getter = properties.get(property);
-            if (getter == null) {
-                return null;
-            } else {
-                return getter.getReturnType();
-            }
-        }
-    }
-
     private Map<TypeElement, Scanned> scanMap = new HashMap<TypeElement, Scanned>();
 
     // Scan the class for properties, determined as follows.  First we look for getters.  A getter is an
@@ -326,287 +148,50 @@
         if (forSuper && scanMap.containsKey(type)) {
             return scanMap.get(type);
         }
-        Scanned scanned = scan1(type, forSuper);
-        scanMap.put(type, scanned);
-        return scanned;
-    }
 
-    private Scanned scan1(TypeElement type, boolean forSuper) {
         Scanned superScanned = null;
         TypeMirror superMirror = type.getSuperclass();
         if (!(superMirror instanceof NoType)) {
-            TypeElement superElement = elements.getTypeElement(types.erasure(superMirror).toString());
+            TypeElement superElement = utils.elements.getTypeElement(utils.types.erasure(superMirror).toString());
             if (superElement != null && isCandidateType(superElement)) {
                 superScanned = scan(superElement, true);
             }
         }
 
-        final Scanned scanned = new Scanned(superScanned);
-        scanned.isAbstract = type.getModifiers().contains(Modifier.ABSTRACT);
-        if (superScanned != null) {
-            scanned.properties.putAll(superScanned.properties);
-            scanned.propertiesWithSetters.addAll(scanned.inheritedSetters());
-        }
-
-        final boolean noBuilder = (type.getAnnotation(NoBuilder.class) != null);
-
-        // Find the properties with explicit getters
-        final List<ExecutableElement> methods = ElementFilter.methodsIn(type.getEnclosedElements());
-        for (ExecutableElement method : methods) {
-            if (method.getModifiers().contains(Modifier.PUBLIC) &&
-                    !method.getModifiers().contains(Modifier.STATIC) &&
-                    !types.isSameType(voidType, method.getReturnType()) &&
-                    method.getParameters().isEmpty() &&
-                    method.getTypeParameters().isEmpty() &&
-                    method.getAnnotation(NoInit.class) == null) {
-                final String name = method.getSimpleName().toString();
-                final int len;
-                if (name.startsWith("get")) {
-                    len = 3;
-                } else if (name.startsWith("is") && types.isSameType(method.getReturnType(), booleanType)) {
-                    len = 2;
-                } else {
-                    len = -1;
-                }
-                if (len > 0 && name.length() > len && !name.equals("getClass")) {
-                    String propertyName = Introspector.decapitalize(name.substring(len));
-                    if (!scanned.inherits(propertyName)) {
-                        TypeMirror propertyType = method.getReturnType();
-                        TypeMirror oldType = scanned.typeOf(propertyName);
-                        scanned.properties.put(propertyName, method);
-                        if (oldType != null && !types.isSameType(oldType, propertyType)) {
-                            warn("Property " + name + " has type " + oldType + " via annotations but type " +
-                                    propertyType + " via getter");
-                            // Could lead to problems with e.g. List<?> which is not equal to itself.
-                        }
-                        if (method.getAnnotation(ReturnsUnmodifiableCollection.class) != null) {
-                            scanned.unmodifiableCollectionProperties.add(propertyName);
-                        }
-                    }
-                }
-            }
-        }
-
-        // If anyone is foolish enough to define a property that is a Java reserved word, then they won't
-        // be able to set it with our generated builder.
-        for (String prop : scanned.properties.keySet()) {
-            if (javaKeyWords.contains(prop)) {
-                if (!noBuilder) {
-                    warn("Property " + type + "." + prop + " is a reserved word");
-                }
-                scanned.properties.remove(prop);
-            }
-        }
-
-        // Find any setters for the properties found above.
-        for (ExecutableElement method : methods) {
-            if (method.getModifiers().contains(Modifier.PUBLIC) &&
-                    !method.getModifiers().contains(Modifier.STATIC) &&
-                    types.isSameType(voidType, method.getReturnType()) &&
-                    method.getParameters().size() == 1 &&
-                    method.getTypeParameters().isEmpty()) {
-                final String name = method.getSimpleName().toString();
-                if (name.startsWith("set") && !name.equals("set")) {
-                    final String propertyName = Introspector.decapitalize(name.substring(3));
-                    TypeMirror getterType = scanned.typeOf(propertyName);
-                    TypeMirror setterType = method.getParameters().get(0).asType();
-                    if (getterType != null && types.isSameType(getterType, setterType)) {
-                        scanned.propertiesWithSetters.add(propertyName);
-                    }
-                }
-            }
-        }
-
-        // We also consider that getters for properties that are Collections (such as List or ObservableList) are
-        // effectively setters since you can replace the contents of the collection.  But if there is a setter
-        // we will prefer that.
-        Iterator<String> it = scanned.properties.keySet().iterator();
-        while (it.hasNext()) {
-            String pName = it.next();
-            TypeMirror pType = scanned.typeOf(pName);
-
-            if (types.isSubtype(types.erasure(pType), rawCollectionType)) {
-                if (isWildcardType(pType)) {
-                    // we ignore wildcard collections (e.g. List<? extend Color>
-                    // because there is no way to add an element to them anyway
-                    it.remove();
-                } else {
-                    boolean added = scanned.propertiesWithSetters.add(pName);
-                    if (added) {
-                        scanned.collectionProperties.add(pName);
-                    }
-                }
-            }
-        }
-
-        // Now we want the constructor that defines the most properties with no setters.  In the case
-        // of immutable classes, this will be the constructor that defines everything.  In the case
-        // of completely-mutable classes, this will typically be the no-arg constructor.  In the case
-        // of partly-mutable classes, this will be the constructor that defines all the immutable propeties.
-        // If there is a tie between two constructors then we choose the one that has the fewest parameters,
-        // which means that it sets the fewest properties that could also be set with setters.
-        ExecutableElement chosenConstructor;
-
-        chosenConstructor = chooseConstructor(type, scanned, Modifier.PUBLIC);
-        if (chosenConstructor == null && !scanned.propertiesWithSetters.isEmpty()) {
-            // If there is no public constructor but there are protected ones then we consider those,
-            // but we also mark the builder as abstract.  If the class has no setters (is immutable)
-            // with a protected constructor, then we will not make a buider for it.
-            chosenConstructor = chooseConstructor(type, scanned, Modifier.PROTECTED);
-            if (chosenConstructor != null) {
-                scanned.isAbstract = true;
-            }
-        }
-
-        if (chosenConstructor == null) {
-            if (!scanned.isAbstract) {
-                if (!forSuper && !noBuilder && scanned.properties.size() > 1) {
-                    warn("Cannot make builder for " + type +
-                            " because no constructor specifies only properties as parameters");
-                }
-                return new Scanned(null);
-            }
-        } else {
-            if (chosenConstructor.getKind() == ElementKind.CONSTRUCTOR) {
-                scanned.constructorCall = "new " + type;
-            } else {
-                scanned.constructorCall = type + "." + chosenConstructor.getSimpleName();
-            }
-
-            List<String> missingDefaults = new ArrayList<String>();
-            for (VariableElement param : chosenConstructor.getParameters()) {
-                String pName = param.getSimpleName().toString();
-                Default def = param.getAnnotation(Default.class);
-                String defaultInit;
-                if (def == null) {
-                    missingDefaults.add(pName);
-                    defaultInit = "";
-                } else {
-                    defaultInit = def.value();
-                }
-                scanned.constructorProperties.put(pName, defaultInit);
-                scanned.constructorParameters.add(setGet((SortedSet<String>) scanned.properties.keySet(), pName));
-            }
-
-            if (verbose && !noBuilder && !missingDefaults.isEmpty()) {
-                warn("Constructor does not specify @Default for parameters " + missingDefaults + ": " + chosenConstructor);
-            }
-        }
-
-        // process properties with @MovedFromSubclass annotation
-        scanned.buildMovedProperties(type);
-
+        Scanned scanned = Scanned.createScanned(superScanned, type, forSuper, utils);
+        scanMap.put(type, scanned);
         return scanned;
     }
 
-    // Find the constructor that sets the most immutable properties and the fewest mutable ones.
-    private ExecutableElement chooseConstructor(TypeElement type, Scanned scanned, Modifier access) {
-        ExecutableElement best = null;
-        int bestImmutables = -1;
-        int bestCount = -1;
-
-        final List<ExecutableElement> constructors =
-                new ArrayList<ExecutableElement>(ElementFilter.constructorsIn(type.getEnclosedElements()));
-
-        // It turns out that this is not appropriate, so it's disabled for now.  We may at some future point
-        // restore support for factories, probably with an explicit @Factory annotation.
-        if (false) {
-            // We rather hackily consider that static methods with the same name as the class they are in,
-            // ignoring case, are factory methods equivalent to constructors, as in Font.font and Color.color.
-            // If both a factory method and a constructor are "best", then we prefer the factory method on the
-            // grounds that it may be able to reuse instances and the like.
-            for (ExecutableElement factory : ElementFilter.methodsIn(type.getEnclosedElements())) {
-                if (factory.getModifiers().contains(Modifier.STATIC) &&
-                        factory.getSimpleName().toString().equalsIgnoreCase(type.getSimpleName().toString())) {
-                    constructors.add(factory);
-                }
-            }
-        }
-
-        for (ExecutableElement constructor : constructors) {
-            if (constructor.getModifiers().contains(access) && constructor.getTypeParameters().isEmpty()) {
-                int immutables = 0;
-                for (VariableElement param : constructor.getParameters()) {
-                    final String pName = param.getSimpleName().toString();
-                    final TypeMirror pType = scanned.typeOf(pName);
-                    if (pType == null ||
-                            (!types.isSameType(param.asType(), pType) && !param.asType().toString().equals(pType.toString()))) {
-                        // This area is a bit messy. Really we should be determining whether the parameter is a subtype of
-                        // the (possibly inherited) property type. But if it is a strict subtype then we need to adjust the
-                        // inherited type, so that for example InputEvent's constructor which takes an EventType<? extends InputEvent>
-                        // would cause the builder to have a field of that type, even though the corresponding property
-                        // inherited from Event is an EventType<? extends Event>. For now, we forgo some possibilities
-                        // to generate builders.
-                        immutables = -1;
-                        break;
-                    }
-                    if (!scanned.propertiesWithSetters.contains(pName)) {
-                        immutables++;
-                    }
-                }
-                final int count = constructor.getParameters().size();
-                if (immutables > bestImmutables || (immutables == bestImmutables && count < bestCount) ||
-                        (immutables == bestImmutables && count == bestCount && best != null &&
-                         best.getKind() == ElementKind.CONSTRUCTOR && constructor.getKind() == ElementKind.METHOD)) {
-                    // That last giant conjunct is where we prefer static factory methods to constructors,
-                    // all else being equal.
-                    best = constructor;
-                    bestImmutables = immutables;
-                    bestCount = count;
-                }
-            }
-        }
-
-        return best;
-    }
-
     private void processType(TypeElement type) {
-        note("BuilderProcessor: process " + type);
+        utils.note("BuilderProcessor: process " + type);
 
         Scanned scanned = scan(type, false);
-
-        Set<String> buildablePropertyNames = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
-        buildablePropertyNames.addAll(scanned.propertiesWithSetters);
-        buildablePropertyNames.removeAll(scanned.inheritedSetters());
-        buildablePropertyNames.removeAll(scanned.unmodifiableCollectionProperties);
-        buildablePropertyNames.addAll(scanned.constructorProperties.keySet());
-        buildablePropertyNames.addAll(scanned.movedProperties);
-
-        Map<String, ExecutableElement> notBuildable = new TreeMap<String, ExecutableElement>(String.CASE_INSENSITIVE_ORDER);
-        notBuildable.putAll(scanned.properties);
-        notBuildable.keySet().removeAll(buildablePropertyNames);
-        notBuildable.keySet().removeAll(scanned.inheritedProperties());
+        Set<String> buildablePropertyNames = scanned.getBuildablePropertyNames();
 
         if (type.getAnnotation(NoBuilder.class) != null) {
             return;
         }
 
         // No properties, no builder
-        if (buildablePropertyNames.isEmpty() && scanned.inheritedSetters().isEmpty()) {
+        if (buildablePropertyNames.isEmpty() &&
+                !scanned.hasInheritedSetters() &&
+                !scanned.hasBuilderExtension()) {
             // We still want a builder if the parent has properties, since the generated builder will
             // construct the right type of object even though you will only be able to set the inherited properties.
+            //
+            // Also the builder methods may be specified by BuilderExtension
+            // so we want to construct the builder every time we have a BuilderExtension            
             return;
         }
 
         try {
             makeBuilder(type, scanned, buildablePropertyNames);
         } catch (IOException e) {
-            if (verbose) {
+            if (utils.verbose) {
                 e.printStackTrace();
             }
-            error("Could not make builder for " + type + ": " + e);
-        }
-    }
-
-    private String builderName(String type) {
-        Matcher m = inputPat.matcher(type);
-        if (m.matches()) {
-            String name = m.replaceAll(outputRepl);
-            builderNames.add(name);
-            return name;
-        } else {
-            error("Internal error: pattern does not match " + type);
-            return type + "Builder";
+            utils.error("Could not make builder for " + type + ": " + e);
         }
     }
 
@@ -638,104 +223,7 @@
                 Calendar.getInstance().get(Calendar.YEAR)
             });
 
-    // A string of the type parameters of this type, without the enclosing <>. For List<E>, it will be "E";
-    // for Integer, it will be ""; for Map<K, V>, it will be "K, V".
-    // If there is an "extends" clause it will be included, so for example
-    // ValueAxis<T extends Number> will return "T extends Number"
-    private static String typeParameterString(TypeElement type) {
-        String s = "";
-        for (TypeParameterElement p : type.getTypeParameters()) {
-            if (!s.isEmpty()) {
-                s += ", ";
-            }
-            s += p;
-            String b = p.getBounds().toString();
-            if (b.startsWith("[") && b.endsWith("]")) {
-                b = b.substring(1, b.length() - 1).trim();
-            }
-            if (!b.equals("java.lang.Object")) {
-                s += " extends " + b;
-            }
-        }
-        return s;
-    }
-
-    // A string of the type arguments of this type. Given ValueAxis<T> extends Axis<T>, if we ask about
-    // Axis<T> then the returned string will be "T".
-    private static String typeArgumentString(TypeMirror type0) {
-        DeclaredType type = (DeclaredType) type0;
-        String s = "";
-        for (TypeMirror p : type.getTypeArguments()) {
-            if (!s.isEmpty()) {
-                s += ", ";
-            }
-            s += p;
-        }
-        return s;
-    }
-
-    // Returns parameters of typed create()
-    // e.g. for this create:
-    // public static <T> ChoiceBoxBuilder<T, ?> create(final Class<T> type1)
-    // it returns final Class<T> type1
-    private String typedCreateParamString(TypeElement type) {
-        String s = "";
-        int i = 0;
-        for (TypeParameterElement p : type.getTypeParameters()) {
-            if (!s.isEmpty()) {
-                s += "> type" + i + " , ";
-            }
-            s += "final Class<";
-            s += p;
-            i++;
-        }
-        s += "> type" + i;
-        return s;
-    }
-
-    // Returns a string of the type arguments for non-typed create()
-    // e.g. <?, ?> in
-    // public static javafx.scene.control.ChoiceBoxBuilder<?, ?> create()
-    private String nonTypedCreateArgumentString(TypeElement type, boolean isFinal) {
-        String p = "";
-        for (int j = 1; j <= type.getTypeParameters().size(); j++) {
-            if (!p.isEmpty()) {
-                p += ", ";
-            }
-            p += "?";
-        }
-        if (!isFinal) {
-            p += ", ?";
-        }
-        return p;
-    }
-
-    private static boolean isWildcardType(TypeMirror type) {
-        boolean result = false;
-        if (type instanceof DeclaredType) {
-            DeclaredType dType = (DeclaredType) type;
-            for (TypeMirror typeArg : dType.getTypeArguments()) {
-                if (typeArg instanceof WildcardType) {
-                    result = true;
-                    break;
-                }
-            }
-        }
-        return result;
-    }
-
     private void makeBuilder(TypeElement type, Scanned scanned, Set<String> buildablePropertyNames) throws IOException {
-
-        if (false) {
-            // We do generate builders even if there is only one property.  Usually you'll just want to
-            // call the constructor in that case, but the builder does give you the option of naming the
-            // parameter, and it can also be inherited by several subclass builders.
-            int n = scanned.inheritedSetters().size() + buildablePropertyNames.size();
-            if (n < 2) {
-                warn("Properties in " + type + ": " + n);
-            }
-        }
-
         // Substitution variables that will be used as we construct the output text.  See rewrite method below.
         // If no value is defined for a var then its value is empty; this is error-prone but simplifies the logic
         // a lot.
@@ -747,7 +235,7 @@
         // A class can also be "effectively final" if it has no visible constructors, but we've already eliminated
         // such classes since we need a constructor in order to build.
 
-        final boolean inherits = !scanned.inheritedSetters().isEmpty();
+        final boolean inherits = scanned.hasInheritedSetters();
         // We only try to inherit from the superclass's builder if it exists and has setters.  If the superclass
         // is immutable then we are potentially missing a chance to reuse its builder's fields and methods, but
         // that case is rather unusual, and would require the builder to access those fields, which are currently
@@ -759,7 +247,8 @@
         buildableProperties.keySet().retainAll(buildablePropertyNames);
 
         vars.put("copyrightComment", copyrightComment);
-        final String builderName = builderName(type.toString());
+        final String builderName = utils.getBuilderName(type.toString());
+        builderNames.add(builderName);
         vars.put("builderName", builderName);
         final String[] tokens = builderName.split("\\.");
         vars.put("shortBuilderName", tokens[tokens.length - 1]);
@@ -770,6 +259,23 @@
         }
         vars.put("simpleName", builderName.substring(lastDot + 1));
 
+        // we need to know name of builderExtension even for classes without one
+        // if their parent class has one
+        // we need to put parent builder extension into construtor
+        vars.put("builderExtensionName", scanned.getBuilderExtensionName());
+        vars.put("builderExtensionAccess","private"); // private for now
+        if (scanned.hasBuilderExtension() || scanned.hasInheritedBuilderExtension()) {
+            vars.put("createBuilderExtension", "new {builderExtensionName}()");
+        }
+        if (scanned.hasBuilderExtension() && !scanned.hasInheritedBuilderExtension()) {
+            // has builder extension so we need to declare it
+            // Disabled for now: (but it is not inherited)
+            vars.put("declareBuilderExtension", "{builderExtensionAccess} final {builderExtensionName} be;");
+            vars.put("accessBuilderExtension", "be");
+        } else {
+            vars.put("accessBuilderExtension", "(({builderExtensionName})be)");
+        }
+
         if (isAbstract) {
             vars.put("abstract", "abstract ");
             // We might inherit from a public constructor, which for now will be deprecated, so suppress that warning.
@@ -780,8 +286,8 @@
             vars.put("create4",     "return new {builderName}();");
             vars.put("create5", "}");
         }
-        final String originalTypeParams = typeParameterString(type);
-        final String typeArgs = typeArgumentString(type.asType());
+        final String originalTypeParams = AnnotationUtils.typeParameterString(type);
+        final String typeArgs = AnnotationUtils.typeArgumentString(type.asType());
         if (originalTypeParams.isEmpty()) {
             vars.put("type", type.toString());
             vars.put("rawType", type.toString());
@@ -791,8 +297,8 @@
             vars.put("type", type + "<" + originalTypeParams + ">");
             vars.put("rawType", type.getQualifiedName().toString());
             vars.put("typeWithoutBounds", type + "<" + typeArgs + ">");
-            vars.put("createParams", typedCreateParamString(type));
-            String nonTypedArgs = nonTypedCreateArgumentString(type, isFinal);
+            vars.put("createParams", AnnotationUtils.typedCreateParamString(type));
+            String nonTypedArgs = AnnotationUtils.nonTypedCreateArgumentString(type, isFinal);
             vars.put("createType2", builderName + "<" + nonTypedArgs + ">");
             if (!isAbstract) {
                 vars.put("createB1", "/** Creates a new instance of {shortBuilderName}. */");
@@ -808,16 +314,16 @@
             // the full declaration of ValueAxisBuilder is
             // public class ValueAxisBuilder<T extends Number, B extends ValueAxisBuilder<T, B>> extends AxisBuilder<T, B>
             // Here we are computing "extends AxisBuilder<T, B>".
-            final String sup = builderName(types.erasure(type.getSuperclass()).toString());
+            final String sup = utils.getBuilderName(utils.types.erasure(type.getSuperclass()).toString());
             vars.put("supB", "B");
-            final String supTypeParams = typeArgumentString(type.getSuperclass());
+            final String supTypeParams = AnnotationUtils.typeArgumentString(type.getSuperclass());
             if (supTypeParams.isEmpty()) {
                 vars.put("extends", " extends " + sup + "<{supB}>");
             } else {
                 vars.put("extends", " extends " + sup + "<" + supTypeParams + ", {supB}>");
             }
         }
-        if (!scanned.isAbstract && isAbstract(scanned.superScanned)) {
+        if (!scanned.isAbstract && Scanned.isAbstract(scanned.superScanned)) {
             vars.put("implements", " implements javafx.util.Builder<{typeWithoutBounds}>");
         }
         final String typeParams;
@@ -854,6 +360,18 @@
 
         vars.put("classjavadoc", "Builder class for " + type.getQualifiedName());
 
+        if (scanned.hasBuilderExtension() || scanned.hasInheritedBuilderExtension()) {
+            vars.put("constructorBuilderExtension1", "{builderExtensionAccess} {simpleName}({builderExtensionName} be) {");
+            if (scanned.hasInheritedBuilderExtension()) {
+                vars.put("constructorBuilderExtension2", "super(be);");
+                vars.put("assingBuilderExtension", "this({createBuilderExtension});");
+            } else {
+                vars.put("constructorBuilderExtension2", "this.be = be;");
+                vars.put("assingBuilderExtension", "this.be = {createBuilderExtension};");
+            }
+            vars.put("constructorBuilderExtension3", "}");
+        }
+
         List<String> lines = rewrite(vars,
                 "{debug}",
                 "{copyrightComment}",
@@ -866,7 +384,14 @@
                 generated,
                 "public {final}{abstract}class {simpleName}{typeParams}{extends}{implements} {",
                     "protected {simpleName}() {",
+                 // should be
+                 // "{constructorAccess} {simpleName}() {",
+                    "{assingBuilderExtension}",
                     "}",
+                    "{declareBuilderExtension}",
+                    "{constructorBuilderExtension1}",
+                    "{constructorBuilderExtension2}",
+                    "{constructorBuilderExtension3}",
                     "",
                     "{create1}",
                     "{create2}",
@@ -881,9 +406,14 @@
                     "{createB5}",
                     "{createB6}"
                 );
+                
+        if (scanned.hasBuilderExtension()) {
+            List<String> be = processBuilderExtension(vars, scanned);
+            lines.addAll(rewrite(vars, be));
+        }
 
-        if (!setters.isEmpty() || inherits) {
-            List<String> applyTo = makeApplyTo(vars, setters, scanned, !scanned.inheritedSetters().isEmpty());
+        if (!setters.isEmpty() || inherits || scanned.hasBuilderExtension()) {
+            List<String> applyTo = makeApplyTo(vars, setters, scanned, inherits);
             lines.addAll(rewrite(vars, applyTo));
             vars.put("applyTo(x)", "applyTo(x);");
         }
@@ -901,7 +431,7 @@
             // an existing object. In either case, we remember {elementType} so that we can use it to provide
             // a varargs setter as well, which will be Color... or whatever.
             if (scanned.collectionProperties.contains(pName) &&
-                    pType instanceof DeclaredType && ((DeclaredType) pType).getTypeArguments().size() == 1) {
+                    AnnotationUtils.hasOneArgument(pType)) {
                 TypeMirror typeArg = ((DeclaredType) pType).getTypeArguments().get(0);
                 if (scanned.constructorProperties.containsKey(pName)) {
                     vars.put("pType", pType.toString());
@@ -992,6 +522,59 @@
 
         makeClass(builderName, type, lines);
     }
+    
+    private List<String> processBuilderExtension(Map<String, Object> vars, Scanned scanned) {
+        final List<String> lines = new ArrayList<String>();
+        
+        for (ExecutableElement method : scanned.builderExtensionMethods) {
+            final String name = method.getSimpleName().toString();
+            String javadoc = utils.elements.getDocComment(method);
+            vars.put("javadoc", javadoc != null ? javadoc : "");
+            vars.put("methodName", name);
+            vars.put("methodTypes", AnnotationUtils.methodParameterString(method));
+            vars.put("methodArgs", AnnotationUtils.methodCallParameterString(method));
+
+            if (scanned.builderExtensionProperties.contains(name) &&
+                scanned.constructorParameters.contains(name)) {
+                    // Special case when we want to change the behavior of 
+                    // otherwise constructed method
+                    // eg. StageBuilder.style(StageStyle x)
+                    // we know it has exactly 1 argument otherwise it would not 
+                    // be put into builderExtensionProperties
+                    VariableElement el = method.getParameters().get(0);
+                    String init = scanned.constructorProperties.get(name);
+                    
+                    if (init == null || init.isEmpty()) {
+                        vars.remove("init");
+                    } else {
+                        vars.put("init", " = " + init);
+                    }
+                    vars.put("argName", el.getSimpleName());
+                    vars.put("pType", el.asType());
+                    vars.put("pName", name);
+                    vars.put("constructorPropertyDef", "private {pType} {pName}{init};");
+                    vars.put("constructorPropertyAssign", "this.{pName} = {argName};");
+            } else {
+                vars.remove("constructorPropertyDef");
+                vars.remove("constructorPropertyAssign");
+            }
+            lines.addAll(rewrite(vars,
+                    "{constructorPropertyDef}", // for constructor args
+                    "/**",
+                    " {javadoc}",
+                    " */",
+                    "{suppressWarnings}",
+                    "public B {methodName}({methodTypes}) {",
+                        "{constructorPropertyAssign}", // for constructor args
+                        "{accessBuilderExtension}.{methodName}({methodArgs});",
+                        "return {cast}this;",
+                    "}",
+                    ""
+                    ));
+        }
+        
+        return lines;
+    }
 
     // This complicated method does two things.  First, it updates |vars| with extra definitions
     // that are appropriate when there will be setter calls at construction time.  Second, it returns
@@ -1000,7 +583,7 @@
     private List<String> makeApplyTo(
             Map<String, Object> vars, List<String> properties, final Scanned scanned, boolean inheritsSetters) {
         int n = properties.size();
-        if (n == 0) {
+        if (n == 0  && !scanned.hasBuilderExtension()) {
             return Collections.emptyList();
         }
 
@@ -1011,7 +594,7 @@
                 String cap = cap(property);
                 if (scanned.collectionProperties.contains(property)) {
                     TypeMirror type = scanned.typeOf(property);
-                    if (rawObservableListType != null && types.isSubtype(types.erasure(type), rawObservableListType)) {
+                    if (utils.isObservableList(type)) {
                         return "x.get" + cap + "().addAll(" + value + ");";
                     } else {
                         return "{ x.get" + cap + "().clear(); x.get" + cap + "().addAll(" + value + "); }";
@@ -1033,69 +616,78 @@
         if (inheritsSetters) {
             lines.add("super.applyTo(x);");
         }
+        
+        // only call applyTo for builderExtension for the top class 
+        // in the hierarchy of inherited builders, otherwise it would
+        // be called more than once (as builder.applyTo calls super.applyTo())
+        if (scanned.hasBuilderExtension() && !scanned.hasInheritedBuilderExtension()) {
+            lines.add("be.applyTo(x);");
+        }
 
-        vars.put("declareBitset", "private {bitset} __set;");
-        if (n == 1) {
-            // If there is only one property then we only need a boolean to record whether it has been set.
-            vars.put("bitset", "boolean");
-            vars.put("setBitI", "__set = true;");
-            lines.addAll(rewrite(vars, "if (__set) " + setterCall.make(properties.get(0))));
-        } else if (n < 8) {
-            // With a small number of properties, we can record them in an int bitset, and use a sequence of ifs
-            // to determine which of them has been set.
-            vars.put("bitset", "int");
-            vars.put("setBitI", "__set |= 1 << {i};");
-            lines.add("int set = __set;");
-            for (int i = 0; i < n; i++) {
-                vars.put("i", i);
-                vars.put("set", setterCall.make(properties.get(i)));
+        if (n > 0) { // empty applyTo for builder extension
+            vars.put("declareBitset", "private {bitset} __set;");
+            if (n == 1) {
+                // If there is only one property then we only need a boolean to record whether it has been set.
+                vars.put("bitset", "boolean");
+                vars.put("setBitI", "__set = true;");
+                lines.addAll(rewrite(vars, "if (__set) " + setterCall.make(properties.get(0))));
+            } else if (n < 8) {
+                // With a small number of properties, we can record them in an int bitset, and use a sequence of ifs
+                // to determine which of them has been set.
+                vars.put("bitset", "int");
+                vars.put("setBitI", "__set |= 1 << {i};");
+                lines.add("int set = __set;");
+                for (int i = 0; i < n; i++) {
+                    vars.put("i", i);
+                    vars.put("set", setterCall.make(properties.get(i)));
+                    lines.addAll(rewrite(vars,
+                            "if ((set & (1 << {i})) != 0) {set}"));
+                }
+            } else {
+                // With many properties, it is cheaper in both code size and time to loop over the bits and determine
+                // which ones have been set.
+                vars.put("setStart", "private void __set(int i) {");
+                vars.put("setBody", "{setBitI}");
+                vars.put("setEnd", "}");
+                vars.put("setBitI", "__set({i});");
+                if (n < 64) {
+                    if (n < 32) {
+                        vars.put("bitset", "int");
+                        vars.put("one", "1");
+                        vars.put("boxedBits", "Integer");
+                    } else {
+                        vars.put("bitset", "long");
+                        vars.put("one", "1L");
+                        vars.put("boxedBits", "Long");
+                    }
+                    vars.put("setBody", "__set |= {one} << i;");
+                    vars.put("loop1", "while (set != 0) {");
+                    vars.put("loop2", "int i = {boxedBits}.numberOfTrailingZeros(set);");
+                    vars.put("loop3", "set &= ~({one} << i);");
+                } else {
+                    // At the time of writing, no classes had more than 64 properties.  (This doesn't include
+                    // inherited properties, so 64 is really quite a lot.)
+                    vars.put("bitset", "java.util.BitSet");
+                    vars.put("declareBitset", "java.util.BitSet __set = new java.util.BitSet();");
+                    vars.put("setBody", "__set.set(i);");
+                    vars.put("loop1", "for (int i = -1; (i = set.nextSetBit(i + 1)) >= 0; ) {");
+                }
                 lines.addAll(rewrite(vars,
-                        "if ((set & (1 << {i})) != 0) {set}"));
+                        "{bitset} set = __set;",
+                        "{loop1}",
+                        "{loop2}",
+                        "{loop3}",
+                        "switch (i) {"));
+                for (int i = 0; i < n; i++) {
+                    vars.put("i", i);
+                    vars.put("set", setterCall.make(properties.get(i)));
+                    lines.addAll(rewrite(vars,
+                            "case {i}: {set} break;"));
+                }
+            lines.add("default: break; // can never happen");
+                lines.add("}"); // switch
+                lines.add("}"); // loop
             }
-        } else {
-            // With many properties, it is cheaper in both code size and time to loop over the bits and determine
-            // which ones have been set.
-            vars.put("setStart", "private void __set(int i) {");
-            vars.put("setBody", "{setBitI}");
-            vars.put("setEnd", "}");
-            vars.put("setBitI", "__set({i});");
-            if (n < 64) {
-                if (n < 32) {
-                    vars.put("bitset", "int");
-                    vars.put("one", "1");
-                    vars.put("boxedBits", "Integer");
-                } else {
-                    vars.put("bitset", "long");
-                    vars.put("one", "1L");
-                    vars.put("boxedBits", "Long");
-                }
-                vars.put("setBody", "__set |= {one} << i;");
-                vars.put("loop1", "while (set != 0) {");
-                vars.put("loop2", "int i = {boxedBits}.numberOfTrailingZeros(set);");
-                vars.put("loop3", "set &= ~({one} << i);");
-            } else {
-                // At the time of writing, no classes had more than 64 properties.  (This doesn't include
-                // inherited properties, so 64 is really quite a lot.)
-                vars.put("bitset", "java.util.BitSet");
-                vars.put("declareBitset", "java.util.BitSet __set = new java.util.BitSet();");
-                vars.put("setBody", "__set.set(i);");
-                vars.put("loop1", "for (int i = -1; (i = set.nextSetBit(i + 1)) >= 0; ) {");
-            }
-            lines.addAll(rewrite(vars,
-                    "{bitset} set = __set;",
-                    "{loop1}",
-                    "{loop2}",
-                    "{loop3}",
-                    "switch (i) {"));
-            for (int i = 0; i < n; i++) {
-                vars.put("i", i);
-                vars.put("set", setterCall.make(properties.get(i)));
-                lines.addAll(rewrite(vars,
-                        "case {i}: {set} break;"));
-            }
-            lines.add("default: break; // can never happen");
-            lines.add("}"); // switch
-            lines.add("}"); // loop
         }
 
         lines.add("}");
@@ -1108,7 +700,7 @@
     // left braces always appear at the end of a line and right braces at the beginning.  (It will also work
     // if matching braces appear within a line.)
     private void makeClass(String className, TypeElement originatingElement, List<String> lines) throws IOException {
-        JavaFileObject jfo = filer.createSourceFile(className, originatingElement);
+        JavaFileObject jfo = processingEnv.getFiler().createSourceFile(className, originatingElement);
         Writer w = jfo.openWriter();
         PrintWriter pw = new PrintWriter(w);
         int indent = 0;
@@ -1173,29 +765,4 @@
     private static String cap(String p) {
         return Character.toUpperCase(p.charAt(0)) + p.substring(1);
     }
-
-    // Return the element of the given set that is equal to e according to the set's comparator.
-    // This can be used to get the canonical spelling wrt case when the comparator is String.CASE_INSENSITIVE_ORDER
-    // for example.
-    private static <E> E setGet(SortedSet<E> set, E e) {
-        Comparator<? super E> cmp = set.comparator();
-        for (E x : set) {
-            if (cmp.compare(x, e) == 0) {
-                return x;
-            }
-        }
-        return null;
-    }
-
-    private static boolean isAbstract(Scanned scanned) {
-        return scanned == null || (scanned.isAbstract && isAbstract(scanned.superScanned));
-    }
-    
-    private static final Set<String> javaKeyWords = new TreeSet<String>(Arrays.asList(
-        "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const",
-        "continue", "default", "do", "double", "else", "enum", "extends", "false", "final", "finally", "float",
-        "for", "goto", "if", "implements", "import", "instanceof", "int", "interface", "long", "native",
-        "new", "null", "package", "private", "protected", "public", "return", "short", "static", "strictfp",
-        "super", "switch", "synchronized", "this", "throw", "throws", "transient", "true", "try", "void",
-        "volatile", "while"));
-}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-annotation-processor/src/javafx/builder/processor/Scanned.java	Wed Jan 09 17:07:00 2013 -0500
@@ -0,0 +1,527 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 javafx.builder.processor;
+
+import com.sun.javafx.beans.annotations.Default;
+import com.sun.javafx.beans.annotations.DuplicateInBuilderProperties;
+import com.sun.javafx.beans.annotations.NoBuilder;
+import com.sun.javafx.beans.annotations.NoInit;
+import com.sun.javafx.collections.annotations.ReturnsUnmodifiableCollection;
+import java.beans.Introspector;
+import java.util.*;
+import javax.lang.model.element.*;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.ElementFilter;
+
+// The result of scanning a class.
+final class Scanned {
+    // The properties that are defined in this class or inherited from the superclass.
+    // The name of each property is mapped to its getter.
+    public final Map<String, ExecutableElement> properties = new TreeMap<String, ExecutableElement>(String.CASE_INSENSITIVE_ORDER);
+    // The properties (local or inherited) that are set by the chosen constructor of this class.
+    // Each property is mapped to an initializer-expression string specified by @Default, or empty string if none
+    public final Map<String, String> constructorProperties = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
+    // Since constructorProperties loses the original order of the constructor arguments, we save them separately.
+    // We originally used a LinkedHashMap to keep the original order, but that didn't give us an easy way to ensure
+    // case-insensitivity.
+    public final List<String> constructorParameters = new ArrayList<String>();
+    // Which local properties are of type Collection or a subtype, meaning that they can be changed by
+    // changing the Collection rather than calling a setter.
+    public final Set<String> collectionProperties = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
+    // Contains methods from builder extension
+    public final List<ExecutableElement> builderExtensionMethods = new ArrayList<ExecutableElement>();
+    // Contains methods from builder extension which hide the properties of the builder
+    public final Set<String> builderExtensionProperties = new HashSet<String>();
+    // The result of scanning the superclass if it exists and is available; otherwise null.
+    public final Scanned superScanned;
+    // True if the class is abstract or "effectively abstract" (has no public constructor).
+    public boolean isAbstract;
+    // The expression to produce an instance of the class, an invocation either of a constructor or a factory method.
+    // Does not include arguments, so for example it might be "new javafx.scene.shape.Rectangle".
+    public String constructorCall;
+
+    // TypeElement of the scanned class
+    private TypeElement type;
+    // Contains class representing builder extension if there is one.
+    // Builder extension are looked up in com.sun... packages and
+    // have their name consist of the name of processed class
+    // with "BuilderExtension" suffix
+    private TypeElement builderExtension;
+    // Which local properties were marked as @ReturnsUnmodifiableCollection.
+    // We will only generate a method for such a property in the builder
+    // if it is one of the properties set by the constructor.
+    private final Set<String> unmodifiableCollectionProperties = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
+    // Which properties (local or inherited) have setters.
+    private final Set<String> propertiesWithSetters = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
+    // Which properties were marked with @DuplicateInBuilderProperties annotation.
+    // Methods for these properties will be generated both for the superclass
+    // and for subclasses
+    private final Set<String> movedProperties = new HashSet<String>();
+    private boolean noBuilder;
+    private AnnotationUtils utils;
+    private static final Set<String> javaKeyWords = new TreeSet<String>(Arrays.asList(
+            "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const",
+            "continue", "default", "do", "double", "else", "enum", "extends", "false", "final", "finally", "float",
+            "for", "goto", "if", "implements", "import", "instanceof", "int", "interface", "long", "native",
+            "new", "null", "package", "private", "protected", "public", "return", "short", "static", "strictfp",
+            "super", "switch", "synchronized", "this", "throw", "throws", "transient", "true", "try", "void",
+            "volatile", "while"));
+
+    private Scanned(Scanned superScanned, TypeElement type, AnnotationUtils utils) {
+        this.superScanned = superScanned;
+        this.utils = utils;
+        this.type = type;
+        this.noBuilder = (type.getAnnotation(NoBuilder.class) != null);
+    }
+
+    private Set<String> inheritedProperties() {
+        if (superScanned == null) {
+            return Collections.emptySet();
+        } else {
+            return superScanned.properties.keySet();
+        }
+    }
+
+    private Set<String> inheritedSetters() {
+        if (superScanned == null) {
+            return Collections.emptySet();
+        } else {
+            return superScanned.propertiesWithSetters;
+        }
+    }
+
+    private boolean inherits(String property) {
+        return inheritedProperties().contains(property);
+    }
+
+    boolean hasInheritedSetters() {
+        if (superScanned == null) {
+            return false;
+        }
+
+        return !superScanned.propertiesWithSetters.isEmpty();
+    }
+
+    private void buildPropertiesWithGetters(List<ExecutableElement> methods) {
+        // Find the properties with explicit getters
+        for (ExecutableElement method : methods) {
+            if (method.getModifiers().contains(Modifier.PUBLIC)
+                    && !method.getModifiers().contains(Modifier.STATIC)
+                    && !utils.isVoidType(method.getReturnType())
+                    && method.getParameters().isEmpty()
+                    && method.getTypeParameters().isEmpty()
+                    && method.getAnnotation(NoInit.class) == null) {
+                final String name = method.getSimpleName().toString();
+                final int len;
+                if (name.startsWith("get")) {
+                    len = 3;
+                } else if (name.startsWith("is") && utils.isBooleanType(method.getReturnType())) {
+                    len = 2;
+                } else {
+                    len = -1;
+                }
+                if (len > 0 && name.length() > len && !name.equals("getClass")) {
+                    String propertyName = Introspector.decapitalize(name.substring(len));
+                    if (!inherits(propertyName)) {
+                        TypeMirror propertyType = method.getReturnType();
+                        TypeMirror oldType = typeOf(propertyName);
+                        properties.put(propertyName, method);
+                        if (oldType != null && !utils.isSameType(oldType, propertyType)) {
+                            utils.warn("Property " + name + " has type " + oldType + " via annotations but type "
+                                    + propertyType + " via getter");
+                            // Could lead to problems with e.g. List<?> which is not equal to itself.
+                        }
+                        if (method.getAnnotation(ReturnsUnmodifiableCollection.class) != null) {
+                            unmodifiableCollectionProperties.add(propertyName);
+                        }
+                    }
+                }
+            }
+        }
+
+        // If anyone is foolish enough to define a property that is a Java reserved word, then they won't
+        // be able to set it with our generated builder.
+        for (String prop : properties.keySet()) {
+            if (javaKeyWords.contains(prop)) {
+                if (!noBuilder) {
+                    utils.warn("Property " + type + "." + prop + " is a reserved word");
+                }
+                properties.remove(prop);
+            }
+        }
+    }
+
+    private void buildPropertiesWithSetters(List<ExecutableElement> methods) {
+        for (ExecutableElement method : methods) {
+            if (method.getModifiers().contains(Modifier.PUBLIC)
+                    && !method.getModifiers().contains(Modifier.STATIC)
+                    && utils.isVoidType(method.getReturnType())
+                    && method.getParameters().size() == 1
+                    && method.getTypeParameters().isEmpty()) {
+                final String name = method.getSimpleName().toString();
+                if (name.startsWith("set") && !name.equals("set")) {
+                    final String propertyName = Introspector.decapitalize(name.substring(3));
+                    TypeMirror getterType = typeOf(propertyName);
+                    TypeMirror setterType = method.getParameters().get(0).asType();
+                    if (getterType != null && utils.isSameType(getterType, setterType)) {
+                        propertiesWithSetters.add(propertyName);
+                    }
+                }
+            }
+        }
+    }
+
+    private void buildCollectionProperties() {
+       // We also consider that getters for properties that are Collections (such as List or ObservableList) are
+       // effectively setters since you can replace the contents of the collection.  But if there is a setter
+       // we will prefer that.
+       Iterator<String> it = properties.keySet().iterator();
+       while (it.hasNext()) {
+           String pName = it.next();
+           TypeMirror pType = typeOf(pName);
+
+           if (utils.isCollection(pType)) {
+               if (AnnotationUtils.isWildcardType(pType)) {
+                   // we ignore wildcard collections (e.g. List<? extend Color>
+                   // because there is no way to add an element to them anyway
+                   it.remove();
+               } else {
+                   boolean added = propertiesWithSetters.add(pName);
+                   if (added) {
+                       collectionProperties.add(pName);
+                   }
+               }
+           }
+       }
+    }
+
+    // Finds the constructor that defines the most properties with no setters.  In the case
+    // of immutable classes, this will be the constructor that defines everything.  In the case
+    // of completely-mutable classes, this will typically be the no-arg constructor.  In the case
+    // of partly-mutable classes, this will be the constructor that defines all the immutable propeties.
+    // If there is a tie between two constructors then we choose the one that has the fewest parameters,
+    // which means that it sets the fewest properties that could also be set with setters.
+    private boolean buildConstructor(boolean forSuper) {
+        ExecutableElement chosenConstructor;
+
+        chosenConstructor = chooseConstructor(Modifier.PUBLIC);
+        if (chosenConstructor == null && !propertiesWithSetters.isEmpty()) {
+            // If there is no public constructor but there are protected ones then we consider those,
+            // but we also mark the builder as abstract.  If the class has no setters (is immutable)
+            // with a protected constructor, then we will not make a buider for it.
+            chosenConstructor = chooseConstructor(Modifier.PROTECTED);
+            if (chosenConstructor != null) {
+                isAbstract = true;
+            }
+        }
+
+        if (chosenConstructor == null) {
+            if (!isAbstract) {
+                if (!forSuper && !noBuilder && properties.size() > 1) {
+                    utils.warn("Cannot make builder for " + type
+                            + " because no constructor specifies only properties as parameters");
+                }
+                return false;
+            }
+        } else {
+            if (chosenConstructor.getKind() == ElementKind.CONSTRUCTOR) {
+                constructorCall = "new " + type;
+            } else {
+                constructorCall = type + "." + chosenConstructor.getSimpleName();
+            }
+
+            List<String> missingDefaults = new ArrayList<String>();
+            for (VariableElement param : chosenConstructor.getParameters()) {
+                String pName = param.getSimpleName().toString();
+                Default def = param.getAnnotation(Default.class);
+                String defaultInit;
+                if (def == null) {
+                    missingDefaults.add(pName);
+                    defaultInit = "";
+                } else {
+                    defaultInit = def.value();
+                }
+                constructorProperties.put(pName, defaultInit);
+                constructorParameters.add(setGet((SortedSet<String>) properties.keySet(), pName));
+            }
+
+            if (utils.verbose && !noBuilder && !missingDefaults.isEmpty()) {
+                utils.warn("Constructor does not specify @Default for parameters " + missingDefaults + ": " + chosenConstructor);
+            }
+        }
+
+        return true;
+    }
+
+    // Fills the movedProperties set with properties from
+    // @DuplicateInBuilderProperties annotation
+    // Also adds these properties into appropriate collections for this
+    // scan class as they need to be processed when making the builder
+    void buildMovedProperties(TypeElement type) {
+        if (superScanned != null) {
+             DuplicateInBuilderProperties annotation = type.getAnnotation(DuplicateInBuilderProperties.class);
+             if (annotation != null) {
+                 for (int i = 0; i < annotation.properties().length; i++) {
+                    String propertyName = annotation.properties()[i];
+                    if (superScanned.propertiesWithSetters.contains(propertyName)) {
+                        propertiesWithSetters.add(propertyName);
+                        movedProperties.add(propertyName);
+                    }
+                    if (superScanned.collectionProperties.contains(propertyName)) {
+                        collectionProperties.add(propertyName);
+                        movedProperties.add(propertyName);
+                    }
+                    if (superScanned.constructorProperties.containsKey(propertyName)) {
+                        constructorProperties.put(propertyName, superScanned.constructorProperties.get(propertyName));
+                        movedProperties.add(propertyName);
+                    }
+                }
+            }
+        }
+    }
+
+    private void processBuilderExtension() {
+        if (superScanned != null) {
+            hasInheritedBuilderExtension = superScanned.hasBuilderExtension()
+                    || superScanned.hasInheritedBuilderExtension();
+        }
+
+        builderExtension = utils.getBuilderExtension(type);
+        if (builderExtension == null) {
+            return;
+        }
+
+        final List<ExecutableElement> methods =
+                ElementFilter.methodsIn(builderExtension.getEnclosedElements());
+        for (ExecutableElement method : methods) {
+            // we process only public non-static method and omit applyTo() method
+            if (method.getModifiers().contains(Modifier.PUBLIC)
+                    && !method.getModifiers().contains(Modifier.STATIC)
+                    && !"applyTo".equals(method.getSimpleName().toString())) {
+                final String name = method.getSimpleName().toString();
+                builderExtensionMethods.add(method);
+                ExecutableElement prop = properties.get(name);
+                // check whether given method would be generated by the builder processor
+                // in such case, we need to tell it not to generate this method
+                // as it is copied from builder extension
+                if (prop != null && method.getParameters().size() == 1) {
+                    TypeMirror beType = method.getParameters().get(0).asType();
+                    TypeMirror pType = prop.getReturnType();
+                    if (utils.isSameType(pType, beType)) {
+                        // standard property
+                        builderExtensionProperties.add(name);
+                    } else if (collectionProperties.contains(name) && AnnotationUtils.hasOneArgument(pType)) {
+                        // collection method - we check whether the type
+                        // of the collection is the same as in the builder
+                        TypeMirror typeArg = ((DeclaredType) pType).getTypeArguments().get(0);
+                        if (AnnotationUtils.hasOneArgument(beType)) {
+                            TypeMirror methodTypeArg = utils.types.erasure(((DeclaredType) beType).getTypeArguments().get(0));
+                            if (utils.isSameType(typeArg, methodTypeArg)) {
+                                builderExtensionProperties.add(name);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    TypeMirror typeOf(String property) {
+        ExecutableElement getter = properties.get(property);
+        if (getter == null) {
+            return null;
+        } else {
+            return getter.getReturnType();
+        }
+    }
+
+    // Find the constructor that sets the most immutable properties and the fewest mutable ones.
+    private ExecutableElement chooseConstructor(Modifier access) {
+        ExecutableElement best = null;
+        int bestImmutables = -1;
+        int bestCount = -1;
+
+        final List<ExecutableElement> constructors =
+                new ArrayList<ExecutableElement>(ElementFilter.constructorsIn(type.getEnclosedElements()));
+
+        // It turns out that this is not appropriate, so it's disabled for now.  We may at some future point
+        // restore support for factories, probably with an explicit @Factory annotation.
+        if (false) {
+            // We rather hackily consider that static methods with the same name as the class they are in,
+            // ignoring case, are factory methods equivalent to constructors, as in Font.font and Color.color.
+            // If both a factory method and a constructor are "best", then we prefer the factory method on the
+            // grounds that it may be able to reuse instances and the like.
+            for (ExecutableElement factory : ElementFilter.methodsIn(type.getEnclosedElements())) {
+                if (factory.getModifiers().contains(Modifier.STATIC)
+                        && factory.getSimpleName().toString().equalsIgnoreCase(type.getSimpleName().toString())) {
+                    constructors.add(factory);
+                }
+            }
+        }
+
+        for (ExecutableElement constructor : constructors) {
+            if (constructor.getModifiers().contains(access) && constructor.getTypeParameters().isEmpty()) {
+                int immutables = 0;
+                for (VariableElement param : constructor.getParameters()) {
+                    final String pName = param.getSimpleName().toString();
+                    final TypeMirror pType = typeOf(pName);
+                    if (pType == null
+                            || (!utils.isSameType(param.asType(), pType) && !param.asType().toString().equals(pType.toString()))) {
+                        // This area is a bit messy. Really we should be determining whether the parameter is a subtype of
+                        // the (possibly inherited) property type. But if it is a strict subtype then we need to adjust the
+                        // inherited type, so that for example InputEvent's constructor which takes an EventType<? extends InputEvent>
+                        // would cause the builder to have a field of that type, even though the corresponding property
+                        // inherited from Event is an EventType<? extends Event>. For now, we forgo some possibilities
+                        // to generate builders.
+                        immutables = -1;
+                        break;
+                    }
+                    if (!propertiesWithSetters.contains(pName)) {
+                        immutables++;
+                    }
+                }
+                final int count = constructor.getParameters().size();
+                if (immutables > bestImmutables || (immutables == bestImmutables && count < bestCount)
+                        || (immutables == bestImmutables && count == bestCount && best != null
+                        && best.getKind() == ElementKind.CONSTRUCTOR && constructor.getKind() == ElementKind.METHOD)) {
+                    // That last giant conjunct is where we prefer static factory methods to constructors,
+                    // all else being equal.
+                    best = constructor;
+                    bestImmutables = immutables;
+                    bestCount = count;
+                }
+            }
+        }
+        if (bestCount != bestImmutables) {
+            System.out.println("bestCount " + bestCount + "immutables " + bestImmutables + " for type " + type);
+        }
+
+        return best;
+    }
+
+    public static Scanned createScanned(Scanned superScanned,
+            TypeElement type,
+            boolean forSuper,
+            AnnotationUtils utils) {
+        final Scanned scanned = new Scanned(superScanned, type, utils);
+        scanned.isAbstract = type.getModifiers().contains(Modifier.ABSTRACT);
+        if (superScanned != null) {
+            scanned.properties.putAll(superScanned.properties);
+            scanned.propertiesWithSetters.addAll(scanned.inheritedSetters());
+        }
+
+        final List<ExecutableElement> methods = ElementFilter.methodsIn(type.getEnclosedElements());
+
+        // Find the properties with explicit getters
+        scanned.buildPropertiesWithGetters(methods);
+
+        // Find any setters for the properties found above.
+        scanned.buildPropertiesWithSetters(methods);
+
+        // We also consider that getters for properties that are Collections (such as List or ObservableList) are
+        // effectively setters since you can replace the contents of the collection.  But if there is a setter
+        // we will prefer that.
+        scanned.buildCollectionProperties();
+
+        // Now we want the constructor that defines the most properties with no setters.  In the case
+        // of immutable classes, this will be the constructor that defines everything.  In the case
+        // of completely-mutable classes, this will typically be the no-arg constructor.  In the case
+        // of partly-mutable classes, this will be the constructor that defines all the immutable propeties.
+        // If there is a tie between two constructors then we choose the one that has the fewest parameters,
+        // which means that it sets the fewest properties that could also be set with setters.
+        if (!scanned.buildConstructor(forSuper)) {
+            return new Scanned(null, type, utils);
+        }
+
+        // process properties with @DuplicateInBuilderProperties annotation
+        scanned.buildMovedProperties(type);
+
+        // try to find builder extension
+        scanned.processBuilderExtension();
+
+        return scanned;
+    }
+
+    public boolean hasBuilderExtension() {
+        return builderExtension != null;
+    }
+
+
+    private boolean hasInheritedBuilderExtension = false;
+    boolean hasInheritedBuilderExtension() {
+        return false; // Inheritance of builder extensions is disabled for now
+        // return hasInheritedBuilderExtension;
+    }
+    
+    private Set<String> buildablePropertyNames;
+    public Set<String> getBuildablePropertyNames() {
+        if (buildablePropertyNames == null) {
+            buildablePropertyNames = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
+
+            buildablePropertyNames.addAll(propertiesWithSetters);
+            buildablePropertyNames.removeAll(inheritedSetters());
+            buildablePropertyNames.removeAll(unmodifiableCollectionProperties);
+            buildablePropertyNames.addAll(constructorProperties.keySet());
+            buildablePropertyNames.addAll(movedProperties);
+            buildablePropertyNames.removeAll(builderExtensionProperties);
+        }
+
+        return buildablePropertyNames;
+    }
+
+    public static boolean isAbstract(Scanned scanned) {
+        return scanned == null || (scanned.isAbstract && isAbstract(scanned.superScanned));
+    }
+
+    public String getBuilderExtensionName() {
+        if (builderExtension != null) {
+            return builderExtension.getQualifiedName().toString();
+        } else {
+            Scanned sc = superScanned;
+            while (sc != null) {
+                if (sc.builderExtension != null) {
+                    return sc.builderExtension.getQualifiedName().toString();
+                }
+                sc = sc.superScanned;
+            }
+        }
+        return "";
+    }
+
+    // Return the element of the given set that is equal to e according to the set's comparator.
+    // This can be used to get the canonical spelling wrt case when the comparator is String.CASE_INSENSITIVE_ORDER
+    // for example.
+    private static <E> E setGet(SortedSet<E> set, E e) {
+        Comparator<? super E> cmp = set.comparator();
+        for (E x : set) {
+            if (cmp.compare(x, e) == 0) {
+                return x;
+            }
+        }
+        return null;
+    }
+
+}
--- a/javafx-concurrent/test/javafx/concurrent/ServiceWithSecurityManagerTest.java	Thu Jan 10 10:20:41 2013 +1300
+++ b/javafx-concurrent/test/javafx/concurrent/ServiceWithSecurityManagerTest.java	Wed Jan 09 17:07:00 2013 -0500
@@ -100,9 +100,13 @@
 
             @Override public void checkPermission(Permission permission) {
                 if (isPrivileged()) return; // OK
-                if (permission instanceof RuntimePermission &&
-                        "setSecurityManager".equals(permission.getName())) {
-                    return; // OK
+                if (permission instanceof RuntimePermission) {
+                    if ("setSecurityManager".equals(permission.getName())) {
+                        return; // OK
+                    }
+                    if ("accessClassInPackage.sun.util.logging".equals(permission.getName())) {
+                        return; // OK
+                    }
                 }
                 super.checkPermission(permission);
             }
--- a/javafx-fxml/src/com/sun/javafx/fxml/BeanAdapter.java	Thu Jan 10 10:20:41 2013 +1300
+++ b/javafx-fxml/src/com/sun/javafx/fxml/BeanAdapter.java	Wed Jan 09 17:07:00 2013 -0500
@@ -44,6 +44,7 @@
 import java.lang.reflect.*;
 
 import javafx.beans.value.ObservableValue;
+import sun.reflect.misc.ReflectUtil;
 
 /**
  * Exposes Java Bean properties of an object via the {@link Map} interface.
@@ -55,6 +56,8 @@
 public class BeanAdapter extends AbstractMap<String, Object> {
     private Object bean;
 
+    private static ClassLoader contextClassLoader;
+    
     private static HashMap<Class<?>, HashMap<String, LinkedList<Method>>> globalMethodCache =
         new HashMap<Class<?>, HashMap<String, LinkedList<Method>>>();
 
@@ -64,7 +67,14 @@
     public static final String PROPERTY_SUFFIX = "Property";
 
     public static final String VALUE_OF_METHOD_NAME = "valueOf";
+    
+    static {
+        contextClassLoader = Thread.currentThread().getContextClassLoader();
 
+        if (contextClassLoader == null) {
+            throw new NullPointerException();
+        }
+    }
     /**
      * Creates a new Bean adapter.
      *
@@ -447,8 +457,12 @@
                 coercedValue = new BigDecimal(value.toString());
             }
         } else if (type == Class.class) {
-            try {
-                coercedValue = Class.forName(value.toString());
+            try {   
+                ReflectUtil.checkPackageAccess(value.toString());
+                coercedValue = Class.forName(
+                        value.toString(), 
+                        false, 
+                        BeanAdapter.contextClassLoader);
             } catch (ClassNotFoundException exception) {
                 throw new IllegalArgumentException(exception);
             }
--- a/javafx-fxml/src/javafx/fxml/FXMLLoader.java	Thu Jan 10 10:20:41 2013 +1300
+++ b/javafx-fxml/src/javafx/fxml/FXMLLoader.java	Wed Jan 09 17:07:00 2013 -0500
@@ -546,7 +546,7 @@
 
     // Element representing a value
     private abstract class ValueElement extends Element {
-        public String id = null;
+        public String fx_id = null;
 
         @Override
         public void processStartElement() throws IOException {
@@ -627,20 +627,24 @@
             }
 
             // Add the value to the namespace
-            if (id != null) {
-                namespace.put(id, value);
+            if (fx_id != null) {
+                namespace.put(fx_id, value);
 
                 // If the value defines an ID property, set it
                 IDProperty idProperty = value.getClass().getAnnotation(IDProperty.class);
 
                 if (idProperty != null) {
                     Map<String, Object> properties = getProperties();
-                    properties.put(idProperty.value(), id);
+                    // set fx:id property value to Node.id only if Node.id was not
+                    // already set when processing start element attributes
+                    if (properties.get(idProperty.value()) == null) {
+                        properties.put(idProperty.value(), fx_id);
+                    }
                 }
-                
+
                 // Set the controller field value
                 if (controller != null) {
-                    Field field = getControllerFields().get(id);
+                    Field field = getControllerFields().get(fx_id);
 
                     if (field != null) {
                         try {
@@ -697,7 +701,7 @@
                         }
                     }
 
-                    id = value;
+                    fx_id = value;
 
                 } else if (localName.equals(FX_CONTROLLER_ATTRIBUTE)) {
                     if (current.parent != null) {
@@ -928,8 +932,8 @@
 
             Object value = fxmlLoader.load();
 
-            if (id != null) {
-                String id = this.id + CONTROLLER_SUFFIX;
+            if (fx_id != null) {
+                String id = this.fx_id + CONTROLLER_SUFFIX;
                 Object controller = fxmlLoader.getController();
 
                 namespace.put(id, controller);
@@ -1808,9 +1812,9 @@
 
     /**
      * Sets the root of the object hierarchy. The value passed to this method
-     * is used as the value of the <tt>&lt;fx:root%gt;</tt> tag. This method
+     * is used as the value of the <tt>&lt;fx:root&gt;</tt> tag. This method
      * must be called prior to loading the document when using
-     * <tt>&lt;fx:root%gt;</tt>.
+     * <tt>&lt;fx:root&gt;</tt>.
      *
      * @param root
      * The root of the object hierarchy.
--- a/javafx-ui-common/src/com/sun/javafx/application/LauncherImpl.java	Thu Jan 10 10:20:41 2013 +1300
+++ b/javafx-ui-common/src/com/sun/javafx/application/LauncherImpl.java	Wed Jan 09 17:07:00 2013 -0500
@@ -60,6 +60,7 @@
     // set to true to debug launch issues from Java launcher
     private static final boolean trace = false;
 
+    private static final String MF_MAIN_CLASS = "Main-Class";
     private static final String MF_JAVAFX_MAIN = "JavaFX-Application-Class";
     private static final String MF_JAVAFX_PRELOADER = "JavaFX-Preloader-Class";
 
@@ -189,7 +190,12 @@
 
             mainClassName = jarAttrs.getValue(MF_JAVAFX_MAIN);
             if (mainClassName == null) {
-                abort(null, "JavaFX jar manifest requires a valid JavaFX-Appliation-Class entry");
+                // fall back on Main-Class if no JAC
+                mainClassName = jarAttrs.getValue(MF_MAIN_CLASS);
+                if (mainClassName == null) {
+                    // Should not happen as the launcher enforces the presence of Main-Class
+                    abort(null, "JavaFX jar manifest requires a valid JavaFX-Appliation-Class or Main-Class entry");
+                }
             }
             mainClassName = mainClassName.trim();
 
--- a/javafx-ui-common/src/com/sun/javafx/image/impl/IntArgb.java	Thu Jan 10 10:20:41 2013 +1300
+++ b/javafx-ui-common/src/com/sun/javafx/image/impl/IntArgb.java	Wed Jan 09 17:07:00 2013 -0500
@@ -41,7 +41,7 @@
     public static final IntPixelAccessor accessor = Accessor.instance;
 
     public static final IntToBytePixelConverter ToByteBgraConverter =
-        IntArgb.ToByteBgraSameConv.nonpremul;
+        new IntTo4ByteSameConverter(IntArgb.getter, ByteBgra.setter);
     public static final IntToBytePixelConverter ToByteBgraPreConverter =
         IntArgb.ToByteBgraPreConv.instance;
     public static final IntToIntPixelConverter ToIntArgbConverter =
@@ -167,56 +167,6 @@
         }
     }
 
-    static class ToByteBgraSameConv extends BaseIntToByteConverter {
-        static final IntToBytePixelConverter nonpremul = new ToByteBgraSameConv(false);
-        static final IntToBytePixelConverter premul = new ToByteBgraSameConv(true);
-
-        private ToByteBgraSameConv(boolean isPremult) {
-            super(isPremult ?  IntArgbPre.getter :  IntArgb.getter,
-                  isPremult ? ByteBgraPre.setter : ByteBgra.setter);
-        }
-
-        @Override
-        void doConvert(int  srcarr[], int srcoff, int srcscanints,
-                       byte dstarr[], int dstoff, int dstscanbytes,
-                       int w, int h)
-        {
-            srcscanints -= w;
-            dstscanbytes -= w * 4;
-            while (--h >= 0) {
-                for (int x = 0; x < w; x++) {
-                    int pixel = srcarr[srcoff++];
-                    dstarr[dstoff++] = (byte) (pixel      );
-                    dstarr[dstoff++] = (byte) (pixel >>  8);
-                    dstarr[dstoff++] = (byte) (pixel >> 16);
-                    dstarr[dstoff++] = (byte) (pixel >> 24);
-                }
-                srcoff += srcscanints;
-                dstoff += dstscanbytes;
-            }
-        }
-
-        @Override
-        void doConvert(IntBuffer  srcbuf, int srcoff, int srcscanints,
-                       ByteBuffer dstbuf, int dstoff, int dstscanbytes,
-                       int w, int h)
-        {
-            dstscanbytes -= w * 4;
-            while (--h >= 0) {
-                for (int x = 0; x < w; x++) {
-                    int pixel = srcbuf.get(srcoff + x);
-                    dstbuf.put(dstoff    , (byte) (pixel      ));
-                    dstbuf.put(dstoff + 1, (byte) (pixel >>  8));
-                    dstbuf.put(dstoff + 2, (byte) (pixel >> 16));
-                    dstbuf.put(dstoff + 3, (byte) (pixel >> 24));
-                    dstoff += 4;
-                }
-                srcoff += srcscanints;
-                dstoff += dstscanbytes;
-            }
-        }
-    }
-
     static class ToByteBgraPreConv extends BaseIntToByteConverter {
         public static final IntToBytePixelConverter instance =
             new ToByteBgraPreConv();
--- a/javafx-ui-common/src/com/sun/javafx/image/impl/IntArgbPre.java	Thu Jan 10 10:20:41 2013 +1300
+++ b/javafx-ui-common/src/com/sun/javafx/image/impl/IntArgbPre.java	Wed Jan 09 17:07:00 2013 -0500
@@ -36,14 +36,14 @@
 import java.nio.IntBuffer;
 
 public class IntArgbPre {
-    public static final IntPixelGetter     getter = IntArgb.Accessor.instance;
-    public static final IntPixelSetter     setter = IntArgb.Accessor.instance;
-    public static final IntPixelAccessor accessor = IntArgb.Accessor.instance;
+    public static final IntPixelGetter     getter = Accessor.instance;
+    public static final IntPixelSetter     setter = Accessor.instance;
+    public static final IntPixelAccessor accessor = Accessor.instance;
 
     public static final IntToBytePixelConverter ToByteBgraConverter =
         IntArgbPre.ToByteBgraConv.instance;
     public static final IntToBytePixelConverter ToByteBgraPreConverter =
-        IntArgb.ToByteBgraSameConv.premul;
+        new IntTo4ByteSameConverter(IntArgbPre.getter, ByteBgraPre.setter);
     public static final IntToIntPixelConverter ToIntArgbConverter =
         IntArgbPre.ToIntArgbConv.instance;
     public static final IntToIntPixelConverter ToIntArgbPreConverter =
@@ -213,9 +213,10 @@
                     int g = (pixel >>  8) & 0xff;
                     int b = (pixel      ) & 0xff;
                     if (a > 0 && a < 0xff) {
-                        r = (r * a + 0x7f) / 0xff;
-                        g = (g * a + 0x7f) / 0xff;
-                        b = (b * a + 0x7f) / 0xff;
+                        int halfa = a >> 1;
+                        r = (r * 0xff + halfa) / a;
+                        g = (g * 0xff + halfa) / a;
+                        b = (b * 0xff + halfa) / a;
                     }
                     dstbuf.put(dstoff    , (byte) b);
                     dstbuf.put(dstoff + 1, (byte) g);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-ui-common/src/com/sun/javafx/image/impl/IntTo4ByteSameConverter.java	Wed Jan 09 17:07:00 2013 -0500
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.javafx.image.impl;
+
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+import com.sun.javafx.image.BytePixelSetter;
+import com.sun.javafx.image.IntPixelGetter;
+
+class IntTo4ByteSameConverter extends BaseIntToByteConverter {
+
+    IntTo4ByteSameConverter(IntPixelGetter getter, BytePixelSetter setter) {
+        super(getter, setter);
+    }
+
+    @Override
+    void doConvert(int  srcarr[], int srcoff, int srcscanints,
+                   byte dstarr[], int dstoff, int dstscanbytes,
+                   int w, int h)
+    {
+        srcscanints -= w;
+        dstscanbytes -= w * 4;
+        while (--h >= 0) {
+            for (int x = 0; x < w; x++) {
+                int pixel = srcarr[srcoff++];
+                dstarr[dstoff++] = (byte) (pixel      );
+                dstarr[dstoff++] = (byte) (pixel >>  8);
+                dstarr[dstoff++] = (byte) (pixel >> 16);
+                dstarr[dstoff++] = (byte) (pixel >> 24);
+            }
+            srcoff += srcscanints;
+            dstoff += dstscanbytes;
+        }
+    }
+
+    @Override
+    void doConvert(IntBuffer srcbuf, int srcoff, int srcscanints,
+                   ByteBuffer dstbuf, int dstoff, int dstscanbytes,
+                   int w, int h)
+    {
+        dstscanbytes -= w * 4;
+        while (--h >= 0) {
+            for (int x = 0; x < w; x++) {
+                int pixel = srcbuf.get(srcoff + x);
+                dstbuf.put(dstoff    , (byte) (pixel      ));
+                dstbuf.put(dstoff + 1, (byte) (pixel >>  8));
+                dstbuf.put(dstoff + 2, (byte) (pixel >> 16));
+                dstbuf.put(dstoff + 3, (byte) (pixel >> 24));
+                dstoff += 4;
+            }
+            srcoff += srcscanints;
+            dstoff += dstscanbytes;
+        }
+    }
+}
\ No newline at end of file
--- a/javafx-ui-common/src/javafx/animation/ParallelTransition.java	Thu Jan 10 10:20:41 2013 +1300
+++ b/javafx-ui-common/src/javafx/animation/ParallelTransition.java	Wed Jan 09 17:07:00 2013 -0500
@@ -362,7 +362,7 @@
             cycleTime = 0;
             int i = 0;
             for (final Animation animation : cachedChildren) {
-                rates[i] = animation.getRate();
+                rates[i] = Math.abs(animation.getRate());
                 if (rates[i] < EPSILON) {
                     rates[i] = 1;
                 }
@@ -394,10 +394,13 @@
     @Override
     void impl_resume() {
         super.impl_resume();
+        int i = 0;
         for (final Animation animation : cachedChildren) {
             if (animation.getStatus() == Status.PAUSED) {
                 animation.impl_resume();
+                animation.clipEnvelope.setRate(rates[i] * Math.signum(getCurrentRate()));
             }
+            i++;
         }
     }
 
@@ -548,12 +551,16 @@
             } else {
                 if (status == Status.STOPPED) {
                     startChild(animation, i);
+                    if (getStatus() == Status.PAUSED) {
+                        animation.impl_pause();
+                    }
+
                     offsetTicks[i] = (getCurrentRate() > 0)? newTicks - delays[i] : add(durations[i], delays[i]) - newTicks;
+                } else if (status == Status.PAUSED) {
+                    offsetTicks[i] += (newTicks - oldTicks) * Math.signum(this.clipEnvelope.getCurrentRate());
                 } else {
                     offsetTicks[i] += (getCurrentRate() > 0) ? newTicks - oldTicks : oldTicks - newTicks;
                 }
-                // TODO: This does probably not work if animation is paused (getCurrentRate() == 0)
-                // TODO: Do I have to use newTicks or currentTicks?
                 animation.clipEnvelope.jumpTo(Math.round(sub(newTicks, delays[i]) * rates[i]));
             }
             i++;
--- a/javafx-ui-common/src/javafx/animation/SequentialTransition.java	Thu Jan 10 10:20:41 2013 +1300
+++ b/javafx-ui-common/src/javafx/animation/SequentialTransition.java	Wed Jan 09 17:07:00 2013 -0500
@@ -370,7 +370,7 @@
             int i = 0;
             for (final Animation animation : cachedChildren) {
                 startTimes[i] = cycleTicks;
-                rates[i] = animation.getRate();
+                rates[i] = Math.abs(animation.getRate());
                 if (rates[i] < EPSILON) {
                     rates[i] = 1;
                 }
@@ -435,6 +435,7 @@
             final Animation current = cachedChildren[curIndex];
             if (current.getStatus() == Status.PAUSED) {
                 current.impl_resume();
+                current.clipEnvelope.setRate(rates[curIndex] * Math.signum(getCurrentRate()));
             }
         }
     }
@@ -689,11 +690,22 @@
                 }
             }
         }
-        // TODO: This does probably not work if animation is paused (getCurrentRate() == 0)
         if (oldIndex == curIndex) {
-            offsetTicks += currentRate > 0 ? newTicks - oldTicks : oldTicks - newTicks;
+            if (currentRate == 0) {
+                offsetTicks += (newTicks - oldTicks) * Math.signum(this.clipEnvelope.getCurrentRate());
+            } else {
+                offsetTicks += currentRate > 0 ? newTicks - oldTicks : oldTicks - newTicks;
+            }
         } else {
-            offsetTicks = currentRate > 0 ? newTicks - add(startTimes[curIndex], delays[curIndex]) : startTimes[curIndex + 1] - newTicks;
+            if (currentRate == 0) {
+                if (this.clipEnvelope.getCurrentRate() > 0) {
+                    offsetTicks = newTicks - add(startTimes[curIndex], delays[curIndex]);
+                } else {
+                    offsetTicks = startTimes[curIndex] + durations[curIndex] - newTicks;
+                }
+            } else {
+                offsetTicks = currentRate > 0 ? newTicks - add(startTimes[curIndex], delays[curIndex]) : startTimes[curIndex + 1] - newTicks;
+            }
         }
         newAnimation.clipEnvelope.jumpTo(Math.round(sub(newTicks, add(startTimes[curIndex], delays[curIndex])) * rates[curIndex]));
         oldTicks = newTicks;
--- a/javafx-ui-common/src/javafx/scene/Node.java	Thu Jan 10 10:20:41 2013 +1300
+++ b/javafx-ui-common/src/javafx/scene/Node.java	Wed Jan 09 17:07:00 2013 -0500
@@ -1438,11 +1438,11 @@
     }
 
     /**
-     * Sets the individual disabled state of this {@code Node}. Setting
+     * Defines the individual disabled state of this {@code Node}. Setting
      * {@code disable} to true will cause this {@code Node} and any subnodes to
-     * become disabled. This variable should be used only to set the disabled
+     * become disabled. This property should be used only to set the disabled
      * state of a {@code Node}.  For querying the disabled state of a
-     * {@code Node}, the {@link #disabledProperty disabled} variable should instead be used,
+     * {@code Node}, the {@link #disabledProperty disabled} property should instead be used,
      * since it is possible that a {@code Node} was disabled as a result of an
      * ancestor being disabled even if the individual {@code disable} state on
      * this {@code Node} is {@code false}.
--- a/javafx-ui-common/src/javafx/scene/input/InputMethodEvent.java	Thu Jan 10 10:20:41 2013 +1300
+++ b/javafx-ui-common/src/javafx/scene/input/InputMethodEvent.java	Wed Jan 09 17:07:00 2013 -0500
@@ -25,6 +25,10 @@
 
 package javafx.scene.input;
 
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
 import java.util.List;
 import javafx.collections.FXCollections;
 import javafx.collections.ObservableList;
@@ -97,7 +101,7 @@
      *
      * @defaultValue null
      */
-    private final ObservableList<InputMethodTextRun> composed;
+    private transient ObservableList<InputMethodTextRun> composed;
 
     /**
      * Gets the text under composition.  This text should be displayed with the
@@ -175,6 +179,16 @@
         return (EventType<InputMethodEvent>) super.getEventType();
     }
     
-    
+    private void writeObject(ObjectOutputStream oos) throws IOException {
+        oos.defaultWriteObject();
+        oos.writeObject(new ArrayList(composed));
+    }
+
+    private void readObject(ObjectInputStream ois) throws IOException,
+            ClassNotFoundException {
+        ois.defaultReadObject();
+        ArrayList<InputMethodTextRun> o = (ArrayList)ois.readObject();
+        composed = FXCollections.unmodifiableObservableList(FXCollections.observableArrayList(o));
+    }
 
 }
--- a/javafx-ui-common/test/unit/com/sun/javafx/image/ConverterTest.java	Thu Jan 10 10:20:41 2013 +1300
+++ b/javafx-ui-common/test/unit/com/sun/javafx/image/ConverterTest.java	Wed Jan 09 17:07:00 2013 -0500
@@ -341,7 +341,7 @@
             int red   = (pixel >> rshift) & 0xff;
             int green = (pixel >> gshift) & 0xff;
             int blue  = (pixel >> bshift) & 0xff;
-            if (alpha < 255 && getter.getAlphaType() == AlphaType.PREMULTIPLIED) {
+            if (alpha > 0 && alpha < 255 && getter.getAlphaType() == AlphaType.PREMULTIPLIED) {
                 int halfa = alpha >> 1;
                 red   = (red   >= alpha) ? 255 : (red   * 255 + halfa) / alpha;
                 green = (green >= alpha) ? 255 : (green * 255 + halfa) / alpha;
--- a/javafx-ui-common/test/unit/javafx/animation/ParallelTransitionPlayTest.java	Thu Jan 10 10:20:41 2013 +1300
+++ b/javafx-ui-common/test/unit/javafx/animation/ParallelTransitionPlayTest.java	Wed Jan 09 17:07:00 2013 -0500
@@ -555,4 +555,275 @@
         assertEquals(5000 + TICK_STEP, yProperty.get());
 
     }
+
+    @Test
+    public void testPauseForward1() {
+        pt.getChildren().addAll(child1X, child1Y);
+
+        pt.play();
+        pt.jumpTo(Duration.seconds(5));
+        amt.pulse();
+        pt.pause();
+        assertEquals(Status.PAUSED, pt.getStatus());
+        assertEquals(Status.PAUSED, child1X.getStatus());
+        assertEquals(Status.PAUSED, child1Y.getStatus());
+        assertEquals(5000 + TICK_STEP, xProperty.get());
+        assertEquals(5000 + TICK_STEP, yProperty.get());
+
+        pt.jumpTo(Duration.seconds(6));
+        assertEquals(Status.PAUSED, pt.getStatus());
+        assertEquals(Status.PAUSED, child1X.getStatus());
+        assertEquals(Status.PAUSED, child1Y.getStatus());
+        assertEquals(6000, xProperty.get());
+        assertEquals(6000, yProperty.get());
+
+        pt.play();
+        assertEquals(Status.RUNNING, pt.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+        assertEquals(6000, xProperty.get());
+        assertEquals(6000, yProperty.get());
+
+        amt.pulse();
+        assertEquals(Status.RUNNING, pt.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+        assertEquals(6000 + TICK_STEP, xProperty.get());
+        assertEquals(6000 + TICK_STEP, yProperty.get());
+
+        pt.pause();
+        pt.jumpTo(Duration.seconds(7));
+        pt.jumpTo(Duration.seconds(9));
+        assertEquals(Status.PAUSED, pt.getStatus());
+        assertEquals(Status.PAUSED, child1X.getStatus());
+        assertEquals(Status.PAUSED, child1Y.getStatus());
+        assertEquals(9000, xProperty.get());
+        assertEquals(9000, yProperty.get());
+
+        pt.play();
+        assertEquals(Status.RUNNING, pt.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+        assertEquals(9000, xProperty.get());
+        assertEquals(9000, yProperty.get());
+
+        amt.pulse();
+        assertEquals(Status.RUNNING, pt.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+        assertEquals(9000 + TICK_STEP, xProperty.get());
+        assertEquals(9000 + TICK_STEP, yProperty.get());
+
+        pt.pause();
+        assertEquals(Status.PAUSED, pt.getStatus());
+        assertEquals(Status.PAUSED, child1X.getStatus());
+        assertEquals(Status.PAUSED, child1Y.getStatus());
+        assertEquals(9000 + TICK_STEP, xProperty.get());
+        assertEquals(9000 + TICK_STEP, yProperty.get());
+
+        pt.jumpTo(Duration.seconds(10).subtract(TickCalculation.toDuration(100)));
+        assertEquals(Status.PAUSED, pt.getStatus());
+        assertEquals(Status.PAUSED, child1X.getStatus());
+        assertEquals(Status.PAUSED, child1Y.getStatus());
+        assertEquals(10000 - TICK_STEP, xProperty.get());
+        assertEquals(10000 - TICK_STEP, yProperty.get());
+
+        pt.play();
+        assertEquals(Status.RUNNING, pt.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+        assertEquals(10000 - TICK_STEP, xProperty.get());
+        assertEquals(10000 - TICK_STEP, yProperty.get());
+
+        amt.pulse();
+        assertEquals(Status.RUNNING, pt.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(10000, xProperty.get());
+        assertEquals(10000, yProperty.get());
+
+        pt.pause();
+        pt.jumpTo(Duration.seconds(60).subtract(TickCalculation.toDuration(100)));
+        assertEquals(Status.PAUSED, pt.getStatus());
+        assertEquals(Status.PAUSED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(60000 - TICK_STEP, xProperty.get());
+        assertEquals(10000, yProperty.get());
+
+        pt.play();
+        assertEquals(Status.RUNNING, pt.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(60000 - TICK_STEP, xProperty.get());
+        assertEquals(10000, yProperty.get());
+
+        amt.pulse();
+        assertEquals(Status.STOPPED, pt.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(60000, xProperty.get());
+        assertEquals(10000, yProperty.get());
+    }
+
+    @Test
+    public void testPauseForward2() {
+        pt.getChildren().addAll(child1X, child1Y);
+
+        pt.play();
+        pt.jumpTo(Duration.seconds(5));
+        amt.pulse();
+        pt.pause();
+        assertEquals(Status.PAUSED, pt.getStatus());
+        assertEquals(Status.PAUSED, child1X.getStatus());
+        assertEquals(Status.PAUSED, child1Y.getStatus());
+        assertEquals(5000 + TICK_STEP, xProperty.get());
+        assertEquals(5000 + TICK_STEP, yProperty.get());
+
+        pt.jumpTo(Duration.seconds(30));
+        assertEquals(Status.PAUSED, pt.getStatus());
+        assertEquals(Status.PAUSED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(30000, xProperty.get());
+        assertEquals(10000, yProperty.get());
+
+        pt.play();
+        assertEquals(Status.RUNNING, pt.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(30000, xProperty.get());
+        assertEquals(10000, yProperty.get());
+
+        amt.pulse();
+        assertEquals(Status.RUNNING, pt.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(30000 + TICK_STEP, xProperty.get());
+        assertEquals(10000, yProperty.get());
+
+        pt.pause();
+        pt.jumpTo(Duration.seconds(60).subtract(TickCalculation.toDuration(100)));
+        assertEquals(Status.PAUSED, pt.getStatus());
+        assertEquals(Status.PAUSED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(60000 - TICK_STEP, xProperty.get());
+        assertEquals(10000, yProperty.get());
+
+        pt.play();
+        assertEquals(Status.RUNNING, pt.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(60000 - TICK_STEP, xProperty.get());
+        assertEquals(10000, yProperty.get());
+
+        amt.pulse();
+        assertEquals(Status.STOPPED, pt.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(60000, xProperty.get());
+        assertEquals(10000, yProperty.get());
+    }
+
+    @Test
+    public void testPauseAutoReverse() {
+        pt.getChildren().addAll(child1X, child1Y);
+        pt.setAutoReverse(true);
+        pt.setCycleCount(-1);
+
+        pt.play();
+        pt.jumpTo(Duration.seconds(5));
+        amt.pulse();
+        pt.pause();
+        assertEquals(Status.PAUSED, pt.getStatus());
+        assertEquals(Status.PAUSED, child1X.getStatus());
+        assertEquals(Status.PAUSED, child1Y.getStatus());
+        assertEquals(5000 + TICK_STEP, xProperty.get());
+        assertEquals(5000 + TICK_STEP, yProperty.get());
+
+        pt.jumpTo(Duration.seconds(60).subtract(TickCalculation.toDuration(100)));
+        assertEquals(Status.PAUSED, pt.getStatus());
+        assertEquals(Status.PAUSED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(60000 - TICK_STEP, xProperty.get());
+        assertEquals(10000, yProperty.get());
+
+        pt.play();
+        assertEquals(Status.RUNNING, pt.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(60000 - TICK_STEP, xProperty.get());
+        assertEquals(10000, yProperty.get());
+
+        amt.pulse();
+        assertEquals(Status.RUNNING, pt.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(60000, xProperty.get());
+        assertEquals(10000, yProperty.get());
+
+        amt.pulse();
+        assertEquals(Status.RUNNING, pt.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(60000 - TICK_STEP, xProperty.get());
+        assertEquals(10000, yProperty.get());
+
+        pt.pause();
+        pt.jumpTo(Duration.seconds(110).subtract(TickCalculation.toDuration(100)));
+        assertEquals(Status.PAUSED, pt.getStatus());
+        assertEquals(Status.PAUSED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(10000 + TICK_STEP, xProperty.get());
+        assertEquals(10000, yProperty.get());
+
+        pt.play();
+        assertEquals(Status.RUNNING, pt.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(10000 + TICK_STEP, xProperty.get());
+        assertEquals(10000, yProperty.get());
+
+        amt.pulse();
+        assertEquals(Status.RUNNING, pt.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(10000, xProperty.get());
+        assertEquals(10000, yProperty.get());
+
+        amt.pulse();
+        assertEquals(Status.RUNNING, pt.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+        assertEquals(10000 - TICK_STEP, xProperty.get());
+        assertEquals(10000 - TICK_STEP, yProperty.get());
+
+        pt.pause();
+        pt.jumpTo(Duration.seconds(120).subtract(TickCalculation.toDuration(100)));
+        assertEquals(Status.PAUSED, pt.getStatus());
+        assertEquals(Status.PAUSED, child1X.getStatus());
+        assertEquals(Status.PAUSED, child1Y.getStatus());
+        assertEquals(0 + TICK_STEP, xProperty.get());
+        assertEquals(0 + TICK_STEP, yProperty.get());
+
+        pt.play();
+        assertEquals(Status.RUNNING, pt.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+        assertEquals(0 + TICK_STEP, xProperty.get());
+        assertEquals(0 + TICK_STEP, yProperty.get());
+
+        amt.pulse();
+        assertEquals(Status.RUNNING, pt.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(0, xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        amt.pulse();
+        assertEquals(Status.RUNNING, pt.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+        assertEquals(0 + TICK_STEP, xProperty.get());
+        assertEquals(0 + TICK_STEP, yProperty.get());
+    }
+
 }
--- a/javafx-ui-common/test/unit/javafx/animation/SequentialTransitionPlayTest.java	Thu Jan 10 10:20:41 2013 +1300
+++ b/javafx-ui-common/test/unit/javafx/animation/SequentialTransitionPlayTest.java	Wed Jan 09 17:07:00 2013 -0500
@@ -200,8 +200,292 @@
     }
 
     @Test
-    public void testPause() {
-        
+    public void testPauseAndJump() {
+        st.getChildren().addAll(child1X, child1Y);
+
+        st.play();
+        st.jumpTo(Duration.seconds(10));
+        st.pause();
+        assertEquals(Status.PAUSED, st.getStatus());
+        assertEquals(Status.PAUSED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(10000, xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        amt.pulse();
+        assertEquals(Duration.seconds(10), st.getCurrentTime());
+        assertEquals(Duration.seconds(10), child1X.getCurrentTime());
+        assertEquals(Duration.ZERO, child1Y.getCurrentTime());
+        assertEquals(10000, xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        st.play();
+        st.jumpTo(Duration.seconds(50));
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(Duration.seconds(50), st.getCurrentTime());
+        assertEquals(Duration.seconds(50), child1X.getCurrentTime());
+        assertEquals(Duration.seconds(0), child1Y.getCurrentTime());
+        assertEquals(50000, xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        amt.pulse();
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(50000 + Math.round(TickCalculation.toMillis(100)), xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        st.pause();
+        st.jumpTo(Duration.seconds(65));
+        assertEquals(Duration.seconds(65), st.getCurrentTime());
+        assertEquals(Duration.seconds(60), child1X.getCurrentTime());
+        assertEquals(Duration.seconds(5), child1Y.getCurrentTime());
+        assertEquals(Status.PAUSED, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.PAUSED, child1Y.getStatus());
+        assertEquals(60000, xProperty.get());
+        assertEquals(5000, yProperty.get());
+
+        amt.pulse();
+        assertEquals(Status.PAUSED, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.PAUSED, child1Y.getStatus());
+        assertEquals(60000, xProperty.get());
+        assertEquals(5000, yProperty.get());
+
+        st.play();
+        st.jumpTo(Duration.minutes(1).add(Duration.seconds(10)).subtract(TickCalculation.toDuration(100)));
+        assertEquals(Duration.seconds(70).subtract(TickCalculation.toDuration(100)), st.getCurrentTime());
+        assertEquals(Duration.seconds(60), child1X.getCurrentTime());
+        assertEquals(Duration.seconds(10).subtract(TickCalculation.toDuration(100)), child1Y.getCurrentTime());
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+        assertEquals(60000, xProperty.get());
+        assertEquals(10000 - Math.round(TickCalculation.toMillis(100)), yProperty.get());
+
+
+        amt.pulse();
+        assertEquals(Duration.seconds(70), st.getCurrentTime());
+        assertEquals(Duration.seconds(60), child1X.getCurrentTime());
+        assertEquals(Duration.seconds(10), child1Y.getCurrentTime());
+        assertEquals(Status.STOPPED, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(60000, xProperty.get());
+        assertEquals(10000, yProperty.get());
+    }
+
+    @Test
+    public void testPauseAndJumpReversed1() {
+        st.getChildren().addAll(child1X, child1Y);
+        st.setRate(-1.0);
+
+        st.jumpTo(Duration.seconds(70));
+        st.play();
+        amt.pulse();
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+        assertEquals(60000, xProperty.get());
+        assertEquals(10000 - Math.round(TickCalculation.toMillis(100)), yProperty.get());
+
+        st.pause();
+        st.jumpTo(Duration.minutes(1).add(Duration.seconds(5)).add(TickCalculation.toDuration(100)));
+        assertEquals(Status.PAUSED, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.PAUSED, child1Y.getStatus());
+        assertEquals(Duration.seconds(65).add(TickCalculation.toDuration(100)), st.getCurrentTime());
+        assertEquals(60000, xProperty.get());
+        assertEquals(5000 + Math.round(TickCalculation.toMillis(100)), yProperty.get());
+
+        st.play();
+        amt.pulse();
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+        assertEquals(60000, xProperty.get());
+        assertEquals(5000, yProperty.get());
+
+        st.pause();
+        st.jumpTo(Duration.seconds(10));
+        assertEquals(Status.PAUSED, st.getStatus());
+        assertEquals(Status.PAUSED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(10000, xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        st.play();
+        amt.pulse();
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(10000  - Math.round(TickCalculation.toMillis(100)), xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        st.pause();
+        st.jumpTo(Duration.seconds(0).add(TickCalculation.toDuration(100)));
+        assertEquals(TickCalculation.toDuration(100), st.getCurrentTime());
+        assertEquals(TickCalculation.toDuration(100), child1X.getCurrentTime());
+        assertEquals(Duration.seconds(0), child1Y.getCurrentTime());
+        assertEquals(Status.PAUSED, st.getStatus());
+        assertEquals(Status.PAUSED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(Math.round(TickCalculation.toMillis(100)), xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        st.play();
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(Math.round(TickCalculation.toMillis(100)), xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        amt.pulse();
+        assertEquals(Duration.seconds(0), st.getCurrentTime());
+        assertEquals(Duration.seconds(0), child1X.getCurrentTime());
+        assertEquals(Duration.seconds(0), child1Y.getCurrentTime());
+        assertEquals(Status.STOPPED, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(0, xProperty.get());
+        assertEquals(0, yProperty.get());
+    }
+
+    @Test
+    public void testPauseAndJumpReversed2() {
+        st.getChildren().addAll(child1X, child1Y);
+        st.setRate(-1.0);
+
+        st.jumpTo(Duration.seconds(70));
+        st.play();
+        amt.pulse();
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+        assertEquals(60000, xProperty.get());
+        assertEquals(10000 - Math.round(TickCalculation.toMillis(100)), yProperty.get());
+
+        st.pause();
+        st.jumpTo(Duration.seconds(50));
+        assertEquals(Status.PAUSED, st.getStatus());
+        assertEquals(Status.PAUSED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(Duration.seconds(50), st.getCurrentTime());
+        assertEquals(50000, xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        st.play();
+        amt.pulse();
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(50000 - Math.round(TickCalculation.toMillis(100)), xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        st.pause();
+        st.jumpTo(Duration.minutes(1).add(Duration.seconds(5)).add(TickCalculation.toDuration(100)));
+        assertEquals(Status.PAUSED, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.PAUSED, child1Y.getStatus());
+        assertEquals(60000, xProperty.get());
+        assertEquals(5000 + Math.round(TickCalculation.toMillis(100)), yProperty.get());
+
+        st.play();
+        amt.pulse();
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+        assertEquals(60000, xProperty.get());
+        assertEquals(5000, yProperty.get());
+    }
+
+    @Test
+    public void testPauseAndJumpAutoReverse() {
+        st.getChildren().addAll(child1X, child1Y);
+        st.setAutoReverse(true);
+        st.setCycleCount(2);
+
+        st.jumpTo(Duration.minutes(1).add(Duration.seconds(10)).subtract(TickCalculation.toDuration(100)));
+        st.play();
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+        assertEquals(60000, xProperty.get());
+        assertEquals(10000 - Math.round(TickCalculation.toMillis(100)), yProperty.get());
+
+        amt.pulse();
+        assertEquals(Duration.seconds(70), st.getCurrentTime());
+        assertEquals(Duration.seconds(60), child1X.getCurrentTime());
+        assertEquals(Duration.seconds(10), child1Y.getCurrentTime());
+        assertEquals(60000, xProperty.get());
+        assertEquals(10000, yProperty.get());
+
+        st.pause();
+        st.jumpTo(Duration.minutes(1).add(Duration.seconds(10)).add(TickCalculation.toDuration(100)));
+        assertEquals(Status.PAUSED, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.PAUSED, child1Y.getStatus());
+        assertEquals(Duration.seconds(70).subtract(TickCalculation.toDuration(100)), st.getCurrentTime());
+        assertEquals(60000, xProperty.get());
+        assertEquals(10000 - Math.round(TickCalculation.toMillis(100)), yProperty.get());
+
+        st.play();
+        amt.pulse();
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+        assertEquals(60000, xProperty.get());
+        assertEquals(10000 - Math.round(TickCalculation.toMillis(2 * 100)), yProperty.get());
+
+        st.pause();
+        st.jumpTo(Duration.seconds(100));
+        assertEquals(Duration.seconds(40), st.getCurrentTime());
+        assertEquals(Duration.seconds(40), child1X.getCurrentTime());
+        assertEquals(Duration.seconds(0), child1Y.getCurrentTime());
+        assertEquals(Status.PAUSED, st.getStatus());
+        assertEquals(Status.PAUSED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(40000, xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        st.play();
+        amt.pulse();
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(40000  - Math.round(TickCalculation.toMillis(100)), xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        st.pause();
+        st.jumpTo(Duration.minutes(2).add(Duration.seconds(20)).subtract(TickCalculation.toDuration(100)));
+        assertEquals(TickCalculation.toDuration(100), st.getCurrentTime());
+        assertEquals(TickCalculation.toDuration(100), child1X.getCurrentTime());
+        assertEquals(Duration.seconds(0), child1Y.getCurrentTime());
+        assertEquals(Status.PAUSED, st.getStatus());
+        assertEquals(Status.PAUSED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(Math.round(TickCalculation.toMillis(100)), xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        st.play();
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(Math.round(TickCalculation.toMillis(100)), xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        amt.pulse();
+        assertEquals(Duration.seconds(0), st.getCurrentTime());
+        assertEquals(Duration.seconds(0), child1X.getCurrentTime());
+        assertEquals(Duration.seconds(0), child1Y.getCurrentTime());
+        assertEquals(Status.STOPPED, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(0, xProperty.get());
+        assertEquals(0, yProperty.get());
     }
 
     @Test
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TextAreaBehavior.java	Thu Jan 10 10:20:41 2013 +1300
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/behavior/TextAreaBehavior.java	Wed Jan 09 17:07:00 2013 -0500
@@ -281,19 +281,11 @@
     }
 
     private void lineStart(boolean select, boolean extendSelection) {
-        if (isRTLText()) {
-            skin.toRightLineEdge(select, extendSelection);
-        } else {
-            skin.toLeftLineEdge(select, extendSelection);
-        }
+        skin.lineStart(select, extendSelection);
     }
 
     private void lineEnd(boolean select, boolean extendSelection) {
-        if (isRTLText()) {
-            skin.toLeftLineEdge(select, extendSelection);
-        } else {
-            skin.toRightLineEdge(select, extendSelection);
-        }
+        skin.lineEnd(select, extendSelection);
     }
 
     protected void scrollCharacterToVisible(int index) {
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextAreaSkin.java	Thu Jan 10 10:20:41 2013 +1300
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextAreaSkin.java	Wed Jan 09 17:07:00 2013 -0500
@@ -43,7 +43,6 @@
 import javafx.event.EventHandler;
 import javafx.geometry.Bounds;
 import javafx.geometry.Insets;
-import javafx.geometry.NodeOrientation;
 import javafx.geometry.Orientation;
 import javafx.geometry.Point2D;
 import javafx.geometry.Rectangle2D;
@@ -61,7 +60,6 @@
 import javafx.scene.shape.Path;
 import javafx.scene.shape.PathElement;
 import javafx.scene.text.Text;
-import javafx.scene.text.TextAlignment;
 import javafx.util.Duration;
 import com.sun.javafx.PlatformUtil;
 import com.sun.javafx.scene.control.behavior.TextAreaBehavior;
@@ -433,8 +431,6 @@
 
 //        setManaged(false);
 
-        contentView.setNodeOrientation(NodeOrientation.LEFT_TO_RIGHT);
-
         // Initialize content
         scrollPane = new ScrollPane();
         scrollPane.setMinWidth(0);
@@ -775,10 +771,6 @@
         paragraphNode.fontProperty().bind(font);
         paragraphNode.fillProperty().bind(textFill);
         paragraphNode.impl_selectionFillProperty().bind(highlightTextFill);
-        
-        if (textArea.getEffectiveNodeOrientation() == NodeOrientation.RIGHT_TO_LEFT) {
-            paragraphNode.setTextAlignment(TextAlignment.RIGHT);
-        }
     }
 
     @Override public void layoutChildren(final double x, final double y,
@@ -1140,6 +1132,11 @@
     double targetCaretX = -1;
 
     @Override public void nextCharacterVisually(boolean moveRight) {
+        if (isRTL()) {
+            // Text node is mirrored.
+            moveRight = !moveRight;
+        }
+
         Text textNode = getTextNode();
         Bounds caretBounds = caretPath.getLayoutBounds();
         if (caretPath.getElements().size() == 4) {
@@ -1161,11 +1158,11 @@
             // We're at beginning or end of line. Try moving up / down.
             int dot = textArea.getCaretPosition();
             targetCaretX = moveRight ? 0 : Double.MAX_VALUE;
-            // TODO: Use Bidi sniffing instead of base direction here?
-            downLines((moveRight != isRTL()) ? -1 : 1, false, false);
+            // TODO: Use Bidi sniffing instead of assuming right means forward here?
+            downLines(moveRight ? 1 : -1, false, false);
             targetCaretX = -1;
             if (dot == textArea.getCaretPosition()) {
-                if (moveRight != isRTL()) {
+                if (moveRight) {
                     textArea.forward();
                 } else {
                     textArea.backward();
@@ -1219,13 +1216,13 @@
                   select, false);
     }
 
-    public void toLeftLineEdge(boolean select, boolean extendSelection) {
+    public void lineStart(boolean select, boolean extendSelection) {
         targetCaretX = 0;
         downLines(0, select, extendSelection);
         targetCaretX = -1;
     }
 
-    public void toRightLineEdge(boolean select, boolean extendSelection) {
+    public void lineEnd(boolean select, boolean extendSelection) {
         targetCaretX = Double.MAX_VALUE;
         downLines(0, select, extendSelection);
         targetCaretX = -1;
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextFieldSkin.java	Thu Jan 10 10:20:41 2013 +1300
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TextFieldSkin.java	Wed Jan 09 17:07:00 2013 -0500
@@ -42,7 +42,6 @@
 import javafx.geometry.Bounds;
 import javafx.geometry.HPos;
 import javafx.geometry.Insets;
-import javafx.geometry.NodeOrientation;
 import javafx.geometry.Point2D;
 import javafx.geometry.Rectangle2D;
 import javafx.scene.Group;
@@ -139,7 +138,7 @@
             @Override
             public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
                 if (textField.getWidth() > 0) {
-                    updateTextNodeCaretPos();
+                    updateTextNodeCaretPos(textField.getCaretPosition());
                     if (!isForwardBias()) {
                         setForwardBias(true);
                     }
@@ -151,7 +150,7 @@
         forwardBiasProperty().addListener(new InvalidationListener() {
             @Override public void invalidated(Observable observable) {
                 if (textField.getWidth() > 0) {
-                    updateTextNodeCaretPos();
+                    updateTextNodeCaretPos(textField.getCaretPosition());
                     updateCaretOff();
                 }
             }
@@ -171,7 +170,6 @@
         clip.heightProperty().bind(textGroup.heightProperty());
 
         // Add content
-        textGroup.setNodeOrientation(NodeOrientation.LEFT_TO_RIGHT);
         textGroup.setClip(clip);
         // Hack to defeat the fact that otherwise when the caret blinks the parent group
         // bounds are completely invalidated and therefore the dirty region is much
@@ -205,7 +203,7 @@
             }
         });
         // updated by listener on caretPosition to ensure order
-        updateTextNodeCaretPos();
+        updateTextNodeCaretPos(textField.getCaretPosition());
         textField.selectionProperty().addListener(new InvalidationListener() {
             @Override public void invalidated(Observable observable) {
                 updateSelection();
@@ -233,8 +231,12 @@
         caretPath.layoutXProperty().bind(textTranslateX);
         textNode.impl_caretShapeProperty().addListener(new InvalidationListener() {
             @Override public void invalidated(Observable observable) {
-                updateTextNodeCaretPos();
                 caretPath.getElements().setAll(textNode.impl_caretShapeProperty().get());
+                if (caretPath.getElements().size() == 0) {
+                    // The caret pos is invalid.
+                    updateTextNodeCaretPos(textField.getCaretPosition());
+                    return;
+                }
                 caretWidth = Math.round(caretPath.getLayoutBounds().getWidth());
             }
         });
@@ -374,11 +376,11 @@
         }
     }
 
-    private void updateTextNodeCaretPos() {
+    private void updateTextNodeCaretPos(int pos) {
         if (isForwardBias()) {
-            textNode.setImpl_caretPosition(getSkinnable().getCaretPosition());
+            textNode.setImpl_caretPosition(pos);
         } else {
-            textNode.setImpl_caretPosition(getSkinnable().getCaretPosition() - 1);
+            textNode.setImpl_caretPosition(pos - 1);
         }
         textNode.impl_caretBiasProperty().set(isForwardBias());
     }
@@ -399,7 +401,9 @@
     }
 
     private void updateSelection() {
-        IndexRange newValue = getSkinnable().getSelection();
+        TextField textField = getSkinnable();
+        IndexRange newValue = textField.getSelection();
+
         if (newValue == null || newValue.getLength() == 0) {
             textNode.impl_selectionStartProperty().set(-1);
             textNode.impl_selectionEndProperty().set(-1);
@@ -418,13 +422,30 @@
         }
 
         if (PlatformUtil.isEmbedded() && newValue != null && newValue.getLength() > 0) {
-            Bounds b = selectionHighlightPath.getBoundsInParent();
-            if (isRTL()) {
-                selectionHandle1.setLayoutX(textGroup.getWidth() - b.getMaxX() - selectionHandle2.getWidth() / 2);
-                selectionHandle2.setLayoutX(textGroup.getWidth() - b.getMinX() - selectionHandle1.getWidth() / 2);
-            } else {
-                selectionHandle1.setLayoutX(b.getMinX() - selectionHandle1.getWidth() / 2);
-                selectionHandle2.setLayoutX(b.getMaxX() - selectionHandle2.getWidth() / 2);
+            int caretPos = textField.getCaretPosition();
+            int anchorPos = textField.getAnchor();
+
+            {
+                // Position the handle for the anchor. This could be handle1 or handle2.
+                // Do this before positioning the handle for the caret.
+                updateTextNodeCaretPos(anchorPos);
+                Bounds b = caretPath.getBoundsInParent();
+                if (caretPos < anchorPos) {
+                    selectionHandle2.setLayoutX(b.getMinX() - selectionHandle2.getWidth() / 2);
+                } else {
+                    selectionHandle1.setLayoutX(b.getMinX() - selectionHandle1.getWidth() / 2);
+                }
+            }
+
+            {
+                // Position handle for the caret. This could be handle1 or handle2.
+                updateTextNodeCaretPos(caretPos);
+                Bounds b = caretPath.getBoundsInParent();
+                if (caretPos < anchorPos) {
+                    selectionHandle1.setLayoutX(b.getMinX() - selectionHandle1.getWidth() / 2);
+                } else {
+                    selectionHandle2.setLayoutX(b.getMinX() - selectionHandle2.getWidth() / 2);
+                }
             }
         }
     }
@@ -533,11 +554,7 @@
                                         caretWidth / 2));
         }
         if (PlatformUtil.isEmbedded()) {
-            if (isRTL()) {
-                caretHandle.setLayoutX(textGroup.getWidth() - caretX - caretHandle.getWidth() / 2 - 1);
-            } else {
-                caretHandle.setLayoutX(caretX - caretHandle.getWidth() / 2 + 1);
-            }
+            caretHandle.setLayoutX(caretX - caretHandle.getWidth() / 2 + 1);
         }
     }
 
@@ -624,13 +641,8 @@
         Insets insets = getSkinnable().getInsets();
         Point2D p;
 
-        if (isRTL()) {
-            p = new Point2D(insets.getLeft() + textGroup.getWidth() - e.getX() - textTranslateX.get(),
-                            e.getY() - insets.getTop());
-        } else {
-            p = new Point2D(e.getX() - textTranslateX.get() - insets.getLeft(),
-                            e.getY() - insets.getTop());
-        }
+        p = new Point2D(e.getX() - textTranslateX.get() - insets.getLeft(),
+                        e.getY() - insets.getTop());
         return textNode.impl_hitTestChar(translateCaretPosition(p));
     }
 
@@ -694,6 +706,11 @@
     }
 
     @Override public void nextCharacterVisually(boolean moveRight) {
+        if (isRTL()) {
+            // Text node is mirrored.
+            moveRight = !moveRight;
+        }
+
         Bounds caretBounds = caretPath.getLayoutBounds();
         if (caretPath.getElements().size() == 4) {
             // The caret is split
@@ -771,11 +788,6 @@
 
     protected HPos getHAlignment() {
         HPos hPos = getSkinnable().getAlignment().getHpos();
-        if (hPos != HPos.CENTER) {
-            if (isRTL()) {
-                hPos = (hPos == HPos.LEFT) ? HPos.RIGHT : HPos.LEFT;
-            }
-        }
         return hPos;
     }
 
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TreeTableRowSkin.java	Thu Jan 10 10:20:41 2013 +1300
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/TreeTableRowSkin.java	Wed Jan 09 17:07:00 2013 -0500
@@ -241,7 +241,7 @@
         throw new UnsupportedOperationException("Not supported yet.");
     }
 
-    @Override protected TableColumnBase<T, ?> getTableColumnBase(TreeTableCell cell) {
+    @Override protected TreeTableColumn<T, ?> getTableColumnBase(TreeTableCell cell) {
         return cell.getTableColumn();
     }