changeset 2002:5e68c3c1e45f 8.0-b68

Automated merge with ssh://jpgodine@jfxsrc.us.oracle.com//javafx/8.0/MASTER/jfx//rt
author jpgodine@JPGODINE-LAP.st-users.us.oracle.com
date Tue, 11 Dec 2012 10:11:51 -0800
parents 8749547f90e5 d42c1ae9369a
children fa103e8c9776 95e34ce7c7d3 bbab7265dba1 d73eadc63171
files javafx-ui-controls/src/com/sun/javafx/scene/control/skin/caspian/caspian.css
diffstat 19 files changed, 1229 insertions(+), 116 deletions(-) [+]
line wrap: on
line diff
--- a/javafx-fxml/src/javafx/fxml/FXMLLoader.java	Tue Dec 11 11:42:53 2012 -0500
+++ b/javafx-fxml/src/javafx/fxml/FXMLLoader.java	Tue Dec 11 10:11:51 2012 -0800
@@ -915,6 +915,15 @@
             FXMLLoader fxmlLoader = new FXMLLoader(location, resources,
                 builderFactory, controllerFactory, charset,
                 loaders);
+            fxmlLoader.parentLoader = FXMLLoader.this;
+            
+            if (isCyclic(FXMLLoader.this, fxmlLoader)) {
+                throw new IOException(
+                        String.format(
+                        "Including \"%s\" in \"%s\" created cyclic reference.",
+                        fxmlLoader.location.toExternalForm(),
+                        FXMLLoader.this.location.toExternalForm()));
+            }
             fxmlLoader.setClassLoader(classLoader);
             fxmlLoader.setStaticLoad(staticLoad);
 
@@ -1566,6 +1575,8 @@
     private ClassLoader classLoader = defaultClassLoader;
     private boolean staticLoad = false;
     private LoadListener loadListener = null;
+    
+    private FXMLLoader parentLoader;
 
     private XMLStreamReader xmlStreamReader = null;
     private Element current = null;
@@ -1809,6 +1820,28 @@
         this.root = root;
     }
 
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof FXMLLoader) {
+            FXMLLoader loader = (FXMLLoader)obj;
+            return loader.location.toExternalForm().equals(
+                    location.toExternalForm());
+        }
+        return false;
+    }            
+    
+    private boolean isCyclic(
+                            FXMLLoader currentLoader, 
+                            FXMLLoader node) {
+        if (currentLoader == null) {
+            return false;
+        }
+        if (currentLoader.equals(node)) {
+            return true;
+        }        
+        return isCyclic(currentLoader.parentLoader, node);
+    }
+        
     /**
      * Returns the controller associated with the root object.
      */
--- a/javafx-fxml/src/javafx/fxml/doc-files/introduction_to_fxml.html	Tue Dec 11 11:42:53 2012 -0500
+++ b/javafx-fxml/src/javafx/fxml/doc-files/introduction_to_fxml.html	Tue Dec 11 10:11:51 2012 -0800
@@ -314,13 +314,13 @@
 <p>When processing markup for an object that will be constructed by a builder, the <span class="code">Builder</span> instances are treated like value objects - if a <span class="code">Builder</span> implements the <span class="code">Map</span> interface, the <span class="code">put()</span> method is used to set the builder's attribute values. Otherwise, the builder is wrapped in a <span class="code">BeanAdapter</span> and its properties are assumed to be exposed via standard Bean setters.</p>
 
 <h4><a name="include_elements">&lt;fx:include&gt;</a></h4>
-<p><assert id="include" group="instance_declarations">The <span class="code">&lt;fx:include&gt;</span> tag creates an object from FXML markup defined in another file.</assert> It is used as follows:</p>
+<p>The <span class="code">&lt;fx:include&gt;</span> tag creates an object from FXML markup defined in another file. It is used as follows:</p>
 
 <pre class="code">
 &lt;fx:include source="<span class="variable">filename</span>"/&gt;
 </pre>
 
-<p>where <span class="variable">filename</span> is the name of the FXML file to include. <assert id="leading_slash_character" group="instance_declarations">Values that begin with a leading slash character are treated as relative to the classpath.</assert> <assert id="no_leading_slash_character" group="instance_declarations">Values with no leading slash are considered relative to the path of the current document.</assert></p>
+<p>where <span class="variable">filename</span> is the name of the FXML file to include. <assert id="include_leading_slash_character" group="instance_declarations">Values that begin with a leading slash character are treated as relative to the classpath.</assert> <assert id="include_no_leading_slash_character" group="instance_declarations">Values with no leading slash are considered relative to the path of the current document.</assert></p>
 
 <p>For example, given the following markup:</p>
 
@@ -420,9 +420,9 @@
 <p>Property elements are generally used when the property value is a complex type that can't be represented using a simple string-based attribute value, or when the character length of the value is so long that specifying it as an attribute would have a negative impact on readability.</p>
 
 <h5>Type Coercion</h5>
-<p>FXML uses "type coercion" to convert property values to the appropriate type as needed. Type coercion is required because the only data types supported by XML are elements, text, and attributes (whose values are also text). However, Java supports a number of different data types including built-in primitive value types as well as extensible reference types.</p>
+<p><assert id="coercion" group="property_elements">FXML uses "type coercion" to convert property values to the appropriate type as needed.</assert> Type coercion is required because the only data types supported by XML are elements, text, and attributes (whose values are also text). However, Java supports a number of different data types including built-in primitive value types as well as extensible reference types.</p>
 
-<p>The FXML loader uses the <span class="code">coerce()</span> method of <span class="code">BeanAdapter</span> to perform any required type conversions. This method is capable of performing basic primitive type conversions such as <span class="code">String</span> to <span class="code">boolean</span> or <span class="code">int</span> to <span class="code">double</span>, and will also convert <span class="code">String</span> to <span class="code">Class</span> or <span class="code">String</span> to <span class="code">Enum</span>. <assert id="additional_conversions" group="property_elements">Additional conversions can be implemented by defining a static <span class="code">valueOf()</span> method on the target type.</assert></p>
+<p>The FXML loader uses the <span class="code">coerce()</span> method of <span class="code">BeanAdapter</span> to perform any required type conversions. This method is capable of performing basic primitive type conversions such as <span class="code">String</span> to <span class="code">boolean</span> or <span class="code">int</span> to <span class="code">double</span>, and will also convert <span class="code">String</span> to <span class="code">Class</span> or <span class="code">String</span> to <span class="code">Enum</span>. Additional conversions can be implemented by defining a static <span class="code">valueOf()</span> method on the target type.</p>
 
 <h4><a name="read_only_list_property_elements">Read-Only List Properties</a></h4>
 <p><assert id="read_only_list_property" group="property_elements">A read-only list property is a Bean property whose getter returns an instance of <span class="code">java.util.List</span> and has no corresponding setter method. The contents of a read-only list element are automatically added to the list as they are processed.</assert></p>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-fxml/test/javafx/fxml/RT_25494_Cycle_DetectionTest.java	Tue Dec 11 10:11:51 2012 -0800
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2010, 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 javafx.fxml;
+
+import java.io.IOException;
+import org.junit.Test;
+
+public class RT_25494_Cycle_DetectionTest {
+    
+    @Test(expected=IOException.class) 
+    public void test_dummy_cycle() throws Exception {
+        FXMLLoader.load(RT_25494_Cycle_DetectionTest.class.getResource("dummy-cycle.fxml"));
+    }
+    
+    @Test(expected=IOException.class) 
+    public void test_one_2_one_cycle() throws Exception {
+        FXMLLoader.load(RT_25494_Cycle_DetectionTest.class.getResource("one-2-one-cycle.fxml"));
+    }
+    
+    @Test(expected=IOException.class) 
+    public void test_cycle() throws Exception {
+        FXMLLoader.load(RT_25494_Cycle_DetectionTest.class.getResource("cycle.fxml"));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-fxml/test/javafx/fxml/cycle.fxml	Tue Dec 11 10:11:51 2012 -0800
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2010, 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.
+-->
+
+<?import javafx.scene.*?>
+<?import javafx.scene.control.*?>
+<?import javafx.scene.layout.*?>
+
+<Scene width="320" height="240" xmlns:fx="http://javafx.com/fxml">
+    <VBox fx:id="root"> 
+        <children>
+            <fx:include source="leaf3.fxml" />
+        </children>
+    </VBox> 
+</Scene>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-fxml/test/javafx/fxml/dummy-cycle.fxml	Tue Dec 11 10:11:51 2012 -0800
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2010, 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.
+-->
+
+<?import javafx.scene.*?>
+<?import javafx.scene.control.*?>
+<?import javafx.scene.layout.*?>
+
+<Scene width="320" height="240" xmlns:fx="http://javafx.com/fxml">
+    <VBox fx:id="root"> 
+        <children>
+            <fx:include source="dummy-cycle.fxml" />
+        </children>
+    </VBox> 
+</Scene>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-fxml/test/javafx/fxml/leaf1.fxml	Tue Dec 11 10:11:51 2012 -0800
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2010, 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.
+-->
+
+<?import javafx.scene.control.*?>
+<?import javafx.scene.layout.*?>
+
+<VBox fx:id="1" xmlns:fx="http://javafx.com/fxml"> 
+    <children>
+        <fx:include source="leaf2.fxml" />
+    </children>
+</VBox>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-fxml/test/javafx/fxml/leaf2.fxml	Tue Dec 11 10:11:51 2012 -0800
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2010, 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.
+-->
+
+<?import javafx.scene.control.*?>
+<?import javafx.scene.layout.*?>
+
+<VBox fx:id="2" xmlns:fx="http://javafx.com/fxml"> 
+    <children>
+        <fx:include source="leaf1.fxml" />
+    </children>
+</VBox> 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-fxml/test/javafx/fxml/leaf3.fxml	Tue Dec 11 10:11:51 2012 -0800
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2010, 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.
+-->
+
+<?import javafx.scene.*?>
+<?import javafx.scene.control.*?>
+<?import javafx.scene.layout.*?>
+
+<VBox fx:id="3" xmlns:fx="http://javafx.com/fxml"> 
+    <children>
+        <fx:include source="leaf4.fxml" />
+    </children>
+</VBox>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-fxml/test/javafx/fxml/leaf4.fxml	Tue Dec 11 10:11:51 2012 -0800
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2010, 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.
+-->
+
+<?import javafx.scene.control.*?>
+<?import javafx.scene.layout.*?>
+
+<VBox fx:id="4" xmlns:fx="http://javafx.com/fxml"> 
+    <children>
+        <fx:include source="cycle.fxml" />
+    </children>
+</VBox>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-fxml/test/javafx/fxml/one-2-one-cycle.fxml	Tue Dec 11 10:11:51 2012 -0800
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Copyright (c) 2010, 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.
+-->
+
+<?import javafx.scene.*?>
+<?import javafx.scene.control.*?>
+<?import javafx.scene.layout.*?>
+
+<Scene width="320" height="240" xmlns:fx="http://javafx.com/fxml">
+    <VBox fx:id="root"> 
+        <children>
+            <fx:include source="leaf2.fxml" />
+        </children>    
+    </VBox> 
+</Scene>
--- a/javafx-ui-common/nbproject/project.xml	Tue Dec 11 11:42:53 2012 -0500
+++ b/javafx-ui-common/nbproject/project.xml	Tue Dec 11 10:11:51 2012 -0800
@@ -137,7 +137,7 @@
             <compilation-unit>
                 <package-root>${test.dir}</package-root>
                 <unit-tests/>
-                <classpath mode="compile">${javac.test.classpath}</classpath>
+                <classpath mode="compile">../../rt-closed/javafx-mx-common/dist/javafx-mx-common.jar:../../rt-closed/glass/glass-mat/dist/glass.jar:../../rt-closed/build/deps/plugin_exports.jar:../test-stub-toolkit/dist/test-stub-toolkit.jar:../../rt-closed/prism-common/dist/prism-common.jar:build/classes:${jfx.sdk.rt.jar}:../../rt-closed/build/deps/junit.jar:../../artifacts/sdk/rt/lib/jfxrt.jar</classpath>
                 <built-to>${build.test.classes.dir}</built-to>
                 <source-level>1.6</source-level>
             </compilation-unit>
--- a/javafx-ui-common/src/javafx/animation/ParallelTransition.java	Tue Dec 11 11:42:53 2012 -0500
+++ b/javafx-ui-common/src/javafx/animation/ParallelTransition.java	Tue Dec 11 10:11:51 2012 -0800
@@ -38,6 +38,10 @@
 import javafx.util.Duration;
 
 import com.sun.javafx.collections.TrackableObservableList;
+import com.sun.javafx.collections.VetoableListDecorator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
 
@@ -161,34 +165,73 @@
         return node;
     }
 
-    private final ObservableList<Animation> children = new TrackableObservableList<Animation>() {
+    private final Set<Animation> childrenSet = new HashSet<Animation>();
+
+    private final ObservableList<Animation> children = new VetoableListDecorator<Animation>(new TrackableObservableList<Animation>() {
         @Override
         protected void onChanged(Change<Animation> c) {
-            while(c.next()) {
-            for (final Animation animation : c.getRemoved()) {
-                if (animation instanceof Transition) {
-                    final Transition transition = (Transition) animation;
-                    if (transition.parent == ParallelTransition.this) {
-                        transition.parent = null;
-                    }
+            while (c.next()) {
+                for (final Animation animation : c.getRemoved()) {
+                    animation.parent = null;
+                    animation.rateProperty().removeListener(childrenListener);
+                    animation.totalDurationProperty().removeListener(childrenListener);
+                    animation.delayProperty().removeListener(childrenListener);
                 }
-                animation.rateProperty().removeListener(childrenListener);
-                animation.totalDurationProperty().removeListener(childrenListener);
-                animation.delayProperty().removeListener(childrenListener);
-            }
-            for (final Animation animation : c.getAddedSubList()) {
-                if (animation instanceof Transition) {
-                    ((Transition) animation).parent = ParallelTransition.this;
+                for (final Animation animation : c.getAddedSubList()) {
+                    animation.parent = ParallelTransition.this;
+                    animation.rateProperty().addListener(childrenListener);
+                    animation.totalDurationProperty().addListener(childrenListener);
+                    animation.delayProperty().addListener(childrenListener);
                 }
-                animation.rateProperty().addListener(childrenListener);
-                animation.totalDurationProperty().addListener(childrenListener);
-                animation.delayProperty().addListener(childrenListener);
-            }
             }
             childrenListener.invalidated(children);
         }
+    }) {
+
+        @Override
+        protected void onProposedChange(List<Animation> toBeAdded, int... indexes) {
+            IllegalArgumentException exception = null;
+            for (int i = 0; i < indexes.length; i+=2) {
+                for (int idx = indexes[i]; idx < indexes[i+1]; ++idx) {
+                    childrenSet.remove(children.get(idx));
+                }
+            }
+            for (Animation child : toBeAdded) {
+                if (child == null) {
+                    exception = new IllegalArgumentException("Child cannot be null");
+                    break;
+                }
+                if (!childrenSet.add(child)) {
+                    exception = new IllegalArgumentException("Attempting to add a duplicate to the list of children");
+                    break;
+                }
+                if (checkCycle(child, ParallelTransition.this)) {
+                    exception = new IllegalArgumentException("This change would create cycle");
+                    break;
+                }
+            }
+
+            if (exception != null) {
+                childrenSet.clear();
+                childrenSet.addAll(children);
+                throw exception;
+            }
+        }
+
     };
 
+    private static boolean checkCycle(Animation child, Animation parent) {
+        Animation a = parent;
+        while (a != child) {
+            if (a.parent != null) {
+                a = a.parent;
+            } else {
+                return false;
+            }
+        }
+        return true;
+    }
+
     /**
      * A list of {@link javafx.animation.Animation Animations} that will be
      * played sequentially.
@@ -258,8 +301,8 @@
     @Override
     protected Node getParentTargetNode() {
         final Node node = getNode();
-        return (node != null) ? node : (parent != null) ? parent
-                .getParentTargetNode() : null;
+        return (node != null) ? node : (parent != null && parent instanceof Transition) ?
+                ((Transition)parent).getParentTargetNode() : null;
     }
 
     private Duration computeCycleDuration() {
@@ -392,7 +435,7 @@
                 if ((newTicks >= delays[i]) && ((oldTicks <= delays[i]) || ((oldTicks < add(delays[i], durations[i])) && (animation.getStatus() == Status.STOPPED)))) {
                     final boolean enteringCycle = oldTicks <= delays[i];
                     if (enteringCycle) {
-                        animation.jumpTo(Duration.ZERO);
+                        animation.clipEnvelope.jumpTo(0);
                     }
                     if (!startChild(animation, i)) {
                         if (enteringCycle) {
@@ -421,7 +464,7 @@
                     if ((oldTicks >= add(durations[i], delays[i])) || ((oldTicks >= delays[i]) && (animation.getStatus() == Status.STOPPED))){
                         final boolean enteringCycle = oldTicks >= add(durations[i], delays[i]);
                         if (enteringCycle) {
-                            animation.jumpTo(toDuration(durations[i], rates[i]));
+                            animation.clipEnvelope.jumpTo(Math.round(durations[i] * rates[i]));
                         }
                         if (!startChild(animation, i)) {
                             if (enteringCycle) {
@@ -454,6 +497,7 @@
      */
     @Deprecated
     @Override public void impl_jumpTo(long currentTicks, long cycleTicks, boolean forceJump) {
+        impl_setCurrentTicks(currentTicks);
         if (getStatus() == Status.STOPPED && !forceJump) {
             return;
         }
@@ -464,13 +508,13 @@
         for (final Animation animation : cachedChildren) {
             if (newTicks <= delays[i]) {
                 offsetTicks[i] = 0;
-                animation.jumpTo(Duration.ZERO);
+                animation.clipEnvelope.jumpTo(0);
                 if ((animation.getStatus() != Status.STOPPED) && (getCurrentRate() < 0)) {
                     animation.impl_finished();
                 }
             } else if (newTicks >= add(durations[i], delays[i])) {
                 offsetTicks[i] = 0;
-                animation.jumpTo(toDuration(durations[i], rates[i]));
+                animation.clipEnvelope.jumpTo(Math.round(durations[i] * rates[i]));
                 if ((animation.getStatus() != Status.STOPPED) && (getCurrentRate() > 0)) {
                     animation.impl_finished();
                 }
@@ -478,7 +522,7 @@
                 // TODO: This does probably not work if animation is paused (getCurrentRate() == 0)
                 // TODO: Do I have to use newTicks or currentTicks?
                 offsetTicks[i] += (getCurrentRate() < 0)? sub(add(durations[i], delays[i]), newTicks) : sub(newTicks, delays[i]);
-                animation.jumpTo(toDuration(sub(newTicks, delays[i]), rates[i]));
+                animation.clipEnvelope.jumpTo(Math.round(sub(newTicks, delays[i]) * rates[i]));
             }
             i++;
         }
--- a/javafx-ui-common/src/javafx/animation/SequentialTransition.java	Tue Dec 11 11:42:53 2012 -0500
+++ b/javafx-ui-common/src/javafx/animation/SequentialTransition.java	Tue Dec 11 10:11:51 2012 -0800
@@ -24,6 +24,7 @@
  */
 package javafx.animation;
 
+import com.sun.javafx.animation.TickCalculation;
 import static com.sun.javafx.animation.TickCalculation.*;
 
 import java.util.Arrays;
@@ -40,6 +41,11 @@
 import javafx.util.Duration;
 
 import com.sun.javafx.collections.TrackableObservableList;
+import com.sun.javafx.collections.VetoableListDecorator;
+import com.sun.scenario.animation.AbstractMasterTimer;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 import javafx.beans.value.ChangeListener;
 import javafx.beans.value.ObservableValue;
 
@@ -107,8 +113,8 @@
     private double[] rates;
     private boolean[] forceChildSync;
     private int end;
-    private int curIndex;
-    private long oldTicks = -1L;
+    private int curIndex = BEFORE;
+    private long oldTicks = 0L;
     private long offsetTicks;
     private boolean childrenChanged = true;
     private boolean toggledRate;
@@ -169,25 +175,20 @@
         return node;
     }
 
-    private final ObservableList<Animation> children = new TrackableObservableList<Animation>() {
+    private final Set<Animation> childrenSet = new HashSet<Animation>();
+    
+    private final ObservableList<Animation> children = new VetoableListDecorator<Animation>(new TrackableObservableList<Animation>() {
         @Override
         protected void onChanged(Change<Animation> c) {
-            while(c.next()) {
+            while (c.next()) {
                 for (final Animation animation : c.getRemoved()) {
-                    if (animation instanceof Transition) {
-                        final Transition transition = (Transition) animation;
-                        if (transition.parent == SequentialTransition.this) {
-                            transition.parent = null;
-                        }
-                    }
+                    animation.parent = null;
                     animation.rateProperty().removeListener(childrenListener);
                     animation.totalDurationProperty().removeListener(childrenListener);
                     animation.delayProperty().removeListener(childrenListener);
                 }
                 for (final Animation animation : c.getAddedSubList()) {
-                    if (animation instanceof Transition) {
-                        ((Transition) animation).parent = SequentialTransition.this;
-                    }
+                    animation.parent = SequentialTransition.this;
                     animation.rateProperty().addListener(childrenListener);
                     animation.totalDurationProperty().addListener(childrenListener);
                     animation.delayProperty().addListener(childrenListener);
@@ -195,8 +196,52 @@
             }
             childrenListener.invalidated(children);
         }
+    }) {
+
+        @Override
+        protected void onProposedChange(List<Animation> toBeAdded, int... indexes) {
+            IllegalArgumentException exception = null;
+            for (int i = 0; i < indexes.length; i+=2) {
+                for (int idx = indexes[i]; idx < indexes[i+1]; ++idx) {
+                    childrenSet.remove(children.get(idx));
+                }
+            }
+            for (Animation child : toBeAdded) {
+                if (child == null) {
+                    exception = new IllegalArgumentException("Child cannot be null");
+                    break;
+                }
+                if (!childrenSet.add(child)) {
+                    exception = new IllegalArgumentException("Attempting to add a duplicate to the list of children");
+                    break;
+                }
+                if (checkCycle(child, SequentialTransition.this)) {
+                    exception = new IllegalArgumentException("This change would create cycle");
+                    break;
+                }
+            }
+
+            if (exception != null) {
+                childrenSet.clear();
+                childrenSet.addAll(children);
+                throw exception;
+            }
+        }
+
     };
 
+    private static boolean checkCycle(Animation child, Animation parent) {
+        Animation a = parent;
+        while (a != child) {
+            if (a.parent != null) {
+                a = a.parent;
+            } else {
+                return false;
+            }
+        }
+        return true;
+    }
+
     /**
      * A list of {@link javafx.animation.Animation Animations} that will be
      * played sequentially.
@@ -258,13 +303,20 @@
         this((Node) null);
     }
 
+    // For testing purposes
+    SequentialTransition(AbstractMasterTimer timer) {
+        super(timer);
+        setInterpolator(Interpolator.LINEAR);
+    }
+
     /**
      * {@inheritDoc}
      */
     @Override
     protected Node getParentTargetNode() {
         final Node _node = getNode();
-        return (_node != null) ? _node : ((parent != null) ? parent.getParentTargetNode() : null);
+        return (_node != null) ? _node : ((parent != null && parent instanceof Transition) ?
+                ((Transition)parent).getParentTargetNode() : null);
     }
 
     private Duration computeCycleDuration() {
@@ -347,8 +399,22 @@
         super.impl_start(forceSync);
         toggledRate = false;
         rateProperty().addListener(rateListener);
-        curIndex = (getCurrentRate() > 0) ? BEFORE : end;
         offsetTicks = 0L;
+        double curRate = getCurrentRate();
+        final long currentTicks = TickCalculation.fromDuration(getCurrentTime());
+        if (curRate < 0) {
+            jumpToEnd();
+            curIndex = end;
+            if (currentTicks < startTimes[end]) {
+                impl_jumpTo(currentTicks, startTimes[end], false);
+            }
+        } else {
+            jumpToBefore();
+            curIndex = BEFORE;
+            if (currentTicks > 0) {
+                impl_jumpTo(currentTicks, startTimes[end], false);
+            }
+        }
     }
 
     @Override
@@ -418,7 +484,7 @@
                     if ((oldTicks <= currentDelay) || (current.getStatus() == Status.STOPPED)) {
                         final boolean enteringCycle = oldTicks <= currentDelay;
                         if (enteringCycle) {
-                            current.jumpTo(Duration.ZERO);
+                            current.clipEnvelope.jumpTo(0);
                         }
                         if (!startChild(current, curIndex)) {
                             if (enteringCycle) {
@@ -431,14 +497,14 @@
                             return;
                         }
                     }
-                    final long localTicks = sub(newTicks, currentDelay);
                     if (newTicks >= startTimes[curIndex+1]) {
-                        current.impl_timePulse(Long.MAX_VALUE);
+                        current.impl_timePulse(sub(durations[curIndex], offsetTicks));
                         if (newTicks == cycleTicks) {
                             curIndex = end;
                         }
                     } else {
-                        current.impl_timePulse(calcTimePulse(localTicks));
+                        final long localTicks = sub(sub(newTicks, offsetTicks), currentDelay);
+                        current.impl_timePulse(localTicks);
                     }
                 }
             } else { // getCurrentRate() < 0
@@ -446,7 +512,7 @@
                 if ((oldTicks >= startTimes[curIndex+1]) || ((oldTicks >= currentDelay) && (current.getStatus() == Status.STOPPED))){
                     final boolean enteringCycle = oldTicks >= startTimes[curIndex+1];
                     if (enteringCycle) {
-                        current.jumpTo("end");
+                        current.clipEnvelope.jumpTo(Math.round(durations[curIndex] * rates[curIndex]));
                     }
                     if (!startChild(current, curIndex)) {
                         if (enteringCycle) {
@@ -460,13 +526,13 @@
                     }
                 }
                 if (newTicks <= currentDelay) {
-                    current.impl_timePulse(Long.MAX_VALUE);
+                    current.impl_timePulse(add(durations[curIndex], offsetTicks));
                     if (newTicks == 0) {
                         curIndex = BEFORE;
                     }
                 } else {
-                    final long localTicks = sub(startTimes[curIndex + 1], newTicks);
-                    current.impl_timePulse(calcTimePulse(localTicks));
+                    final long localTicks = sub(startTimes[curIndex + 1], sub(newTicks, offsetTicks));
+                    current.impl_timePulse(localTicks);
                 }
             }
         } else { // curIndex != newIndex
@@ -476,7 +542,7 @@
                     if ((oldTicks <= oldDelay) || ((current.getStatus() == Status.STOPPED) && (oldTicks != startTimes[curIndex + 1]))) {
                         final boolean enteringCycle = oldTicks <= oldDelay;
                         if (enteringCycle) {
-                            current.jumpTo(Duration.ZERO);
+                            current.clipEnvelope.jumpTo(0);
                         }
                         if (!startChild(current, curIndex)) {
                             if (enteringCycle) {
@@ -488,7 +554,7 @@
                         }
                     }
                     if (current.getStatus() == Status.RUNNING) {
-                        current.impl_timePulse(Long.MAX_VALUE);
+                        current.impl_timePulse(sub(durations[curIndex], offsetTicks));
                     }
                     oldTicks = startTimes[curIndex + 1];
                 }
@@ -496,9 +562,9 @@
                 curIndex++;
                 for (; curIndex < newIndex; curIndex++) {
                     final Animation animation = cachedChildren[curIndex];
-                    animation.jumpTo(Duration.ZERO);
+                    animation.clipEnvelope.jumpTo(0);
                     if (startChild(animation, curIndex)) {
-                        animation.impl_timePulse(Long.MAX_VALUE);
+                        animation.impl_timePulse(durations[curIndex]); // No need to subtract offsetTicks ( == 0)
                     } else {
                         final EventHandler<ActionEvent> handler = animation.getOnFinished();
                         if (handler != null) {
@@ -508,16 +574,16 @@
                     oldTicks = startTimes[curIndex + 1];
                 }
                 final Animation newAnimation = cachedChildren[curIndex];
-                newAnimation.jumpTo(Duration.ZERO);
+                newAnimation.clipEnvelope.jumpTo(0);
                 if (startChild(newAnimation, curIndex)) {
                     if (newTicks >= startTimes[curIndex+1]) {
-                        newAnimation.impl_timePulse(Long.MAX_VALUE);
+                        newAnimation.impl_timePulse(durations[curIndex]); // No need to subtract offsetTicks ( == 0)
                         if (newTicks == cycleTicks) {
                             curIndex = end;
                         }
                     } else {
-                        final long localTicks = sub(newTicks, add(startTimes[curIndex], delays[curIndex]));
-                        newAnimation.impl_timePulse(calcTimePulse(localTicks));
+                        final long localTicks = sub(sub(newTicks, offsetTicks), add(startTimes[curIndex], delays[curIndex]));
+                        newAnimation.impl_timePulse(localTicks);
                     }
                 } else {
                     final EventHandler<ActionEvent> handler = newAnimation.getOnFinished();
@@ -531,7 +597,7 @@
                     if ((oldTicks >= startTimes[curIndex+1]) || ((oldTicks > oldDelay) && (current.getStatus() == Status.STOPPED))){
                         final boolean enteringCycle = oldTicks >= startTimes[curIndex+1];
                         if (enteringCycle) {
-                            current.jumpTo("end");
+                            current.clipEnvelope.jumpTo(Math.round(durations[curIndex] * rates[curIndex]));
                         }
                         if (!startChild(current, curIndex)) {
                             if (enteringCycle) {
@@ -543,7 +609,7 @@
                         }
                     }
                     if (current.getStatus() == Status.RUNNING) {
-                        current.impl_timePulse(Long.MAX_VALUE);
+                        current.impl_timePulse(add(durations[curIndex], offsetTicks));
                     }
                     oldTicks = startTimes[curIndex];
                 }
@@ -551,9 +617,9 @@
                 curIndex--;
                 for (; curIndex > newIndex; curIndex--) {
                     final Animation animation = cachedChildren[curIndex];
-                    animation.jumpTo(toDuration(durations[curIndex], rates[curIndex]));
+                    animation.clipEnvelope.jumpTo(Math.round(durations[curIndex] * rates[curIndex]));
                     if (startChild(animation, curIndex)) {
-                        animation.impl_timePulse(Long.MAX_VALUE);
+                        animation.impl_timePulse(durations[curIndex]); // No need to subtract offsetTicks ( == 0)
                     } else {
                         final EventHandler<ActionEvent> handler = animation.getOnFinished();
                         if (handler != null) {
@@ -563,16 +629,16 @@
                     oldTicks = startTimes[curIndex];
                 }
                 final Animation newAnimation = cachedChildren[curIndex];
-                newAnimation.jumpTo("end");
+                newAnimation.clipEnvelope.jumpTo(Math.round(durations[curIndex] * rates[curIndex]));
                 if (startChild(newAnimation, curIndex)) {
                     if (newTicks <= add(startTimes[curIndex], delays[curIndex])) {
-                        newAnimation.impl_timePulse(Long.MAX_VALUE);
+                        newAnimation.impl_timePulse(durations[curIndex]); // No need to subtract offsetTicks ( == 0)
                         if (newTicks == 0) {
                             curIndex = BEFORE;
                         }
                     } else {
-                        final long localTicks = sub(startTimes[curIndex + 1], newTicks);
-                        newAnimation.impl_timePulse(calcTimePulse(localTicks));
+                        final long localTicks = sub(startTimes[curIndex + 1], sub(newTicks, offsetTicks));
+                        newAnimation.impl_timePulse(localTicks);
                     }
                 } else {
                     final EventHandler<ActionEvent> handler = newAnimation.getOnFinished();
@@ -586,11 +652,14 @@
     }
 
     @Override void impl_jumpTo(long currentTicks, long cycleTicks, boolean forceJump) {
-        if (getStatus() == Status.STOPPED && !forceJump) {
+        impl_setCurrentTicks(currentTicks);
+        final Status status = getStatus();
+
+        if (status == Status.STOPPED && !forceJump) {
             return;
         }
+        
         impl_sync(false);
-        final Status status = getStatus();
         final double frac = calculateFraction(currentTicks, cycleTicks);
         final long newTicks = Math.max(0, Math.min(getCachedInterpolator().interpolate(0, cycleTicks, frac), cycleTicks));
         final int oldIndex = curIndex;
@@ -605,13 +674,26 @@
                         cachedChildren[oldIndex].impl_stop();
                     }
                 }
-                if (currentRate >= 0 && curIndex < oldIndex) {
-                    for (int i = oldIndex == end ? end - 1 : oldIndex; i > curIndex; --i) {
-                        cachedChildren[i].impl_jumpTo(0, durations[i], true);
+                if (currentRate >= 0) {
+                    if (curIndex < oldIndex) {
+                        for (int i = oldIndex == end ? end - 1 : oldIndex; i > curIndex; --i) {
+                            cachedChildren[i].impl_jumpTo(0, durations[i], true);
+                        }
+                    } else { //curIndex > oldIndex as curIndex != oldIndex
+                        for (int i = oldIndex == BEFORE? 0 : oldIndex; i < curIndex; ++i) {
+                            cachedChildren[i].impl_jumpTo(durations[i], durations[i], true);
+                        }
                     }
-                } else if (currentRate <= 0 && curIndex > oldIndex) {
-                    for (int i = oldIndex == BEFORE ? 0 : oldIndex; i < curIndex; ++i) {
-                        cachedChildren[i].impl_jumpTo(durations[i], durations[i], true);
+
+                } else if (currentRate <= 0) {
+                    if (curIndex > oldIndex) {
+                        for (int i = oldIndex == BEFORE ? 0 : oldIndex; i < curIndex; ++i) {
+                            cachedChildren[i].impl_jumpTo(durations[i], durations[i], true);
+                        }
+                    } else {
+                        for (int i = oldIndex == end ? end - 1: oldIndex; i > curIndex; --i) {
+                            cachedChildren[i].impl_jumpTo(0, durations[i], true);
+                        }
                     }
                 }
                 startChild(newAnimation, curIndex);
@@ -621,11 +703,27 @@
             }
         }
         // TODO: This does probably not work if animation is paused (getCurrentRate() == 0)
-        offsetTicks = (currentRate < 0)? sub(startTimes[curIndex+1], newTicks) : sub(newTicks, add(startTimes[curIndex], delays[curIndex]));
-        newAnimation.jumpTo(toDuration(sub(newTicks, add(startTimes[curIndex], delays[curIndex])), rates[curIndex]));
+        if (oldIndex == curIndex) {
+            offsetTicks += newTicks - oldTicks;
+        } else {
+            offsetTicks = currentRate > 0 ? newTicks - add(startTimes[curIndex], delays[curIndex]) : newTicks - startTimes[curIndex + 1];
+        }
+        newAnimation.clipEnvelope.jumpTo(Math.round(sub(newTicks, add(startTimes[curIndex], delays[curIndex])) * rates[curIndex]));
         oldTicks = newTicks;
     }
 
+    private void jumpToEnd() {
+        for (int i = 0 ; i < end; ++i) {
+            cachedChildren[i].impl_jumpTo(durations[i], durations[i], true);
+        }
+    }
+
+    private void jumpToBefore() {
+        for (int i = end - 1 ; i >= 0; --i) {
+            cachedChildren[i].impl_jumpTo(0, durations[i], true);
+        }
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -634,7 +732,4 @@
         // no-op
     }
 
-    private long calcTimePulse(long ticks) {
-        return sub(ticks, offsetTicks);
-    }
 }
--- a/javafx-ui-common/src/javafx/animation/Transition.java	Tue Dec 11 11:42:53 2012 -0500
+++ b/javafx-ui-common/src/javafx/animation/Transition.java	Tue Dec 11 10:11:51 2012 -0800
@@ -25,6 +25,7 @@
 
 package javafx.animation;
 
+import com.sun.scenario.animation.AbstractMasterTimer;
 import javafx.beans.property.ObjectProperty;
 import javafx.beans.property.SimpleObjectProperty;
 import javafx.scene.Node;
@@ -132,15 +133,6 @@
     }
 
     /**
-     * The parent of this {@code Transition}. If this transition has not been
-     * added to another transition, such as {@link ParallelTransition} and
-     * {@link SequentialTransition}, then parent will be null.
-     * 
-     * @defaultValue null
-     */
-    Transition parent = null;
-
-    /**
      * The constructor of {@code Transition}.
      * 
      * This constructor allows to define a {@link #targetFramerate}.
@@ -158,13 +150,19 @@
     public Transition() {
     }
 
+    // For testing purposes
+    Transition(AbstractMasterTimer timer) {
+        super(timer);
+    }
+
     /**
      * Returns the target {@link Node} for animation of this {@code Transition}.
      * This method returns {@code node} if it is set, else returns its
      * {@code parent.getTargetNode()} otherwise null.
      */
     protected Node getParentTargetNode() {
-        return (parent != null) ? parent.getParentTargetNode() : null;
+        return (parent != null && parent instanceof Transition) ?
+                ((Transition)parent).getParentTargetNode() : null;
     }
 
     /**
@@ -213,6 +211,7 @@
 
     @Override
     void impl_jumpTo(long currentTicks, long cycleTicks, boolean forceJump) {
+        impl_setCurrentTicks(currentTicks);
         if (getStatus() != Status.STOPPED || forceJump) {
             impl_sync(false);
             interpolate(calculateFraction(currentTicks, cycleTicks));
--- a/javafx-ui-common/src/javafx/scene/layout/BorderStrokeStyle.java	Tue Dec 11 11:42:53 2012 -0500
+++ b/javafx-ui-common/src/javafx/scene/layout/BorderStrokeStyle.java	Tue Dec 11 10:11:51 2012 -0800
@@ -40,7 +40,7 @@
  */
 public final class BorderStrokeStyle {
     private static final List<Double> DOTTED_LIST = Collections.unmodifiableList(asList(0, 2));
-    private static final List<Double> DASHED_LIST = Collections.unmodifiableList(asList(5, 3));
+    private static final List<Double> DASHED_LIST = Collections.unmodifiableList(asList(2, 1.4));
 
     /**
      * Indicates that no stroke should be drawn.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-ui-common/test/unit/javafx/animation/AbstractMasterTimerMock.java	Tue Dec 11 10:11:51 2012 -0800
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2011, 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 javafx.animation;
+
+import com.sun.javafx.animation.TickCalculation;
+import java.util.HashSet;
+import java.util.Set;
+
+import com.sun.scenario.DelayedRunnable;
+import com.sun.scenario.animation.AbstractMasterTimer;
+import com.sun.scenario.animation.shared.PulseReceiver;
+
+public class AbstractMasterTimerMock extends AbstractMasterTimer {
+
+    private final Set<PulseReceiver> targets = new HashSet<PulseReceiver>();
+    
+    private long nanos;
+    
+    public void setNanos(long nanos) {
+        this.nanos = nanos;
+    }
+    
+    @Override
+    public long nanos() {
+        return nanos;
+    }
+
+    @Override
+    protected boolean shouldUseNanoTime() {
+        return true;
+    }
+
+    @Override
+    protected void postUpdateAnimationRunnable(DelayedRunnable animationRunnable) {
+    }
+
+    @Override
+    protected int getPulseDuration(int precision) {
+        return precision / 60;
+    }
+    
+    @Override 
+    public void addPulseReceiver(PulseReceiver target) {
+        super.addPulseReceiver(target);
+        targets.add(target);
+    }
+    
+    @Override 
+    public void removePulseReceiver(PulseReceiver target) {
+        super.addPulseReceiver(target);
+        targets.remove(target);
+    }
+    
+    public boolean containsPulseReceiver(PulseReceiver target) {
+        return targets.contains(target);
+    }
+
+    public void pulse() {
+        nanos += TickCalculation.toMillis(100) * 1000000L;
+        for (PulseReceiver pr : targets) {
+            pr.timePulse(TickCalculation.fromNano(nanos));
+        }
+    }
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-ui-common/test/unit/javafx/animation/SequentialTransitionPlayTest.java	Tue Dec 11 10:11:51 2012 -0800
@@ -0,0 +1,562 @@
+/*
+ * Copyright (c) 2011, 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 javafx.animation;
+
+import com.sun.javafx.animation.TickCalculation;
+import javafx.animation.Animation.Status;
+import javafx.beans.property.LongProperty;
+import javafx.beans.property.SimpleLongProperty;
+import javafx.util.Duration;
+import org.junit.Before;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class SequentialTransitionPlayTest {
+
+    LongProperty xProperty = new SimpleLongProperty();
+    LongProperty yProperty = new SimpleLongProperty();
+    AbstractMasterTimerMock amt;
+    SequentialTransition st;
+    Transition child1X;
+    Transition child2X;
+    Transition child1Y;
+
+    @Before
+    public void setUp() {
+        amt = new AbstractMasterTimerMock();
+        st = new SequentialTransition(amt);
+        child1X = new Transition() {
+            {
+                setCycleDuration(Duration.minutes(1));
+                setInterpolator(Interpolator.LINEAR);
+            }
+
+            @Override
+            protected void interpolate(double d) {
+                xProperty.set(Math.round(d * 60000));
+            }
+        };
+        child2X = new Transition() {
+            {
+                setCycleDuration(Duration.seconds(30));
+                setInterpolator(Interpolator.LINEAR);
+            }
+
+            @Override
+            protected void interpolate(double d) {
+                xProperty.set(10000 + Math.round(d * 30000));
+            }
+        };
+        child1Y = new Transition() {
+            {
+                setCycleDuration(Duration.seconds(10));
+                setInterpolator(Interpolator.LINEAR);
+            }
+
+            @Override
+            protected void interpolate(double d) {
+                yProperty.set(Math.round(d * 10000));
+            }
+        };
+    }
+
+    @Test
+    public void testSimplePlay() {
+        st.getChildren().addAll(child1X, child1Y);
+
+        st.play();
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+
+        amt.pulse();
+        assertEquals(TickCalculation.toDuration(100), st.getCurrentTime());
+        assertEquals(TickCalculation.toDuration(100), child1X.getCurrentTime());
+        assertEquals(Duration.ZERO, child1Y.getCurrentTime());
+        assertEquals(Math.round(TickCalculation.toMillis(100)), xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+
+        st.jumpTo(Duration.minutes(1).subtract(TickCalculation.toDuration(100)));
+
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(60000 - Math.round(TickCalculation.toMillis(100)), xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        amt.pulse();
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(60000, xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        amt.pulse();
+
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+        assertEquals(60000, xProperty.get());
+        assertEquals(Math.round(TickCalculation.toMillis(100)), yProperty.get());
+
+        st.jumpTo(Duration.minutes(1).add(Duration.seconds(10)).subtract(TickCalculation.toDuration(100)));
+
+        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(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 testSimplePlayReversed() {
+        st.getChildren().addAll(child1X, child1Y);
+        st.setRate(-1.0);
+        st.jumpTo(Duration.seconds(70));
+
+        st.play();
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(Duration.seconds(70), st.getCurrentTime());
+        assertEquals(Duration.seconds(60), child1X.getCurrentTime());
+        assertEquals(Duration.seconds(10), child1Y.getCurrentTime());
+
+        amt.pulse();
+        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(60000, xProperty.get());
+        assertEquals(10000 - Math.round(TickCalculation.toMillis(100)), yProperty.get());
+
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+
+        st.jumpTo(Duration.minutes(1).add(TickCalculation.toDuration(100)));
+
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+        assertEquals(60000, xProperty.get());
+        assertEquals(Math.round(TickCalculation.toMillis(100)), yProperty.get());
+
+        amt.pulse();
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(60000, xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        amt.pulse();
+
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(60000 - Math.round(TickCalculation.toMillis(100)), xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        st.jumpTo(TickCalculation.toDuration(100));
+
+        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(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 testPause() {
+        
+    }
+
+    @Test
+    public void testJumpAndPlay() {
+        st.getChildren().addAll(child1X, child1Y);
+
+        st.jumpTo(Duration.seconds(65));
+        st.play();
+
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+        assertEquals(60000, xProperty.get());
+        assertEquals(5000, yProperty.get());
+
+
+        amt.pulse();
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+        assertEquals(60000, xProperty.get());
+        assertEquals(5000 + Math.round(TickCalculation.toMillis(100)), yProperty.get());
+
+    }
+
+    @Test
+    public void testJumpAndPlayReversed() {
+        st.getChildren().addAll(child1X, child1Y);
+        st.setRate(-1.0);
+
+        st.jumpTo(Duration.seconds(65));
+        st.play();
+
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+        assertEquals(60000, xProperty.get());
+        assertEquals(5000, yProperty.get());
+
+
+        amt.pulse();
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+        assertEquals(60000, xProperty.get());
+        assertEquals(5000 - Math.round(TickCalculation.toMillis(100)), yProperty.get());
+
+    }
+
+    
+    @Test
+    public void testCycle() {
+        st.getChildren().addAll(child1X, child1Y);
+        st.setCycleCount(2);
+
+        st.play();
+
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(0, xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        st.jumpTo(Duration.minutes(1).add(Duration.seconds(10)).subtract(TickCalculation.toDuration(100)));
+
+        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(Status.RUNNING, st.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(0, xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        amt.pulse();
+
+        assertEquals(TickCalculation.toDuration(100), st.getCurrentTime());
+        assertEquals(TickCalculation.toDuration(100), child1X.getCurrentTime());
+        assertEquals(Duration.ZERO, child1Y.getCurrentTime());
+        assertEquals(Math.round(TickCalculation.toMillis(100)), xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        st.jumpTo(Duration.minutes(2).add(Duration.seconds(20)).subtract(TickCalculation.toDuration(100)));
+
+        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(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 testCycleReverse() {
+        st.getChildren().addAll(child1X, child1Y);
+        st.setCycleCount(-1);
+        st.setRate(-1.0);
+
+        st.play();
+
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(0, xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        st.jumpTo(TickCalculation.toDuration(100));
+
+        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(Status.RUNNING, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+        assertEquals(60000, xProperty.get());
+        assertEquals(10000, yProperty.get());
+
+        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.jumpTo(Duration.minutes(1).add(Duration.seconds(10)).subtract(TickCalculation.toDuration(100)));
+
+        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(Status.RUNNING, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+        assertEquals(60000, xProperty.get());
+        assertEquals(10000 - Math.round(TickCalculation.toMillis(200)), yProperty.get());
+
+    }
+
+    @Test
+    public void testJump() {
+        st.getChildren().addAll(child1X, child1Y);
+
+        assertEquals(Status.STOPPED, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(0, xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        st.jumpTo(Duration.seconds(10));
+
+        assertEquals(Status.STOPPED, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(0, xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        st.play();
+
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());  //Note: Not sure if we need to have also child1X running at this point
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(10000, xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        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.jumpTo(Duration.seconds(65));
+
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+        assertEquals(60000, xProperty.get());
+        assertEquals(5000, yProperty.get());
+
+        st.jumpTo(Duration.seconds(10));
+
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(10000, xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        st.stop();
+
+        assertEquals(Status.STOPPED, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+        assertEquals(10000, xProperty.get());
+        assertEquals(0, yProperty.get());
+
+    }
+
+    @Test
+    public void testAutoReverse() {
+        st.getChildren().addAll(child1X, child1Y);
+        st.setAutoReverse(true);
+        st.setCycleCount(-1);
+
+        st.play();
+
+        for (int i = 0; i < TickCalculation.fromDuration(Duration.seconds(70)) / 100 - 1; ++i) {
+            amt.pulse();
+        }
+
+        amt.pulse();
+
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+
+        assertEquals(60000, xProperty.get());
+        assertEquals(10000, yProperty.get());
+
+        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());
+
+    }
+
+    @Test
+    public void testAutoReverseWithJump() {
+        st.getChildren().addAll(child1X, child1Y);
+        st.setAutoReverse(true);
+        st.setCycleCount(-1);
+
+        st.play();
+
+        st.jumpTo(Duration.seconds(70).subtract(TickCalculation.toDuration(100)));
+
+        amt.pulse();
+
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+
+        assertEquals(60000, xProperty.get());
+        assertEquals(10000, yProperty.get());
+
+        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());
+
+    }
+
+    @Test
+    public void testChildWithDifferentRate() {
+        st.getChildren().addAll(child1X, child1Y);
+        child1X.setRate(2.0);
+
+        st.play();
+
+        amt.pulse();
+
+        assertEquals(Math.round(TickCalculation.toMillis(100) * 2), xProperty.get());
+
+        st.jumpTo(Duration.seconds(30));
+
+        assertEquals(60000, xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        st.jumpTo(Duration.seconds(40));
+
+        assertEquals(60000, xProperty.get());
+        assertEquals(10000, yProperty.get());
+
+    }
+
+    @Test
+    public void testToggleRate() {
+        st.getChildren().addAll(child1X, child1Y);
+
+        st.play();
+
+        st.jumpTo(Duration.seconds(60));
+
+        amt.pulse();
+
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+
+        assertEquals(60000, xProperty.get());
+        assertEquals(Math.round(TickCalculation.toMillis(100)), yProperty.get());
+
+        st.setRate(-1.0);
+
+        amt.pulse();
+        amt.pulse();
+
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.RUNNING, child1X.getStatus());
+        assertEquals(Status.STOPPED, child1Y.getStatus());
+
+        assertEquals(60000 - Math.round(TickCalculation.toMillis(100)), xProperty.get());
+        assertEquals(0, yProperty.get());
+
+        st.setRate(1.0);
+
+        amt.pulse();
+        amt.pulse();
+
+        assertEquals(Status.RUNNING, st.getStatus());
+        assertEquals(Status.STOPPED, child1X.getStatus());
+        assertEquals(Status.RUNNING, child1Y.getStatus());
+
+        assertEquals(60000, xProperty.get());
+        assertEquals(Math.round(TickCalculation.toMillis(100)), yProperty.get());
+
+    }
+}
--- a/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/caspian/caspian.css	Tue Dec 11 11:42:53 2012 -0500
+++ b/javafx-ui-controls/src/com/sun/javafx/scene/control/skin/caspian/caspian.css	Tue Dec 11 10:11:51 2012 -0800
@@ -1208,7 +1208,7 @@
 .scroll-bar:horizontal > .track-background {
      -fx-background-color:
         -fx-box-border,
-        linear-gradient(to bottom, derive(-fx-color,-15%), derive(-fx-color,2.2%) 20%, derive(-fx-color,60%));
+        linear-gradient(to top, derive(-fx-color,-15%), derive(-fx-color,2.2%) 20%, derive(-fx-color,60%));
     -fx-background-insets:  0, 1;
 }
 
@@ -1223,23 +1223,19 @@
 .scroll-bar:vertical > .track-background {
      -fx-background-color:
         -fx-box-border,
-        linear-gradient(to right, derive(-fx-color,-15%), derive(-fx-color,2.2%) 20%, derive(-fx-color,60%));
+        linear-gradient(to left, derive(-fx-color,-15%), derive(-fx-color,2.2%) 20%, derive(-fx-color,60%));
     -fx-background-insets:  0, 1;
 }
 
 .scroll-bar > .increment-button {
-    -fx-background-color:
-        -fx-box-border,
-        linear-gradient(to bottom, derive(-fx-color,30%) 5%, derive(-fx-color,-17%));
-    -fx-background-insets:  0, 1;
+    -fx-background-color: transparent;
+    -fx-background-insets:  0;
     -fx-padding: 0.25em; /* 3 */
 }
 
 .scroll-bar > .decrement-button {
-    -fx-background-color:
-        -fx-box-border,
-        linear-gradient(to bottom, derive(-fx-color,30%) 5%, derive(-fx-color,-17%));
-    -fx-background-insets:  0, 1;
+    -fx-background-color: transparent;
+    -fx-background-insets:  0;
     -fx-padding: 0.25em; /* 3 */
 }
 
--- a/javafx-ui-controls/src/javafx/scene/control/TextInputControl.java	Tue Dec 11 11:42:53 2012 -0500
+++ b/javafx-ui-controls/src/javafx/scene/control/TextInputControl.java	Tue Dec 11 10:11:51 2012 -0800
@@ -25,13 +25,13 @@
 
 package javafx.scene.control;
 
+import java.text.BreakIterator;
 import javafx.beans.DefaultProperty;
 import javafx.beans.InvalidationListener;
 import javafx.beans.Observable;
 import javafx.beans.binding.IntegerBinding;
 import javafx.beans.binding.StringBinding;
 import javafx.beans.property.BooleanProperty;
-import javafx.beans.property.IntegerProperty;
 import javafx.beans.property.ReadOnlyIntegerProperty;
 import javafx.beans.property.ReadOnlyIntegerWrapper;
 import javafx.beans.property.ReadOnlyObjectProperty;
@@ -39,7 +39,6 @@
 import javafx.beans.property.ReadOnlyStringProperty;
 import javafx.beans.property.ReadOnlyStringWrapper;
 import javafx.beans.property.SimpleBooleanProperty;
-import javafx.beans.property.SimpleIntegerProperty;
 import javafx.beans.property.SimpleStringProperty;
 import javafx.beans.property.StringProperty;
 import javafx.beans.value.ChangeListener;
@@ -47,8 +46,6 @@
 import javafx.beans.value.ObservableValue;
 import javafx.scene.input.Clipboard;
 import javafx.scene.input.ClipboardContent;
-import java.text.BreakIterator;
-
 import com.sun.javafx.Utils;
 import com.sun.javafx.binding.ExpressionHelper;
 import com.sun.javafx.css.StyleManager;
@@ -309,18 +306,21 @@
     /**
      * Removes a range of characters from the content.
      *
-     * @param range
+     * @param range The range of text to delete. The range object must not be null.
      *
      * @see #deleteText(int, int)
      */
     public void deleteText(IndexRange range) {
         replaceText(range, "");
     }
+
     /**
      * Removes a range of characters from the content.
      *
-     * @param start
-     * @param end
+     * @param start The starting index in the range, inclusive. This must be &gt;= 0 and &lt; the end.
+     * @param end The ending index in the range, exclusive. This is one-past the last character to
+     *            delete (consistent with the String manipulation methods). This must be &gt; the start,
+     *            and &lt;= the length of the text.
      */
     public void deleteText(int start, int end) {
         replaceText(start, end, "");
@@ -329,8 +329,8 @@
     /**
      * Replaces a range of characters with the given text.
      *
-     * @param range
-     * @param text
+     * @param range The range of text to replace. The range object must not be null.
+     * @param text The text that is to replace the range. This must not be null.
      *
      * @see #replaceText(int, int, String)
      */
@@ -348,9 +348,11 @@
     /**
      * Replaces a range of characters with the given text.
      *
-     * @param start
-     * @param end
-     * @param text
+     * @param start The starting index in the range, inclusive. This must be &gt;= 0 and &lt; the end.
+     * @param end The ending index in the range, exclusive. This is one-past the last character to
+     *            delete (consistent with the String manipulation methods). This must be &gt; the start,
+     *            and &lt;= the length of the text.
+     * @param text The text that is to replace the range. This must not be null.
      */
     public void replaceText(int start, int end, String text) {
         if (start > end) {