changeset 4149:fa1eb6d3e875

Merge
author ngthomas
date Tue, 02 Jul 2013 23:11:35 -0700
parents 4915a04d88fc 0749a80c0634
children 79c040d01c80
files apps/experiments/3DViewer/src/main/java/com/javafx/experiments/shape3d/SubDivision.java modules/base/src/main/java/com/sun/javafx/animation/TickCalculation.java modules/base/src/main/java/com/sun/scenario/DelayedRunnable.java modules/base/src/main/java/com/sun/scenario/Settings.java modules/base/src/main/java/com/sun/scenario/ToolkitAccessor.java modules/base/src/main/java/com/sun/scenario/animation/AbstractMasterTimer.java modules/base/src/main/java/com/sun/scenario/animation/AnimationPulse.java modules/base/src/main/java/com/sun/scenario/animation/AnimationPulseMBean.java modules/base/src/main/java/com/sun/scenario/animation/NumberTangentInterpolator.java modules/base/src/main/java/com/sun/scenario/animation/SplineInterpolator.java modules/base/src/main/java/com/sun/scenario/animation/shared/AnimationAccessor.java modules/base/src/main/java/com/sun/scenario/animation/shared/ClipEnvelope.java modules/base/src/main/java/com/sun/scenario/animation/shared/ClipInterpolator.java modules/base/src/main/java/com/sun/scenario/animation/shared/FiniteClipEnvelope.java modules/base/src/main/java/com/sun/scenario/animation/shared/GeneralClipInterpolator.java modules/base/src/main/java/com/sun/scenario/animation/shared/InfiniteClipEnvelope.java modules/base/src/main/java/com/sun/scenario/animation/shared/InterpolationInterval.java modules/base/src/main/java/com/sun/scenario/animation/shared/PulseReceiver.java modules/base/src/main/java/com/sun/scenario/animation/shared/SimpleClipInterpolator.java modules/base/src/main/java/com/sun/scenario/animation/shared/SingleLoopClipEnvelope.java modules/base/src/main/java/com/sun/scenario/animation/shared/TimelineClipCore.java modules/base/src/main/java/javafx/animation/Animation.java modules/base/src/main/java/javafx/animation/AnimationAccessorImpl.java modules/base/src/main/java/javafx/animation/AnimationTimer.java modules/base/src/main/java/javafx/animation/Interpolatable.java modules/base/src/main/java/javafx/animation/Interpolator.java modules/base/src/main/java/javafx/animation/KeyFrame.java modules/base/src/main/java/javafx/animation/KeyValue.java modules/base/src/main/java/javafx/animation/Timeline.java modules/base/src/test/java/com/sun/scenario/SettingsTest.java modules/base/src/test/java/com/sun/scenario/StandaloneAccessor.java modules/base/src/test/java/com/sun/scenario/animation/AbstractMasterTimerMock.java modules/base/src/test/java/com/sun/scenario/animation/AbstractMasterTimerTest.java modules/base/src/test/java/com/sun/scenario/animation/NumberTangentInterpolatorTest.java modules/base/src/test/java/com/sun/scenario/animation/SplineInterpolatorTest.java modules/base/src/test/java/com/sun/scenario/animation/shared/ClipEnvelopeMock.java modules/base/src/test/java/com/sun/scenario/animation/shared/ClipTest.java modules/base/src/test/java/com/sun/scenario/animation/shared/FiniteClipEnvelopeTest.java modules/base/src/test/java/com/sun/scenario/animation/shared/GeneralClipInterpolatorTest.java modules/base/src/test/java/com/sun/scenario/animation/shared/InfiniteClipEnvelopeTest.java modules/base/src/test/java/com/sun/scenario/animation/shared/SimpleClipInterpolatorTest.java modules/base/src/test/java/com/sun/scenario/animation/shared/SingleLoopClipEnvelopeTest.java modules/base/src/test/java/com/sun/scenario/animation/shared/TimelineClipCoreTest.java modules/base/src/test/java/javafx/animation/AnimationImpl.java modules/base/src/test/java/javafx/animation/AnimationMock.java modules/base/src/test/java/javafx/animation/AnimationPulseReceiverTest.java modules/base/src/test/java/javafx/animation/AnimationSetRateTest.java modules/base/src/test/java/javafx/animation/AnimationTest.java modules/base/src/test/java/javafx/animation/InterpolatorTest.java modules/base/src/test/java/javafx/animation/KeyFrameTest.java modules/base/src/test/java/javafx/animation/KeyValueTest.java modules/base/src/test/java/javafx/animation/TimelineHelper.java modules/base/src/test/java/javafx/animation/TimelinePlayTest.java modules/base/src/test/java/javafx/animation/TimelineTest.java
diffstat 147 files changed, 14616 insertions(+), 13996 deletions(-) [+]
line wrap: on
line diff
--- a/.classpath	Mon Jul 01 12:20:05 2013 -0700
+++ b/.classpath	Tue Jul 02 23:11:35 2013 -0700
@@ -1,5 +1,11 @@
 <classpath>
   <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+  <classpathentry kind="src" exported="true" path="/fxml"/>
+  <classpathentry kind="src" exported="true" path="/fxpackager"/>
+  <classpathentry kind="src" exported="true" path="/swt"/>
+  <classpathentry kind="src" exported="true" path="/swing"/>
+  <classpathentry kind="src" exported="true" path="/media"/>
+  <classpathentry kind="src" exported="true" path="/web"/>
+  <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
   <classpathentry kind="output" path="bin"/>
-  <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
 </classpath>
--- a/.project	Mon Jul 01 12:20:05 2013 -0700
+++ b/.project	Tue Jul 02 23:11:35 2013 -0700
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <projectDescription>
-	<name>javafx</name>
+	<name>rt</name>
 	<comment></comment>
 	<projects>
 	</projects>
--- a/apps/experiments/3DViewer/src/main/java/com/javafx/experiments/importers/maya/Loader.java	Mon Jul 01 12:20:05 2013 -0700
+++ b/apps/experiments/3DViewer/src/main/java/com/javafx/experiments/importers/maya/Loader.java	Tue Jul 02 23:11:35 2013 -0700
@@ -253,7 +253,7 @@
         
         Node sourceMayaMeshNode = resolveNode(inputMeshMNode);
         Node targetMayaMeshNode = resolveNode(outputMeshMNode);
-            
+        
         if (sourceMayaMeshNode.getClass().equals(PolygonMeshView.class)) {
             PolygonMeshView sourceMayaMeshView = (PolygonMeshView) sourceMayaMeshNode;
             PolygonMeshView targetMayaMeshView = (PolygonMeshView) targetMayaMeshNode;
@@ -462,8 +462,10 @@
             mv.setMesh((PolygonMesh) mesh);
 //            mv.setCullFace(CullFace.NONE); //TODO
             loaded.put(n, mv);
-            if (node != null) {
-                ((Group) node).getChildren().add(mv);
+            if (((PolygonMesh)mesh).getPoints().size() > 0) {
+                if (node != null) {
+                    ((Group) node).getChildren().add(mv);
+                }
             }
         } else {
             MeshView mv = new MeshView();
@@ -483,7 +485,7 @@
             }
         }
     }
-            
+    
     protected void processJointType(MNode n, Group parentNode) {
         // [Note to Alex]: I've re-enabled joints, but not skinning yet [John]
         Node result;
--- a/apps/experiments/3DViewer/src/main/java/com/javafx/experiments/importers/obj/PolyObjImporter.java	Mon Jul 01 12:20:05 2013 -0700
+++ b/apps/experiments/3DViewer/src/main/java/com/javafx/experiments/importers/obj/PolyObjImporter.java	Tue Jul 02 23:11:35 2013 -0700
@@ -285,7 +285,7 @@
         );
         if (debug) {
             System.out.println("mesh.points = " + mesh.getPoints());
-            System.out.println("mesh.texCoords = " + Arrays.toString(mesh.texCoords));
+            System.out.println("mesh.texCoords = " + mesh.getTexCoords());
             System.out.println("mesh.faces: ");
             for (int[] face: mesh.faces) {
                 System.out.println("    face:: "+Arrays.toString(face));
@@ -301,7 +301,7 @@
         materials.put(key, material);
         
         log("Added mesh '" + key + "' of " + (mesh.getPoints().size()/3) + " vertexes, "
-                + (mesh.texCoords.length/2) + " uvs, "
+                + (mesh.getTexCoords().size()/2) + " uvs, "
                 + mesh.faces.length + " faces, "
                 + 0 + " smoothing groups.");
         log("material diffuse color = " + ((PhongMaterial) material).getDiffuseColor());
--- a/apps/experiments/3DViewer/src/main/java/com/javafx/experiments/jfx3dviewer/ContentModel.java	Mon Jul 01 12:20:05 2013 -0700
+++ b/apps/experiments/3DViewer/src/main/java/com/javafx/experiments/jfx3dviewer/ContentModel.java	Tue Jul 02 23:11:35 2013 -0700
@@ -55,7 +55,7 @@
 import javafx.scene.transform.Rotate;
 import javafx.scene.transform.Translate;
 import com.javafx.experiments.shape3d.PolygonMeshView;
-import com.javafx.experiments.shape3d.SubDivision;
+import com.javafx.experiments.shape3d.SubdivisionMesh;
 import javafx.beans.property.ObjectProperty;
 
 /**
@@ -140,8 +140,8 @@
     };
     private boolean wireframe = false;
     private int subdivisionLevel = 0;
-    private SubDivision.BoundaryMode boundaryMode = SubDivision.BoundaryMode.CREASE_EDGES;
-    private SubDivision.MapBorderMode mapBorderMode = SubDivision.MapBorderMode.NOT_SMOOTH;
+    private SubdivisionMesh.BoundaryMode boundaryMode = SubdivisionMesh.BoundaryMode.CREASE_EDGES;
+    private SubdivisionMesh.MapBorderMode mapBorderMode = SubdivisionMesh.MapBorderMode.NOT_SMOOTH;
 
     public ContentModel() {
         subScene = new SubScene(root3D,400,400,true,false);
@@ -365,14 +365,14 @@
         }
     }
 
-    public SubDivision.BoundaryMode getBoundaryMode() {
+    public SubdivisionMesh.BoundaryMode getBoundaryMode() {
         return boundaryMode;
     }
-    public void setBoundaryMode(SubDivision.BoundaryMode boundaryMode) {
+    public void setBoundaryMode(SubdivisionMesh.BoundaryMode boundaryMode) {
         this.boundaryMode = boundaryMode;
         setBoundaryMode(root3D, boundaryMode);
     }
-    private void setBoundaryMode(Node node, SubDivision.BoundaryMode boundaryMode) {
+    private void setBoundaryMode(Node node, SubdivisionMesh.BoundaryMode boundaryMode) {
         if (node instanceof PolygonMeshView) {
             ((PolygonMeshView)node).setBoundaryMode(boundaryMode);
         } else if (node instanceof Parent) {
@@ -380,14 +380,14 @@
         }
     }
     
-    public SubDivision.MapBorderMode getMapBorderMode() {
+    public SubdivisionMesh.MapBorderMode getMapBorderMode() {
         return mapBorderMode;
     }
-    public void setMapBorderMode(SubDivision.MapBorderMode mapBorderMode) {
+    public void setMapBorderMode(SubdivisionMesh.MapBorderMode mapBorderMode) {
         this.mapBorderMode = mapBorderMode;
         setMapBorderMode(root3D, mapBorderMode);
     }
-    private void setMapBorderMode(Node node, SubDivision.MapBorderMode mapBorderMode) {
+    private void setMapBorderMode(Node node, SubdivisionMesh.MapBorderMode mapBorderMode) {
         if (node instanceof PolygonMeshView) {
             ((PolygonMeshView)node).setMapBorderMode(mapBorderMode);
         } else if (node instanceof Parent) {
--- a/apps/experiments/3DViewer/src/main/java/com/javafx/experiments/jfx3dviewer/SettingsController.java	Mon Jul 01 12:20:05 2013 -0700
+++ b/apps/experiments/3DViewer/src/main/java/com/javafx/experiments/jfx3dviewer/SettingsController.java	Tue Jul 02 23:11:35 2013 -0700
@@ -46,7 +46,7 @@
 import javafx.scene.control.Toggle;
 import javafx.scene.control.ToggleGroup;
 import javafx.scene.paint.Color;
-import com.javafx.experiments.shape3d.SubDivision;
+import com.javafx.experiments.shape3d.SubdivisionMesh;
 import javafx.beans.binding.ObjectBinding;
 import javafx.event.EventHandler;
 import javafx.scene.Node;
@@ -150,7 +150,7 @@
                     subdivisionBoundaryGroup.selectToggle(oldValue);
                     selectedToggle = oldValue;
                 } else {
-                    contentModel.setBoundaryMode((SubDivision.BoundaryMode) selectedToggle.getUserData());
+                    contentModel.setBoundaryMode((SubdivisionMesh.BoundaryMode) selectedToggle.getUserData());
                 }
             }
         });
@@ -160,7 +160,7 @@
                     subdivisionSmoothGroup.selectToggle(oldValue);
                     selectedToggle = oldValue;
                 } else {
-                    contentModel.setMapBorderMode((SubDivision.MapBorderMode) selectedToggle.getUserData());
+                    contentModel.setMapBorderMode((SubdivisionMesh.MapBorderMode) selectedToggle.getUserData());
                 }
             }
         });
--- a/apps/experiments/3DViewer/src/main/java/com/javafx/experiments/jfx3dviewer/settings.fxml	Mon Jul 01 12:20:05 2013 -0700
+++ b/apps/experiments/3DViewer/src/main/java/com/javafx/experiments/jfx3dviewer/settings.fxml	Tue Jul 02 23:11:35 2013 -0700
@@ -97,7 +97,7 @@
                     <ToggleGroup fx:id="subdivisionBoundaryGroup" />
                   </toggleGroup>
                   <userData>
-                    <SubDivision.BoundaryMode fx:value="CREASE_EDGES"/>
+                    <SubdivisionMesh.BoundaryMode fx:value="CREASE_EDGES"/>
                   </userData>
                   <tooltip>
                     <Tooltip text="Only edges at the boundary are treated as creases" />
@@ -105,7 +105,7 @@
                 </ToggleButton>
                 <ToggleButton mnemonicParsing="false" styleClass="right-pill" text="All" toggleGroup="$subdivisionBoundaryGroup">
                   <userData>
-                    <SubDivision.BoundaryMode fx:value="CREASE_ALL"/>
+                    <SubdivisionMesh.BoundaryMode fx:value="CREASE_ALL"/>
                   </userData>
                   <tooltip>
                     <Tooltip text="Edges and points at the boundary are treated as creases" />
@@ -121,7 +121,7 @@
                     <ToggleGroup fx:id="subdivisionSmoothGroup" />
                   </toggleGroup>
                   <userData>
-                    <SubDivision.MapBorderMode fx:value="NOT_SMOOTH"/>
+                    <SubdivisionMesh.MapBorderMode fx:value="NOT_SMOOTH"/>
                   </userData>
                   <tooltip>
                     <Tooltip text="Keeps the same uvs for all control points" />
@@ -129,7 +129,7 @@
                 </ToggleButton>
                 <ToggleButton mnemonicParsing="false" styleClass="center-pill" text="Internal" toggleGroup="$subdivisionSmoothGroup">
                   <userData>
-                    <SubDivision.MapBorderMode fx:value="SMOOTH_INTERNAL"/>
+                    <SubdivisionMesh.MapBorderMode fx:value="SMOOTH_INTERNAL"/>
                   </userData>
                   <tooltip>
                     <Tooltip text="Smooths uvs of points at corners" />
@@ -137,7 +137,7 @@
                 </ToggleButton>
                 <ToggleButton mnemonicParsing="false" styleClass="right-pill" text="All" toggleGroup="$subdivisionSmoothGroup">
                   <userData>
-                    <SubDivision.MapBorderMode fx:value="SMOOTH_ALL"/>
+                    <SubdivisionMesh.MapBorderMode fx:value="SMOOTH_ALL"/>
                   </userData>
                   <tooltip>
                     <Tooltip text="Smooths uvs of points at boundaries" />
--- a/apps/experiments/3DViewer/src/main/java/com/javafx/experiments/shape3d/PolygonMesh.java	Mon Jul 01 12:20:05 2013 -0700
+++ b/apps/experiments/3DViewer/src/main/java/com/javafx/experiments/shape3d/PolygonMesh.java	Tue Jul 02 23:11:35 2013 -0700
@@ -10,15 +10,15 @@
  */
 public class PolygonMesh {
     private final ObservableFloatArray points = FXCollections.observableFloatArray();
-    public float[] texCoords;
+    private final ObservableFloatArray texCoords = FXCollections.observableFloatArray();
     public int[][] faces;
-    private int numEdgesInFaces = -1;
+    protected int numEdgesInFaces = -1;
 
     public PolygonMesh() {}
 
-    public PolygonMesh(float[] points,float[] texCoords, int[][] faces) {
+    public PolygonMesh(float[] points, float[] texCoords, int[][] faces) {
         this.points.addAll(points);
-        this.texCoords = texCoords;
+        this.texCoords.addAll(texCoords);
         this.faces = faces;
     }
 
@@ -26,6 +26,10 @@
         return points;
     }
     
+    public ObservableFloatArray getTexCoords() {
+        return texCoords;
+    }
+    
     public int getNumEdgesInFaces() {
         if (numEdgesInFaces == -1) {
             numEdgesInFaces = 0;
--- a/apps/experiments/3DViewer/src/main/java/com/javafx/experiments/shape3d/PolygonMeshView.java	Mon Jul 01 12:20:05 2013 -0700
+++ b/apps/experiments/3DViewer/src/main/java/com/javafx/experiments/shape3d/PolygonMeshView.java	Tue Jul 02 23:11:35 2013 -0700
@@ -4,9 +4,10 @@
 import javafx.beans.property.ObjectProperty;
 import javafx.beans.property.SimpleIntegerProperty;
 import javafx.beans.property.SimpleObjectProperty;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
 import javafx.collections.ArrayChangeListener;
 import javafx.collections.ObservableFloatArray;
-import javafx.collections.ObservableIntegerArray;
 import javafx.scene.Parent;
 import javafx.scene.paint.Material;
 import javafx.scene.shape.CullFace;
@@ -14,15 +15,41 @@
 import javafx.scene.shape.MeshView;
 import javafx.scene.shape.TriangleMesh;
 
+import static javafx.scene.shape.TriangleMesh.*;
+import static com.javafx.experiments.shape3d.SubdivisionMesh.*;
+
 /**
  * A MeshView node for Polygon Meshes
  */
 public class PolygonMeshView extends Parent {
     private static final boolean DEBUG = false;
     private final MeshView meshView = new MeshView();
-    private PolygonMesh subdividedMesh = null;
-    // TODO keep only one TriangleMesh around
 
+    private TriangleMesh triangleMesh = new TriangleMesh();
+    
+    // this is null if no subdivision is happening (i.e. subdivisionLevel = 0);
+    private SubdivisionMesh subdivisionMesh;
+    
+    private final ArrayChangeListener<ObservableFloatArray> meshPointsListener = new ArrayChangeListener<ObservableFloatArray>() {
+        @Override
+        public void onChanged(ObservableFloatArray t, boolean bln, int i, int i1) {
+            pointsDirty = true;
+            updateMesh();
+        }
+    };
+    private final ArrayChangeListener<ObservableFloatArray> meshTexCoordListener = new ArrayChangeListener<ObservableFloatArray>() {
+        @Override
+        public void onChanged(ObservableFloatArray t, boolean bln, int i, int i1) {
+            texCoordsDirty = true;
+            updateMesh();
+        }
+    };
+    
+    private boolean pointsDirty = true;
+    private boolean pointsSizeDirty = true;
+    private boolean texCoordsDirty = true;
+    private boolean facesDirty = true;
+    
     // =========================================================================
     // PROPERTIES
 
@@ -31,25 +58,35 @@
      *
      * @defaultValue null
      */
-    private ObjectProperty<PolygonMesh> mesh = new SimpleObjectProperty<PolygonMesh>(){
-        @Override protected void invalidated() {
-            updateSubdivision();
+    private ObjectProperty<PolygonMesh> meshProperty;
+    public PolygonMesh getMesh() { return meshProperty().get(); }
+    public void setMesh(PolygonMesh mesh) { meshProperty().set(mesh);}
+    public ObjectProperty<PolygonMesh> meshProperty() { 
+        if (meshProperty == null) {
+            meshProperty = new SimpleObjectProperty<PolygonMesh>();
+            meshProperty.addListener(new ChangeListener<PolygonMesh>() {
+                @Override
+                public void changed(ObservableValue<? extends PolygonMesh> observable, PolygonMesh oldValue, PolygonMesh newValue) {
+                    if (oldValue != null) {
+                        oldValue.getPoints().removeListener(meshPointsListener);
+                        oldValue.getPoints().removeListener(meshTexCoordListener);
+                    }
+
+                    meshProperty.set(newValue);
+
+                    pointsDirty = pointsSizeDirty = texCoordsDirty = facesDirty = true;
+                    updateMesh();
+                    
+                    if (newValue != null) {
+                        newValue.getPoints().addListener(meshPointsListener);
+                        newValue.getTexCoords().addListener(meshTexCoordListener);
+                    }
+                }
+            });
         }
-    };
-    public PolygonMesh getMesh() { return mesh.get(); }
-    public void setMesh(PolygonMesh mesh) { 
-        this.mesh.set(mesh);
-        mesh.getPoints().addListener(new ArrayChangeListener<ObservableFloatArray>() {
-            @Override
-            public void onChanged(ObservableFloatArray t, boolean bln, int i, int i1) {
-                // TODO don't update the whole mesh, only update the parts affected by points
-                updateMesh();
-            }
-        });
+        return meshProperty;
     }
     
-    public ObjectProperty<PolygonMesh> meshProperty() { return mesh; }
-    
     /**
      * Defines the drawMode this {@code Shape3D}.
      *
@@ -62,8 +99,9 @@
         if (drawMode == null) {
             drawMode = new SimpleObjectProperty<DrawMode>(PolygonMeshView.this, "drawMode", DrawMode.FILL) {
                 @Override protected void invalidated() {
+                    meshView.setDrawMode(get());
+                    pointsDirty = pointsSizeDirty = texCoordsDirty = facesDirty = true;
                     updateMesh();
-                    meshView.setDrawMode(get());
                 }
             };
         }
@@ -106,42 +144,83 @@
      *
      * @defaultValue 0
      */
-    private SimpleIntegerProperty subdivisionLevel = new SimpleIntegerProperty(0) {
-        @Override protected void invalidated() {
-            updateSubdivision();
+    private SimpleIntegerProperty subdivisionLevelProperty;
+    public void setSubdivisionLevel(int subdivisionLevel) { subdivisionLevelProperty().set(subdivisionLevel); }
+    public int getSubdivisionLevel() { return subdivisionLevelProperty == null ? 0 : subdivisionLevelProperty.get(); }
+    public SimpleIntegerProperty subdivisionLevelProperty() { 
+        if (subdivisionLevelProperty == null) {
+            subdivisionLevelProperty = new SimpleIntegerProperty(getSubdivisionLevel()) {
+                @Override protected void invalidated() {
+                    // create SubdivisionMesh if subdivisionLevel is greater than 0
+                    if ((getSubdivisionLevel() > 0) && (subdivisionMesh == null)) {
+                        subdivisionMesh = new SubdivisionMesh(getMesh(), getSubdivisionLevel(), getBoundaryMode(), getMapBorderMode());
+                        subdivisionMesh.getOriginalMesh().getPoints().addListener(new ArrayChangeListener<ObservableFloatArray>() {
+                            @Override
+                            public void onChanged(ObservableFloatArray t, boolean bln, int i, int i1) {
+                                subdivisionMesh.update();
+                            }
+                        });
+                        setMesh(subdivisionMesh);
+                    }
+                    if (subdivisionMesh != null) {
+                        subdivisionMesh.setSubdivisionLevel(getSubdivisionLevel());
+                        subdivisionMesh.update();
+                    }
+                    pointsDirty = pointsSizeDirty = texCoordsDirty = facesDirty = true;
+                    updateMesh();
+                }
+            };
         }
-    };
-    public int getSubdivisionLevel() { return subdivisionLevel.get(); }
-    public SimpleIntegerProperty subdivisionLevelProperty() { return subdivisionLevel; }
-    public void setSubdivisionLevel(int subdivisionLevel) { this.subdivisionLevel.set(subdivisionLevel); }
+        return subdivisionLevelProperty;
+    }
     
     /**
      * Texture mapping boundary rule for Catmull Clark subdivision applied to the mesh
      *
      * @defaultValue BoundaryMode.CREASE_EDGES
      */
-    private SimpleObjectProperty<SubDivision.BoundaryMode> boundaryMode = new SimpleObjectProperty<SubDivision.BoundaryMode>(SubDivision.BoundaryMode.CREASE_EDGES) {
-        @Override protected void invalidated() {
-            updateSubdivision();
+    private SimpleObjectProperty<BoundaryMode> boundaryMode;
+    public void setBoundaryMode(BoundaryMode boundaryMode) { boundaryModeProperty().set(boundaryMode); }
+    public BoundaryMode getBoundaryMode() { return boundaryMode == null ? BoundaryMode.CREASE_EDGES : boundaryMode.get(); }
+    public SimpleObjectProperty<BoundaryMode> boundaryModeProperty() {
+        if (boundaryMode == null) {
+            boundaryMode = new SimpleObjectProperty<BoundaryMode>(getBoundaryMode()) {
+                @Override protected void invalidated() {
+                    if (subdivisionMesh != null) {
+                        subdivisionMesh.setBoundaryMode(getBoundaryMode());
+                        subdivisionMesh.update();
+                    }
+                    pointsDirty = true;
+                    updateMesh();
+                }
+            };
         }
-    };
-    public SubDivision.BoundaryMode getBoundaryMode() { return boundaryMode.get(); }
-    public SimpleObjectProperty<SubDivision.BoundaryMode> boundaryModeProperty() { return boundaryMode; }
-    public void setBoundaryMode(SubDivision.BoundaryMode boundaryMode) { this.boundaryMode.set(boundaryMode); }
+        return boundaryMode;
+    }
     
     /**
      * Texture mapping smoothness option for Catmull Clark subdivision applied to the mesh
      *
      * @defaultValue MapBorderMode.NOT_SMOOTH
      */
-    private SimpleObjectProperty<SubDivision.MapBorderMode> mapBorderMode = new SimpleObjectProperty<SubDivision.MapBorderMode>(SubDivision.MapBorderMode.NOT_SMOOTH) {
-        @Override protected void invalidated() {
-            updateSubdivision();
+    private SimpleObjectProperty<MapBorderMode> mapBorderMode;
+    public void setMapBorderMode(MapBorderMode mapBorderMode) { mapBorderModeProperty().set(mapBorderMode); }
+    public MapBorderMode getMapBorderMode() { return mapBorderMode == null ? MapBorderMode.NOT_SMOOTH : mapBorderMode.get(); }
+    public SimpleObjectProperty<MapBorderMode> mapBorderModeProperty() { 
+        if (mapBorderMode == null) {
+            mapBorderMode = new SimpleObjectProperty<MapBorderMode>(getMapBorderMode()) {
+                @Override protected void invalidated() {
+                    if (subdivisionMesh != null) {
+                        subdivisionMesh.setMapBorderMode(getMapBorderMode());
+                        subdivisionMesh.update();
+                    }
+                    texCoordsDirty = true;
+                    updateMesh();
+                }
+            };
         }
-    };
-    public SubDivision.MapBorderMode getMapBorderMode() { return mapBorderMode.get(); }
-    public SimpleObjectProperty<SubDivision.MapBorderMode> mapBorderModeProperty() { return mapBorderMode; }
-    public void setMapBorderMode(SubDivision.MapBorderMode mapBorderMode) { this.mapBorderMode.set(mapBorderMode); }
+        return mapBorderMode;
+    }
 
     // =========================================================================
     // CONSTRUCTORS
@@ -159,121 +238,143 @@
     // =========================================================================
     // PRIVATE METHODS
 
-    private void updateSubdivision() {
-        final int iterations = subdivisionLevel.get();
-        if (iterations == 0) {
-            subdividedMesh = null;
-        } else {
-            subdividedMesh = getMesh();
-            for (int i=0; i<iterations; i++) {
-                subdividedMesh = SubDivision.subdivide(subdividedMesh, boundaryMode.get(), mapBorderMode.get());
-            }
-        }
-        updateMesh();
-    }
-
     private void updateMesh() {
-        PolygonMesh pmesh = subdividedMesh != null ? subdividedMesh : getMesh();
-        if (pmesh == null || pmesh.faces == null || pmesh.texCoords == null) {
-            meshView.setMesh(null);
+        PolygonMesh pmesh = getMesh();
+        if (pmesh == null || pmesh.faces == null) {
+            triangleMesh = new TriangleMesh();
+            meshView.setMesh(triangleMesh);
             return;
         }
+        
         final boolean isWireframe = getDrawMode() == DrawMode.LINE;
         if (DEBUG) System.out.println("UPDATE MESH -- "+(isWireframe?"WIREFRAME":"SOLID"));
-        final TriangleMesh triangleMesh = new TriangleMesh();
-        final int numOfPoints = pmesh.getPoints().size()/TriangleMesh.NUM_COMPONENTS_PER_POINT;
+        final int numOfPoints = pmesh.getPoints().size()/NUM_COMPONENTS_PER_POINT;
         if (DEBUG) System.out.println("numOfPoints = " + numOfPoints);
         
         if(isWireframe) {
-            // create points and copy over points to the first part of the array
-            float [] pointsArray = new float [pmesh.getPoints().size() + pmesh.getNumEdgesInFaces()*3];
-            System.arraycopy(pmesh.getPoints().toArray(null), 0, pointsArray, 0, pmesh.getPoints().size());
-            int pointsInd = pmesh.getPoints().size();
+            // The current triangleMesh implementation gives buggy behavior when the size of faces are shrunken
+            // Create a new TriangleMesh as a work around
+            // [JIRA] (RT-31178)
+            if (texCoordsDirty || facesDirty || pointsSizeDirty) {
+                triangleMesh = new TriangleMesh();
+                pointsDirty = pointsSizeDirty = texCoordsDirty = facesDirty = true; // to fill in the new triangle mesh
+            }
+            if (facesDirty) {
+                facesDirty = false;
+                // create faces for each edge
+                int [] facesArray = new int [pmesh.getNumEdgesInFaces() * NUM_COMPONENTS_PER_FACE];
+                int facesInd = 0;
+                int pointsInd = pmesh.getPoints().size();
+                for(int[] face: pmesh.faces) {
+                    if (DEBUG) System.out.println("face.length = " + (face.length/2)+"  -- "+Arrays.toString(face));
+                    int lastPointIndex = face[face.length-2];
+                    if (DEBUG) System.out.println("    lastPointIndex = " + lastPointIndex);
+                    for (int p=0;p<face.length;p+=2) {
+                        int pointIndex = face[p];
+                        if (DEBUG) System.out.println("        connecting point["+lastPointIndex+"] to point[" + pointIndex+"]");
+                        facesArray[facesInd++] = lastPointIndex;
+                        facesArray[facesInd++] = 0;
+                        facesArray[facesInd++] = pointIndex;
+                        facesArray[facesInd++] = 0;
+                        facesArray[facesInd++] = pointsInd/NUM_COMPONENTS_PER_POINT;
+                        facesArray[facesInd++] = 0;
+                        if (DEBUG) System.out.println("            facesInd = " + facesInd);
+                        pointsInd += NUM_COMPONENTS_PER_POINT;
+                        lastPointIndex = pointIndex;
+                    }
+                }
+                triangleMesh.getFaces().setAll(facesArray);
+            }
+            if (texCoordsDirty) {
+                texCoordsDirty = false;
+                // set simple texCoords for wireframe
+                triangleMesh.getTexCoords().setAll(0,0);
+            }
+            if (pointsDirty) {
+                pointsDirty = false;
+                // create points and copy over points to the first part of the array
+                float [] pointsArray = new float [pmesh.getPoints().size() + pmesh.getNumEdgesInFaces()*3];
+                pmesh.getPoints().copyTo(0, pointsArray, 0, pmesh.getPoints().size());
 
-            // create faces and add point for each edge
-            final int numOfFacesBefore = pmesh.faces.length;
-            final int numOfFacesAfter = pmesh.getNumEdgesInFaces();
-            int [] facesArray = new int [numOfFacesAfter * TriangleMesh.NUM_COMPONENTS_PER_FACE];
-            int facesInd = 0;
-            
-            for(int[] face: pmesh.faces) {
-                if (DEBUG) System.out.println("face.length = " + (face.length/2)+"  -- "+Arrays.toString(face));
-                int lastPointIndex = face[face.length-2];
-                if (DEBUG) System.out.println("    lastPointIndex = " + lastPointIndex);
-                for (int p=0;p<face.length;p+=2) {
-                    int pointIndex = face[p];
-                    if (DEBUG) System.out.println("        connecting point["+lastPointIndex+"] to point[" + pointIndex+"]");
-                    facesArray[facesInd++] = lastPointIndex;
-                    facesArray[facesInd++] = 0;
-                    facesArray[facesInd++] = pointIndex;
-                    facesArray[facesInd++] = 0;
-                    facesArray[facesInd++] = pointsInd/TriangleMesh.NUM_COMPONENTS_PER_POINT;
-                    facesArray[facesInd++] = 0;
-                    final int numOfPoints2 = pointsInd/TriangleMesh.NUM_COMPONENTS_PER_POINT;
-                    if (DEBUG) System.out.println("            numOfPoints = " + numOfPoints2);
-                    // get start and end point
-                    final float x1 = pointsArray[lastPointIndex*TriangleMesh.NUM_COMPONENTS_PER_POINT];
-                    final float y1 = pointsArray[lastPointIndex*TriangleMesh.NUM_COMPONENTS_PER_POINT+1];
-                    final float z1 = pointsArray[lastPointIndex*TriangleMesh.NUM_COMPONENTS_PER_POINT+2];
-                    final float x2 = pointsArray[pointIndex*TriangleMesh.NUM_COMPONENTS_PER_POINT];
-                    final float y2 = pointsArray[pointIndex*TriangleMesh.NUM_COMPONENTS_PER_POINT+1];
-                    final float z2 = pointsArray[pointIndex*TriangleMesh.NUM_COMPONENTS_PER_POINT+2];
-                    final float distance = Math.abs(distanceBetweenPoints(x1,y1,z1,x2,y2,z2));
-                    final float offset = distance/1000;
-                    // add new point
-                    pointsArray[pointsInd++] = x2 + offset;
-                    pointsArray[pointsInd++] = y2 + offset;
-                    pointsArray[pointsInd++] = z2 + offset;
-                    if (DEBUG) System.out.println("            facesInd = " + facesInd);
-                    lastPointIndex = pointIndex;
+                // add point for each edge
+                int pointsInd = pmesh.getPoints().size();
+                for(int[] face: pmesh.faces) {
+                    int lastPointIndex = face[face.length-2];
+                    for (int p=0;p<face.length;p+=2) {
+                        int pointIndex = face[p];
+                        // get start and end point
+                        final float x1 = pointsArray[lastPointIndex*NUM_COMPONENTS_PER_POINT];
+                        final float y1 = pointsArray[lastPointIndex*NUM_COMPONENTS_PER_POINT+1];
+                        final float z1 = pointsArray[lastPointIndex*NUM_COMPONENTS_PER_POINT+2];
+                        final float x2 = pointsArray[pointIndex*NUM_COMPONENTS_PER_POINT];
+                        final float y2 = pointsArray[pointIndex*NUM_COMPONENTS_PER_POINT+1];
+                        final float z2 = pointsArray[pointIndex*NUM_COMPONENTS_PER_POINT+2];
+                        final float distance = Math.abs(distanceBetweenPoints(x1,y1,z1,x2,y2,z2));
+                        final float offset = distance/1000;
+                        // add new point
+                        pointsArray[pointsInd++] = x2 + offset;
+                        pointsArray[pointsInd++] = y2 + offset;
+                        pointsArray[pointsInd++] = z2 + offset;
+                        lastPointIndex = pointIndex;
+                    }
                 }
+                triangleMesh.getPoints().setAll(pointsArray);
             }
-            triangleMesh.getPoints().addAll(pointsArray);
-            triangleMesh.getFaces().addAll(facesArray);
-            if (DEBUG) System.out.println("numOfFacesBefore = " + numOfFacesBefore);
-            if (DEBUG) System.out.println("numOfFacesAfter = " + numOfFacesAfter);
-            // set simple texCoords for wireframe
-            triangleMesh.getTexCoords().addAll(0,0);
         } else {
-            // copy over points
-            triangleMesh.getPoints().addAll(pmesh.getPoints());
+            // The current triangleMesh implementation gives buggy behavior when the size of faces are shrunken
+            // Create a new TriangleMesh as a work around
+            // [JIRA] (RT-31178)
+            if (texCoordsDirty || facesDirty || pointsSizeDirty) {
+                triangleMesh = new TriangleMesh();
+                pointsDirty = pointsSizeDirty = texCoordsDirty = facesDirty = true; // to fill in the new triangle mesh
+            }
+            if (facesDirty) {
+                facesDirty = false;
+                // create faces and break into triangles
+                final int numOfFacesBefore = pmesh.faces.length;
+                final int numOfFacesAfter = pmesh.getNumEdgesInFaces() - 2*numOfFacesBefore;
+                int [] facesArray = new int [numOfFacesAfter * NUM_COMPONENTS_PER_FACE];
+                int facesInd = 0;
+                for(int[] face: pmesh.faces) {
+                    if (DEBUG) System.out.println("face.length = " + face.length+"  -- "+Arrays.toString(face));
+                    int firstPointIndex = face[0];
+                    int firstTexIndex = face[1];
+                    int lastPointIndex = face[2];
+                    int lastTexIndex = face[3];
+                    for (int p=4;p<face.length;p+=2) {
+                        int pointIndex = face[p];
+                        int texIndex = face[p+1];
+                        facesArray[facesInd++] = firstPointIndex;
+                        facesArray[facesInd++] = firstTexIndex;
+                        facesArray[facesInd++] = lastPointIndex;
+                        facesArray[facesInd++] = lastTexIndex;
+                        facesArray[facesInd++] = pointIndex;
+                        facesArray[facesInd++] = texIndex;
+                        lastPointIndex = pointIndex;
+                        lastTexIndex = texIndex;
+                    }
+                }
+                triangleMesh.getFaces().setAll(facesArray);
+            }
+            if (texCoordsDirty) {
+                texCoordsDirty = false;
+                triangleMesh.getTexCoords().setAll(pmesh.getTexCoords());
+            }
+            if (pointsDirty) {
+                pointsDirty = false;
+                triangleMesh.getPoints().setAll(pmesh.getPoints());
+            }
+        }
         
-            // create faces and break into triangles
-            final int numOfFacesBefore = pmesh.faces.length;
-            final int numOfFacesAfter = pmesh.getNumEdgesInFaces() - 2*numOfFacesBefore;
-            int [] facesArray = new int [numOfFacesAfter * TriangleMesh.NUM_COMPONENTS_PER_FACE];
-            int facesInd = 0;
-            
-            for(int[] face: pmesh.faces) {
-                if (DEBUG) System.out.println("face.length = " + face.length+"  -- "+Arrays.toString(face));
-                int firstPointIndex = face[0];
-                int firstTexIndex = face[1];
-                int lastPointIndex = face[2];
-                int lastTexIndex = face[3];
-                for (int p=4;p<face.length;p+=2) {
-                    int pointIndex = face[p];
-                    int texIndex = face[p+1];
-                    facesArray[facesInd++] = firstPointIndex;
-                    facesArray[facesInd++] = firstTexIndex;
-                    facesArray[facesInd++] = lastPointIndex;
-                    facesArray[facesInd++] = lastTexIndex;
-                    facesArray[facesInd++] = pointIndex;
-                    facesArray[facesInd++] = texIndex;
-                    lastPointIndex = pointIndex;
-                    lastTexIndex = texIndex;
-                }
-            }
-            triangleMesh.getFaces().addAll(facesArray);
-            if (DEBUG) System.out.println("numOfFacesBefore = " + numOfFacesBefore);
-            if (DEBUG) System.out.println("numOfFacesAfter = " + numOfFacesAfter);
-            // copy over texCoords
-            triangleMesh.getTexCoords().addAll(pmesh.texCoords);
+        if (DEBUG) System.out.println("CREATING TRIANGLE MESH");
+        if (DEBUG) System.out.println("    points    = "+Arrays.toString(((TriangleMesh) meshView.getMesh()).getPoints().toArray(null)));
+        if (DEBUG) System.out.println("    texCoords = "+Arrays.toString(((TriangleMesh) meshView.getMesh()).getTexCoords().toArray(null)));
+        if (DEBUG) System.out.println("    faces     = "+Arrays.toString(((TriangleMesh) meshView.getMesh()).getFaces().toArray(null)));
+    
+        if (meshView.getMesh() != triangleMesh) {
+            meshView.setMesh(triangleMesh);
         }
-        if (DEBUG) System.out.println("CREATING TRIANGLE MESH");
-        if (DEBUG) System.out.println("    points    = "+Arrays.toString(triangleMesh.getPoints().toArray(null)));
-        if (DEBUG) System.out.println("    texCoords = "+Arrays.toString(triangleMesh.getTexCoords().toArray(null)));
-        if (DEBUG) System.out.println("    faces     = "+Arrays.toString(triangleMesh.getFaces().toArray(null)));
-        meshView.setMesh(triangleMesh);
+        pointsDirty = pointsSizeDirty = texCoordsDirty = facesDirty = false;
     }
 
     private float distanceBetweenPoints(float x1, float y1, float z1, float x2, float y2, float z2) {
--- a/apps/experiments/3DViewer/src/main/java/com/javafx/experiments/shape3d/SkinningMesh.java	Mon Jul 01 12:20:05 2013 -0700
+++ b/apps/experiments/3DViewer/src/main/java/com/javafx/experiments/shape3d/SkinningMesh.java	Tue Jul 02 23:11:35 2013 -0700
@@ -26,7 +26,7 @@
 
     public SkinningMesh(PolygonMesh mesh, Transform meshTransform, float[][] weights, Affine[] bindTransforms, List<Joint> joints) {
         this.getPoints().addAll(mesh.getPoints());
-        this.texCoords = mesh.texCoords;
+        this.getTexCoords().addAll(mesh.getTexCoords());
         this.faces = mesh.faces;
         
         this.weights = weights;
--- a/apps/experiments/3DViewer/src/main/java/com/javafx/experiments/shape3d/SubDivision.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,419 +0,0 @@
-package com.javafx.experiments.shape3d;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import javafx.geometry.Point2D;
-import javafx.geometry.Point3D;
-
-
-/**
- * 
- * Catmull Clark subdivision surface
- */
-public class SubDivision {
-    
-    private PolygonMesh oldMesh;
-    private Map<Edge, EdgeInfo> edgeInfos;
-    private FaceInfo[] faceInfos;
-    private PointInfo[] pointInfos;
-    private float[] points;
-    private float[] texCoords;
-    private int[] reindex;
-    private int newPointIndex;
-    private int newTexCoordIndex;
-    private BoundaryMode boundaryMode;
-    private MapBorderMode mapBorderMode;
-
-    /** 
-     * Describes whether the edges and points at the boundary are treated as creases
-     */
-    public enum BoundaryMode {
-        /**
-         * only edges at the boundary are treated as creases
-         */
-        CREASE_EDGES, 
-        /**
-         * edges and points at the boundary are treated as creases
-         */
-        CREASE_ALL
-    }
-    
-    /**
-     * describes how the new texture coordinate for the control point is defined
-     */
-    public enum MapBorderMode {
-        /**
-         * keeps the same uvs for all control points
-         */
-        NOT_SMOOTH, 
-        /**
-         * smooths uvs of points at corners
-         */
-        SMOOTH_INTERNAL, 
-        /**
-         * smooths uvs of points at boundaries (and creases [in the future when creases are defined])
-         */
-        SMOOTH_ALL
-    }
-    
-    public SubDivision(PolygonMesh oldMesh, BoundaryMode boundaryMode, MapBorderMode mapBorderMode) {
-        this.oldMesh = oldMesh;
-        this.boundaryMode = boundaryMode;
-        this.mapBorderMode = mapBorderMode;
-    }
-    
-    public PolygonMesh subdivide() {
-        collectInfo();
-        calcEdgePoints();
-        
-        points = new float[oldMesh.getPoints().size() + faceInfos.length * 3 + edgeInfos.size() * 3];
-        texCoords = new float[oldMesh.getNumEdgesInFaces() * 4 * 2];
-        int[][] faces = new int[oldMesh.getNumEdgesInFaces()][8];
-        newPointIndex = 0;
-        newTexCoordIndex = 0;
-        reindex = new int[oldMesh.getPoints().size()]; // indexes incremented by 1, 0 reserved for empty
-        
-        int newFacesInd = 0;
-        for (int f = 0; f < oldMesh.faces.length; f++) {
-            FaceInfo faceInfo = faceInfos[f];
-            int[] oldFaces = oldMesh.faces[f];
-            for (int p = 0; p < oldFaces.length; p += 2) {
-                faces[newFacesInd][0] = getPointNewIndex(oldFaces[p]);
-                faces[newFacesInd][1] = getTexCoordNewIndex(faceInfo, oldFaces[p], oldFaces[p+1]);
-                faces[newFacesInd][2] = getPointNewIndex(faceInfo, (p / 2 + 1) % faceInfo.edges.length);
-                faces[newFacesInd][3] = getTexCoordNewIndex(faceInfo, (p / 2 + 1) % faceInfo.edges.length);
-                faces[newFacesInd][4] = getPointNewIndex(faceInfo);
-                faces[newFacesInd][5] = getTexCoordNewIndex(faceInfo);
-                faces[newFacesInd][6] = getPointNewIndex(faceInfo, p / 2);
-                faces[newFacesInd][7] = getTexCoordNewIndex(faceInfo, p / 2);
-                newFacesInd++;
-            }
-        }
-        PolygonMesh newMesh = new PolygonMesh(points, texCoords, faces);
-        return newMesh;
-    }
-    
-    public static PolygonMesh subdivide(PolygonMesh oldMesh, BoundaryMode boundaryMode, MapBorderMode mapBorderMode) {
-        SubDivision subDivision = new SubDivision(oldMesh, boundaryMode, mapBorderMode);
-        return subDivision.subdivide();
-    }
-
-    private void addEdge(Edge edge, FaceInfo faceInfo, Point3D midPoint) {
-        EdgeInfo edgeInfo = edgeInfos.get(edge);
-        if (edgeInfo == null) {
-            edgeInfo = new EdgeInfo();
-            edgeInfo.midPoint = midPoint;
-            edgeInfos.put(edge, edgeInfo);
-        }
-        edgeInfo.faces.add(faceInfo);
-    }
-
-    private void addPoint(int point, FaceInfo faceInfo, Edge edge) {
-        PointInfo pointInfo = pointInfos[point];
-        if (pointInfo == null) {
-            pointInfo = new PointInfo();
-            pointInfos[point] = pointInfo;
-        }
-        pointInfo.edges.add(edge);
-        pointInfo.faces.add(faceInfo);
-    }
-    
-    private void addPoint(int point, Edge edge) {
-        PointInfo pointInfo = pointInfos[point];
-        if (pointInfo == null) {
-            pointInfo = new PointInfo();
-            pointInfos[point] = pointInfo;
-        }
-        pointInfo.edges.add(edge);
-    }
-
-    private void collectInfo() {
-        edgeInfos = new HashMap<>(oldMesh.faces.length * 2);
-        faceInfos = new FaceInfo[oldMesh.faces.length];
-        pointInfos = new PointInfo[oldMesh.getPoints().size() / 3];
-        
-        for (int f = 0; f < oldMesh.faces.length; f++) {
-            int[] face = oldMesh.faces[f];
-            int n = face.length / 2;
-            FaceInfo faceInfo = new FaceInfo(n);
-            faceInfos[f] = faceInfo;
-            if (n < 3) {
-                continue;
-            }
-            int from = face[(n-1) * 2];
-            int texFrom = face[(n-1) * 2 + 1];
-            double fx, fy, fz, fu, fv;
-            double tx, ty, tz, tu, tv;
-            double x = 0, y = 0, z = 0, u = 0, v = 0;
-            fx = oldMesh.getPoints().get(from * 3);
-            fy = oldMesh.getPoints().get(from * 3 + 1);
-            fz = oldMesh.getPoints().get(from * 3 + 2);
-            fu = oldMesh.texCoords[texFrom * 2];
-            fv = oldMesh.texCoords[texFrom * 2 + 1];
-            for (int i = 0; i < n; i++) {
-                int to = face[i * 2];
-                int texTo = face[i * 2 + 1];
-                tx = oldMesh.getPoints().get(to * 3);
-                ty = oldMesh.getPoints().get(to * 3 + 1);
-                tz = oldMesh.getPoints().get(to * 3 + 2);
-                tu = oldMesh.texCoords[texTo * 2];
-                tv = oldMesh.texCoords[texTo * 2 + 1];
-                Point3D midPoint = new Point3D((fx + tx) / 2, (fy + ty) / 2, (fz + tz) / 2);
-                Point2D midTexCoord = new Point2D((fu + tu) / 2, (fv + tv) / 2);
-                Edge edge = new Edge(from, to);
-                faceInfo.edges[i] = edge;
-                faceInfo.edgeTexCoords[i] = midTexCoord;
-                addEdge(edge, faceInfo, midPoint);
-                addPoint(to, faceInfo, edge);
-                addPoint(from, edge);
-                fx = tx; fy = ty; fz = tz; fu = tu; fv = tv;
-                x += tx / n; y += ty / n; z += tz / n; u += tu / n; v += tv / n;
-                from = to;
-                texFrom = texTo;
-            }
-            faceInfo.point = new Point3D(x, y, z);
-            faceInfo.texCoord = new Point2D(u, v);
-        }
-    }
-
-    private void calcEdgePoints() {
-        for (EdgeInfo edgeInfo : edgeInfos.values()) {
-            if (edgeInfo.isBoundary()) {
-                edgeInfo.edgePoint = edgeInfo.midPoint;
-            } else {
-                int n = edgeInfo.faces.size() + 2;
-                double x = edgeInfo.midPoint.getX() * 2 / n;
-                double y = edgeInfo.midPoint.getY() * 2 / n;
-                double z = edgeInfo.midPoint.getZ() * 2 / n;
-                for (FaceInfo faceInfo : edgeInfo.faces) {
-                    Point3D facePoint = faceInfo.point;
-                    x += facePoint.getX() / n;
-                    y += facePoint.getY() / n;
-                    z += facePoint.getZ() / n;
-                }
-                edgeInfo.edgePoint = new Point3D(x, y, z);
-            }
-        }
-    }
-
-    private void calcControlPoint(int srcPointIndex, int destPointIndex) {
-        PointInfo pointInfo = pointInfos[srcPointIndex];
-        double x, y, z;
-        if (pointInfo.isBoundary()) {
-            if ((boundaryMode == BoundaryMode.CREASE_EDGES) || pointInfo.hasInternalEdge()) {
-                x = oldMesh.getPoints().get(srcPointIndex * 3) / 2;
-                y = oldMesh.getPoints().get(srcPointIndex * 3 + 1) / 2;
-                z = oldMesh.getPoints().get(srcPointIndex * 3 + 2) / 2;
-                for (Edge edge : pointInfo.edges) {
-                    EdgeInfo edgeInfo = edgeInfos.get(edge);
-                    if (edgeInfo.isBoundary()) {
-                        x += edgeInfo.edgePoint.getX() / 4;
-                        y += edgeInfo.edgePoint.getY() / 4;
-                        z += edgeInfo.edgePoint.getZ() / 4;
-                    }
-                }
-            } else {
-                x = oldMesh.getPoints().get(srcPointIndex * 3);
-                y = oldMesh.getPoints().get(srcPointIndex * 3 + 1);
-                z = oldMesh.getPoints().get(srcPointIndex * 3 + 2);
-            }
-        } else {
-            int n = pointInfo.faces.size();
-            x = oldMesh.getPoints().get(srcPointIndex * 3) * (n - 3.0) / n;
-            y = oldMesh.getPoints().get(srcPointIndex * 3 + 1) * (n - 3.0) / n;
-            z = oldMesh.getPoints().get(srcPointIndex * 3 + 2) * (n - 3.0) / n;
-            for (FaceInfo faceInfo : pointInfo.faces) {
-                Point3D point = faceInfo.point;
-                x += point.getX() / n / n;
-                y += point.getY() / n / n;
-                z += point.getZ() / n / n;
-            }
-            for (Edge edge : pointInfo.edges) {
-                EdgeInfo edgeInfo = edgeInfos.get(edge);
-                x += edgeInfo.midPoint.getX() * 2 / n / n;
-                y += edgeInfo.midPoint.getY() * 2 / n / n;
-                z += edgeInfo.midPoint.getZ() * 2 / n / n;
-            }
-        }
-        points[destPointIndex * 3] = (float) x;
-        points[destPointIndex * 3 + 1] = (float) y;
-        points[destPointIndex * 3 + 2] = (float) z;
-    }
-
-    private void calcControlTexCoord(FaceInfo faceInfo, int srcPointIndex, int srcTexCoordIndex, int destTexCoordIndex){
-        PointInfo pointInfo = pointInfos[srcPointIndex];
-        if ((mapBorderMode == MapBorderMode.SMOOTH_ALL && pointInfo.isBoundary()) || 
-                (mapBorderMode == MapBorderMode.SMOOTH_INTERNAL && !pointInfo.hasInternalEdge())) {
-            double u = oldMesh.texCoords[srcTexCoordIndex * 2] / 2;
-            double v = oldMesh.texCoords[srcTexCoordIndex * 2 + 1] / 2;
-            for (int i = 0; i < faceInfo.edges.length; i++) {
-                if ((faceInfo.edges[i].to == srcPointIndex) || (faceInfo.edges[i].from == srcPointIndex)) {
-                    u += faceInfo.edgeTexCoords[i].getX() / 4;
-                    v += faceInfo.edgeTexCoords[i].getY() / 4;
-                }
-            }
-            texCoords[destTexCoordIndex * 2] = (float) u;
-            texCoords[destTexCoordIndex * 2 + 1] = (float) v;
-        } else {
-            texCoords[destTexCoordIndex * 2] = oldMesh.texCoords[srcTexCoordIndex * 2];
-            texCoords[destTexCoordIndex * 2 + 1] = oldMesh.texCoords[srcTexCoordIndex * 2 + 1];
-        }
-    }
-
-    private int getPointNewIndex(int srcPointIndex) {
-        int destPointIndex = reindex[srcPointIndex] - 1;
-        if (destPointIndex == -1) {
-            destPointIndex = newPointIndex;
-            reindex[srcPointIndex] = destPointIndex + 1;
-            newPointIndex++;
-            calcControlPoint(srcPointIndex, destPointIndex);
-        }
-        return destPointIndex;
-    }
-    
-    private int getPointNewIndex(FaceInfo faceInfo, int edgeInd) {
-        Edge edge = faceInfo.edges[edgeInd];
-        EdgeInfo edgeInfo = edgeInfos.get(edge);
-        int destPointIndex = edgeInfo.newPointIndex - 1;
-        if (destPointIndex == -1) {
-            destPointIndex = newPointIndex;
-            edgeInfo.newPointIndex = destPointIndex + 1;
-            newPointIndex++;
-            points[destPointIndex * 3] = (float) edgeInfo.edgePoint.getX();
-            points[destPointIndex * 3 + 1] = (float) edgeInfo.edgePoint.getY();
-            points[destPointIndex * 3 + 2] = (float) edgeInfo.edgePoint.getZ();
-        }
-        return destPointIndex;
-    }
-
-    private int getPointNewIndex(FaceInfo faceInfo) {
-        int destPointIndex = faceInfo.newPointIndex - 1;
-        if (destPointIndex == -1) {
-            destPointIndex = newPointIndex;
-            faceInfo.newPointIndex = destPointIndex + 1;
-            newPointIndex++;
-            points[destPointIndex * 3] = (float) faceInfo.point.getX();
-            points[destPointIndex * 3 + 1] = (float) faceInfo.point.getY();
-            points[destPointIndex * 3 + 2] = (float) faceInfo.point.getZ();
-        }
-        return destPointIndex;
-    }
-
-    private int getTexCoordNewIndex(FaceInfo faceInfo, int srcPointIndex, int srcTexCoordIndex) {
-        int destTexCoordIndex = newTexCoordIndex;
-        newTexCoordIndex++;
-        calcControlTexCoord(faceInfo, srcPointIndex, srcTexCoordIndex, destTexCoordIndex);
-        return destTexCoordIndex;
-    }
-    
-    private int getTexCoordNewIndex(FaceInfo faceInfo, int edgeInd) {
-        int destTexCoordIndex = newTexCoordIndex;
-        newTexCoordIndex++;
-        texCoords[destTexCoordIndex * 2] = (float) faceInfo.edgeTexCoords[edgeInd].getX();
-        texCoords[destTexCoordIndex * 2 + 1] = (float) faceInfo.edgeTexCoords[edgeInd].getY();
-        return destTexCoordIndex;
-    }
-    
-    private int getTexCoordNewIndex(FaceInfo faceInfo) {
-        int destTexCoordIndex = newTexCoordIndex;
-        newTexCoordIndex++;
-        texCoords[destTexCoordIndex * 2] = (float) faceInfo.texCoord.getX();
-        texCoords[destTexCoordIndex * 2 + 1] = (float) faceInfo.texCoord.getY();
-        return destTexCoordIndex;
-    }
-
-    private static class Edge {
-        int from, to;
-
-        public Edge(int from, int to) {
-            this.from = Math.min(from, to);
-            this.to = Math.max(from, to);
-        }
-
-        @Override
-        public int hashCode() {
-            int hash = 7;
-            hash = 41 * hash + this.from;
-            hash = 41 * hash + this.to;
-            return hash;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (obj == null) {
-                return false;
-            }
-            if (getClass() != obj.getClass()) {
-                return false;
-            }
-            final Edge other = (Edge) obj;
-            if (this.from != other.from) {
-                return false;
-            }
-            if (this.to != other.to) {
-                return false;
-            }
-            return true;
-        }
-    }
-    
-    private static class EdgeInfo {
-        Point3D midPoint;
-        Point3D edgePoint;
-        int newPointIndex;
-        List<FaceInfo> faces = new ArrayList<>(2);
-        
-        /**
-         * an edge is in the boundary if it has only one adjacent face
-         */
-        public boolean isBoundary() {
-            return faces.size() == 1;
-        }
-    }
-    
-    private class PointInfo {
-        List<FaceInfo> faces = new ArrayList<>(4);
-        Set<Edge> edges = new HashSet<>(4);
-        
-        /**
-         * A point is in the boundary if any of its adjacent edges is in the boundary
-         */
-        public boolean isBoundary() {
-            for (Edge edge : edges) {
-                EdgeInfo edgeInfo = edgeInfos.get(edge);
-                if (edgeInfo.isBoundary())
-                    return true;
-            }
-            return false;
-        }
-        
-        /**
-         * A point is internal if at least one of its adjacent edges is not in the boundary
-         */
-        public boolean hasInternalEdge() {
-            for (Edge edge : edges) {
-                EdgeInfo edgeInfo = edgeInfos.get(edge);
-                if (!edgeInfo.isBoundary())
-                    return true;
-            }
-            return false;
-        }
-    }
-    
-    private static class FaceInfo {
-        Point3D point;
-        Point2D texCoord;
-        int newPointIndex;
-        Edge[] edges;
-        Point2D[] edgeTexCoords;
-
-        public FaceInfo(int n) {
-            edges = new Edge[n];
-            edgeTexCoords = new Point2D[n];
-        }
-    }
-}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/experiments/3DViewer/src/main/java/com/javafx/experiments/shape3d/SubdivisionMesh.java	Tue Jul 02 23:11:35 2013 -0700
@@ -0,0 +1,172 @@
+package com.javafx.experiments.shape3d;
+
+import com.javafx.experiments.shape3d.symbolic.SymbolicPolygonMesh;
+import com.javafx.experiments.shape3d.symbolic.SymbolicSubdivisionBuilder;
+import java.util.ArrayList;
+import java.util.List;
+import javafx.collections.ArrayChangeListener;
+import javafx.collections.ObservableFloatArray;
+
+/**
+ * Catmull Clark subdivision surface polygon mesh
+ */
+public class SubdivisionMesh extends PolygonMesh {
+    private final PolygonMesh originalMesh;
+    private int subdivisionLevel;
+    private BoundaryMode boundaryMode;
+    private MapBorderMode mapBorderMode;
+    private final List<SymbolicPolygonMesh> symbolicMeshes;
+    
+    private boolean pointValuesDirty;
+    private boolean meshDirty;
+    private boolean subdivisionLevelDirty;
+    
+    /** 
+     * Describes whether the edges and points at the boundary are treated as creases
+     */
+    public enum BoundaryMode {
+        /**
+         * Only edges at the boundary are treated as creases
+         */
+        CREASE_EDGES, 
+        /**
+         * Edges and points at the boundary are treated as creases
+         */
+        CREASE_ALL
+    }
+    
+    /**
+     * Describes how the new texture coordinate for the control point is defined
+     */
+    public enum MapBorderMode {
+        /**
+         * Jeeps the same uvs for all control points
+         */
+        NOT_SMOOTH, 
+        /**
+         * Smooths uvs of points at corners
+         */
+        SMOOTH_INTERNAL, 
+        /**
+         * Smooths uvs of points at boundaries and original control points (and creases [in the future when creases are defined])
+         */
+        SMOOTH_ALL
+    }
+    
+    public SubdivisionMesh(PolygonMesh originalMesh, int subdivisionLevel, BoundaryMode boundaryMode, MapBorderMode mapBorderMode) {
+        this.originalMesh = originalMesh;
+        setSubdivisionLevelForced(subdivisionLevel);
+        setBoundaryModeForced(boundaryMode);
+        setMapBorderModeForced(mapBorderMode);
+        
+        symbolicMeshes = new ArrayList<>(4); // the polymesh is usually subdivided up to 3 times
+
+        originalMesh.getPoints().addListener(new ArrayChangeListener<ObservableFloatArray>() {
+            @Override
+            public void onChanged(ObservableFloatArray observableArray, boolean sizeChanged, int from, int to) {
+                if (sizeChanged) {
+                    meshDirty = true;
+                } else {
+                    pointValuesDirty = true;
+                }
+            }
+        });
+        originalMesh.getTexCoords().addListener(new ArrayChangeListener<ObservableFloatArray>() {
+            @Override
+            public void onChanged(ObservableFloatArray observableArray, boolean sizeChanged, int from, int to) {
+                meshDirty = true;
+            }
+        });
+    }
+    
+    /**
+     * Updates the variables of the underlying polygon mesh.
+     * It only updates the fields that need to be updated.
+     */
+    public void update() {
+        if (meshDirty) {
+            symbolicMeshes.clear();
+            symbolicMeshes.add(new SymbolicPolygonMesh(originalMesh));
+            pointValuesDirty = true;
+            subdivisionLevelDirty = true;
+        }
+ 
+        while (subdivisionLevel >= symbolicMeshes.size()) {
+            symbolicMeshes.add(SymbolicSubdivisionBuilder.subdivide(symbolicMeshes.get(symbolicMeshes.size()-1), boundaryMode, mapBorderMode));
+            pointValuesDirty = true;
+            subdivisionLevelDirty = true;
+        }
+        
+        if (pointValuesDirty) {
+            for (int i = 0; i <= subdivisionLevel; i++) {
+                SymbolicPolygonMesh symbolicMesh = symbolicMeshes.get(i);
+                symbolicMesh.points.update();
+            }
+        }
+        
+        if (pointValuesDirty || subdivisionLevelDirty) {
+            float[] points = symbolicMeshes.get(subdivisionLevel).points.data;
+            getPoints().setAll(points, 0, points.length);
+        }
+        
+        if (subdivisionLevelDirty) {
+            faces = symbolicMeshes.get(subdivisionLevel).faces;
+            numEdgesInFaces = -1;
+            float[] texCoords = symbolicMeshes.get(subdivisionLevel).texCoords;
+            getTexCoords().setAll(texCoords, 0, texCoords.length);
+        }
+        
+        meshDirty = false;
+        pointValuesDirty = false;
+        subdivisionLevelDirty = false;
+    }
+    
+    private void setSubdivisionLevelForced(int subdivisionLevel) {
+        this.subdivisionLevel = subdivisionLevel;
+        subdivisionLevelDirty = true;
+    }
+    
+    private void setBoundaryModeForced(SubdivisionMesh.BoundaryMode boundaryMode) {
+        this.boundaryMode = boundaryMode;
+        meshDirty = true;
+    }
+
+    private void setMapBorderModeForced(SubdivisionMesh.MapBorderMode mapBorderMode) {
+        this.mapBorderMode = mapBorderMode;
+        meshDirty = true;
+    }
+    
+    public PolygonMesh getOriginalMesh() {
+        return originalMesh;
+    }
+    
+    public int getSubdivisionLevel() {
+        return subdivisionLevel;
+    }
+
+    public void setSubdivisionLevel(int subdivisionLevel) {
+        if (subdivisionLevel != this.subdivisionLevel) {
+            setSubdivisionLevelForced(subdivisionLevel);
+        }
+    }
+    
+    public SubdivisionMesh.BoundaryMode getBoundaryMode() {
+        return boundaryMode;
+    }
+
+    public void setBoundaryMode(SubdivisionMesh.BoundaryMode boundaryMode) {
+        if (boundaryMode != this.boundaryMode) {
+            setBoundaryModeForced(boundaryMode);
+        }
+    }
+
+    public SubdivisionMesh.MapBorderMode getMapBorderMode() {
+        return mapBorderMode;
+    }
+
+    public void setMapBorderMode(SubdivisionMesh.MapBorderMode mapBorderMode) {
+        if (mapBorderMode != this.mapBorderMode) {
+            setMapBorderModeForced(mapBorderMode);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/experiments/3DViewer/src/main/java/com/javafx/experiments/shape3d/symbolic/OriginalPointArray.java	Tue Jul 02 23:11:35 2013 -0700
@@ -0,0 +1,17 @@
+package com.javafx.experiments.shape3d.symbolic;
+
+import com.javafx.experiments.shape3d.PolygonMesh;
+
+public class OriginalPointArray extends SymbolicPointArray {
+    PolygonMesh mesh;
+
+    public OriginalPointArray(PolygonMesh mesh) {
+        super(new float[mesh.getPoints().size()]);
+        this.mesh = mesh;
+    }
+
+    @Override
+    public void update() {
+        mesh.getPoints().copyTo(0, data, 0, data.length);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/experiments/3DViewer/src/main/java/com/javafx/experiments/shape3d/symbolic/SubdividedPointArray.java	Tue Jul 02 23:11:35 2013 -0700
@@ -0,0 +1,137 @@
+package com.javafx.experiments.shape3d.symbolic;
+
+import java.util.Arrays;
+import com.javafx.experiments.shape3d.SubdivisionMesh;
+import javafx.scene.shape.TriangleMesh;
+
+public class SubdividedPointArray extends SymbolicPointArray {
+    private final float[] controlPoints; // points of the previous subdivision level
+    private final int[][] controlInds; // indices corresponding to controlPoints
+    private final float[][] controlFactors; // factors corresponding to controlPoints
+    private final int[][] inds;
+    private final float[][] factors;
+    
+    private final SubdivisionMesh.BoundaryMode boundaryMode;
+    
+    private int currPoint = 0;
+    
+    public SubdividedPointArray(SymbolicPointArray controlPointArray, int numPoints, SubdivisionMesh.BoundaryMode boundaryMode) {
+        super(new float[TriangleMesh.NUM_COMPONENTS_PER_POINT*numPoints]);
+        
+        this.controlPoints = controlPointArray.data;
+        this.controlInds = new int[numPoints][];
+        this.controlFactors = new float[numPoints][];
+        this.inds = new int[numPoints][];
+        this.factors = new float[numPoints][];
+        
+        this.boundaryMode = boundaryMode;
+    }
+    
+    
+    public int addFacePoint(int[] vertices) {
+        controlInds[currPoint] = vertices;
+        controlFactors[currPoint] = new float[vertices.length];
+        Arrays.fill(controlFactors[currPoint], 1.0f/vertices.length);
+        
+        inds[currPoint] = new int[0];
+        factors[currPoint] = new float[0];
+        
+        return currPoint++;
+    }
+    
+    public int addEdgePoint(int[] facePoints, int fromPoint, int toPoint, boolean isBoundary) {
+        if (isBoundary) {
+            controlInds[currPoint] = new int[] {fromPoint, toPoint};
+            controlFactors[currPoint] = new float[] {0.5f, 0.5f};
+
+            inds[currPoint] = new int[0];
+            factors[currPoint] = new float[0];
+        } else {
+            int n = facePoints.length + 2;
+            controlInds[currPoint] = new int[] {fromPoint, toPoint};
+            controlFactors[currPoint] = new float[] {1.0f/n, 1.0f/n};
+            
+            inds[currPoint] = facePoints;
+            factors[currPoint] = new float[facePoints.length];
+            Arrays.fill(factors[currPoint], 1.0f/n);
+        }
+        return currPoint++;
+    }
+
+    public int addControlPoint(int[] facePoints, int[] edgePoints, int[] fromEdgePoints, int[] toEdgePoints, boolean[] isEdgeBoundary, int origPoint, boolean isBoundary, boolean hasInternalEdge) {
+        if (isBoundary) {
+            if ((boundaryMode == SubdivisionMesh.BoundaryMode.CREASE_EDGES) || hasInternalEdge) {
+                controlInds[currPoint] = new int[] {origPoint};
+                controlFactors[currPoint] = new float[] {0.5f};
+                
+                int numBoundaryEdges = 0;
+                for (int i = 0; i < edgePoints.length; i++) {
+                    if (isEdgeBoundary[i]) {
+                        numBoundaryEdges++;
+                    }
+                }
+                inds[currPoint] = new int[numBoundaryEdges];
+                factors[currPoint] = new float[numBoundaryEdges];
+                int boundaryEdgeInd = 0;
+                for (int i = 0; i < edgePoints.length; i++) {
+                    if (isEdgeBoundary[i]) {
+                        inds[currPoint][boundaryEdgeInd] = edgePoints[i];
+                        factors[currPoint][boundaryEdgeInd] = 0.25f;
+                        boundaryEdgeInd++;
+                    }
+                }
+            } else {
+                controlInds[currPoint] = new int[] {origPoint};
+                controlFactors[currPoint] = new float[] {1.0f};
+
+                inds[currPoint] = new int[0];
+                factors[currPoint] = new float[0];
+            }
+        } else {
+            int n = facePoints.length;
+            
+            controlInds[currPoint] = new int[1 + edgePoints.length*2];
+            controlFactors[currPoint] = new float[1 + edgePoints.length*2];
+            controlInds[currPoint][0] = origPoint;
+            controlFactors[currPoint][0] = (n - 3.0f) / n;
+            for (int i = 0; i < edgePoints.length; i++) {
+                controlInds[currPoint][1+2*i] = fromEdgePoints[i];
+                controlFactors[currPoint][1+2*i] = 1.0f/(n * n);
+                controlInds[currPoint][1+2*i+1] = toEdgePoints[i];
+                controlFactors[currPoint][1+2*i+1] = 1.0f/(n * n);
+            }
+            
+            inds[currPoint] = facePoints;
+            factors[currPoint] = new float[facePoints.length];
+            Arrays.fill(factors[currPoint], 1.0f/(n * n));
+        }
+        return currPoint++;
+    }
+    
+    @Override
+    public void update() {
+        int ci;
+        float f;
+        float x, y, z;
+        for (int i = 0; i < numPoints; i++) {
+            x = y = z = 0.0f;
+            for (int j = 0; j < controlInds[i].length; j++) {
+                ci = 3 * controlInds[i][j];
+                f = controlFactors[i][j];
+                x += controlPoints[ci] * f;
+                y += controlPoints[ci + 1] * f;
+                z += controlPoints[ci + 2] * f;
+            }
+            for (int j = 0; j < inds[i].length; j++) {
+                ci = 3 * inds[i][j];
+                f = factors[i][j];
+                x += data[ci] * f;
+                y += data[ci + 1] * f;
+                z += data[ci + 2] * f;
+            }
+            data[3*i] = x;
+            data[3*i+1] = y;
+            data[3*i+2] = z;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/experiments/3DViewer/src/main/java/com/javafx/experiments/shape3d/symbolic/SymbolicPointArray.java	Tue Jul 02 23:11:35 2013 -0700
@@ -0,0 +1,23 @@
+package com.javafx.experiments.shape3d.symbolic;
+
+import javafx.scene.shape.TriangleMesh;
+
+/**
+ * A 3D geometric point array that has the x, y, z coordinates of every point
+ * as a function of other variables.
+ */
+public abstract class SymbolicPointArray {
+    final public float[] data;
+    final public int numPoints;
+    
+    protected SymbolicPointArray(float[] data) {
+        this.data = data;
+        this.numPoints = data.length/TriangleMesh.NUM_COMPONENTS_PER_POINT;
+    }
+    
+    /**
+     * Updates the variables x, y, z based on the state of the other variables
+     * that this symbolic point depends on.
+     */
+    public abstract void update();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/experiments/3DViewer/src/main/java/com/javafx/experiments/shape3d/symbolic/SymbolicPolygonMesh.java	Tue Jul 02 23:11:35 2013 -0700
@@ -0,0 +1,39 @@
+package com.javafx.experiments.shape3d.symbolic;
+
+import com.javafx.experiments.shape3d.PolygonMesh;
+
+/**
+ * Polygon mesh where the points are symbolic. That is, the values of the 
+ * points depend on other variables and they can be updated appropriately.
+ */
+public class SymbolicPolygonMesh {
+    public SymbolicPointArray points;
+    public float[] texCoords;
+    public int[][] faces;
+    private int numEdgesInFaces = -1;
+
+    public SymbolicPolygonMesh() { }
+    
+    public SymbolicPolygonMesh(SymbolicPointArray points, float[] texCoords, int[][] faces) {
+        this.points = points;
+        this.texCoords = texCoords;
+        this.faces = faces;
+    }
+    
+    public SymbolicPolygonMesh(PolygonMesh mesh) {
+        this.points = new OriginalPointArray(mesh);
+        this.texCoords = mesh.getTexCoords().toArray(this.texCoords);
+        this.faces = mesh.faces;
+    }
+    
+    public int getNumEdgesInFaces() {
+        if (numEdgesInFaces == -1) {
+            numEdgesInFaces = 0;
+            for(int[] face : faces) {
+                numEdgesInFaces += face.length;
+            }
+           numEdgesInFaces /= 2;
+        }
+        return numEdgesInFaces;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/experiments/3DViewer/src/main/java/com/javafx/experiments/shape3d/symbolic/SymbolicSubdivisionBuilder.java	Tue Jul 02 23:11:35 2013 -0700
@@ -0,0 +1,360 @@
+package com.javafx.experiments.shape3d.symbolic;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javafx.geometry.Point2D;
+
+import static com.javafx.experiments.shape3d.SubdivisionMesh.*;
+
+/**
+ * 
+ * Data structure builder for Catmull Clark subdivision surface
+ */
+public class SymbolicSubdivisionBuilder {
+    
+    private SymbolicPolygonMesh oldMesh;
+    private Map<Edge, EdgeInfo> edgeInfos;
+    private FaceInfo[] faceInfos;
+    private PointInfo[] pointInfos;
+    private SubdividedPointArray points;
+    private float[] texCoords;
+    private int[] reindex;
+    private int newTexCoordIndex;
+    private BoundaryMode boundaryMode;
+    private MapBorderMode mapBorderMode;
+
+    public SymbolicSubdivisionBuilder(SymbolicPolygonMesh oldMesh, BoundaryMode boundaryMode, MapBorderMode mapBorderMode) {
+        this.oldMesh = oldMesh;
+        this.boundaryMode = boundaryMode;
+        this.mapBorderMode = mapBorderMode;
+    }
+    
+    public SymbolicPolygonMesh subdivide() {
+        collectInfo();
+        
+        texCoords = new float[(oldMesh.getNumEdgesInFaces() * 3 + oldMesh.faces.length) * 2];
+        int[][] faces = new int[oldMesh.getNumEdgesInFaces()][8];
+        newTexCoordIndex = 0;
+        reindex = new int[oldMesh.points.numPoints]; // indexes incremented by 1, 0 reserved for empty
+        
+        // face points first
+        int newFacesInd = 0;
+        for (int f = 0; f < oldMesh.faces.length; f++) {
+            FaceInfo faceInfo = faceInfos[f];
+            int[] oldFaces = oldMesh.faces[f];
+            for (int p = 0; p < oldFaces.length; p += 2) {
+                faces[newFacesInd][4] = getPointNewIndex(faceInfo);
+                faces[newFacesInd][5] = getTexCoordNewIndex(faceInfo);
+                newFacesInd++;
+            }
+        }
+        // then, add edge points
+        newFacesInd = 0;
+        for (int f = 0; f < oldMesh.faces.length; f++) {
+            FaceInfo faceInfo = faceInfos[f];
+            int[] oldFaces = oldMesh.faces[f];
+            for (int p = 0; p < oldFaces.length; p += 2) {
+                faces[newFacesInd][2] = getPointNewIndex(faceInfo, (p / 2 + 1) % faceInfo.edges.length);
+                faces[newFacesInd][3] = getTexCoordNewIndex(faceInfo, (p / 2 + 1) % faceInfo.edges.length);
+                faces[newFacesInd][6] = getPointNewIndex(faceInfo, p / 2);
+                faces[newFacesInd][7] = getTexCoordNewIndex(faceInfo, p / 2);
+                newFacesInd++;
+            }
+        }
+        // finally, add control points
+        newFacesInd = 0;
+        for (int f = 0; f < oldMesh.faces.length; f++) {
+            FaceInfo faceInfo = faceInfos[f];
+            int[] oldFaces = oldMesh.faces[f];
+            for (int p = 0; p < oldFaces.length; p += 2) {
+                faces[newFacesInd][0] = getPointNewIndex(oldFaces[p]);
+                faces[newFacesInd][1] = getTexCoordNewIndex(faceInfo, oldFaces[p], oldFaces[p+1]);
+                newFacesInd++;
+            }
+        }
+        
+        SymbolicPolygonMesh newMesh = new SymbolicPolygonMesh(points, texCoords, faces);
+        return newMesh;
+    }
+    
+    public static SymbolicPolygonMesh subdivide(SymbolicPolygonMesh oldMesh, BoundaryMode boundaryMode, MapBorderMode mapBorderMode) {
+        SymbolicSubdivisionBuilder subdivision = new SymbolicSubdivisionBuilder(oldMesh, boundaryMode, mapBorderMode);
+        return subdivision.subdivide();
+    }
+
+    private void addEdge(Edge edge, FaceInfo faceInfo) {
+        EdgeInfo edgeInfo = edgeInfos.get(edge);
+        if (edgeInfo == null) {
+            edgeInfo = new EdgeInfo();
+            edgeInfo.edge = edge;
+            edgeInfos.put(edge, edgeInfo);
+        }
+        edgeInfo.faces.add(faceInfo);
+    }
+
+    private void addPoint(int point, FaceInfo faceInfo, Edge edge) {
+        PointInfo pointInfo = pointInfos[point];
+        if (pointInfo == null) {
+            pointInfo = new PointInfo();
+            pointInfos[point] = pointInfo;
+        }
+        pointInfo.edges.add(edge);
+        pointInfo.faces.add(faceInfo);
+    }
+    
+    private void addPoint(int point, Edge edge) {
+        PointInfo pointInfo = pointInfos[point];
+        if (pointInfo == null) {
+            pointInfo = new PointInfo();
+            pointInfos[point] = pointInfo;
+        }
+        pointInfo.edges.add(edge);
+    }
+
+    private void collectInfo() {
+        edgeInfos = new HashMap<>(oldMesh.faces.length * 2);
+        faceInfos = new FaceInfo[oldMesh.faces.length];
+        pointInfos = new PointInfo[oldMesh.points.numPoints];
+        
+        for (int f = 0; f < oldMesh.faces.length; f++) {
+            int[] face = oldMesh.faces[f];
+            int n = face.length / 2;
+            FaceInfo faceInfo = new FaceInfo(n);
+            faceInfos[f] = faceInfo;
+            if (n < 3) {
+                continue;
+            }
+            int from = face[(n-1) * 2];
+            int texFrom = face[(n-1) * 2 + 1];
+            double fu, fv;
+            double tu, tv;
+            double u = 0, v = 0;
+            fu = oldMesh.texCoords[texFrom * 2];
+            fv = oldMesh.texCoords[texFrom * 2 + 1];
+            for (int i = 0; i < n; i++) {
+                int to = face[i * 2];
+                int texTo = face[i * 2 + 1];
+                tu = oldMesh.texCoords[texTo * 2];
+                tv = oldMesh.texCoords[texTo * 2 + 1];
+                Point2D midTexCoord = new Point2D((fu + tu) / 2, (fv + tv) / 2);
+                Edge edge = new Edge(from, to);
+                faceInfo.edges[i] = edge;
+                faceInfo.edgeTexCoords[i] = midTexCoord;
+                addEdge(edge, faceInfo);
+                addPoint(to, faceInfo, edge);
+                addPoint(from, edge);
+                fu = tu; fv = tv;
+                u += tu / n; v += tv / n;
+                from = to;
+                texFrom = texTo;
+            }
+            faceInfo.texCoord = new Point2D(u, v);
+        }
+        
+        points = new SubdividedPointArray(oldMesh.points, oldMesh.points.numPoints + faceInfos.length + edgeInfos.size(), boundaryMode);
+        
+        for (int f = 0; f < oldMesh.faces.length; f++) {
+            int[] face = oldMesh.faces[f];
+            int n = face.length / 2;
+            int[] faceVertices = new int[n];
+            for (int i = 0; i < n; i++) {
+                faceVertices[i] = face[i * 2];
+            }
+            faceInfos[f].facePoint = points.addFacePoint(faceVertices);
+        }
+        
+        for(EdgeInfo edgeInfo : edgeInfos.values()) {
+            int[] edgeFacePoints = new int[edgeInfo.faces.size()];
+            for (int f = 0; f < edgeInfo.faces.size(); f++) {
+                edgeFacePoints[f] = edgeInfo.faces.get(f).facePoint;
+            }
+            edgeInfo.edgePoint = points.addEdgePoint(edgeFacePoints, edgeInfo.edge.from, edgeInfo.edge.to, edgeInfo.isBoundary());
+        }
+    }
+
+    private int calcControlPoint(int srcPointIndex) {
+        PointInfo pointInfo = pointInfos[srcPointIndex];
+        int origPoint = srcPointIndex;
+        
+        int[] facePoints = new int[pointInfo.faces.size()];
+        for (int f = 0; f < facePoints.length; f++) {
+            facePoints[f] = pointInfo.faces.get(f).facePoint;
+        }
+        int[] edgePoints = new int[pointInfo.edges.size()];
+        boolean[] isEdgeBoundary = new boolean[pointInfo.edges.size()];
+        int[] fromEdgePoints = new int[pointInfo.edges.size()];
+        int[] toEdgePoints = new int[pointInfo.edges.size()];
+        int i = 0;
+        for (Edge edge : pointInfo.edges) {
+            EdgeInfo edgeInfo = edgeInfos.get(edge);
+            edgePoints[i] = edgeInfo.edgePoint;
+            isEdgeBoundary[i] = edgeInfo.isBoundary();
+            fromEdgePoints[i] = edgeInfo.edge.from;
+            toEdgePoints[i] = edgeInfo.edge.to;
+            i++;
+        }
+        int destPointIndex = points.addControlPoint(facePoints, edgePoints, fromEdgePoints, toEdgePoints, isEdgeBoundary, origPoint, pointInfo.isBoundary(), pointInfo.hasInternalEdge());
+        return destPointIndex;
+    }
+
+    private void calcControlTexCoord(FaceInfo faceInfo, int srcPointIndex, int srcTexCoordIndex, int destTexCoordIndex){
+        PointInfo pointInfo = pointInfos[srcPointIndex];
+        boolean pointBelongsToCrease = oldMesh.points instanceof OriginalPointArray;
+        if ((mapBorderMode == MapBorderMode.SMOOTH_ALL && (pointInfo.isBoundary() || pointBelongsToCrease)) || 
+                (mapBorderMode == MapBorderMode.SMOOTH_INTERNAL && !pointInfo.hasInternalEdge())) {
+            double u = oldMesh.texCoords[srcTexCoordIndex * 2] / 2;
+            double v = oldMesh.texCoords[srcTexCoordIndex * 2 + 1] / 2;
+            for (int i = 0; i < faceInfo.edges.length; i++) {
+                if ((faceInfo.edges[i].to == srcPointIndex) || (faceInfo.edges[i].from == srcPointIndex)) {
+                    u += faceInfo.edgeTexCoords[i].getX() / 4;
+                    v += faceInfo.edgeTexCoords[i].getY() / 4;
+                }
+            }
+            texCoords[destTexCoordIndex * 2] = (float) u;
+            texCoords[destTexCoordIndex * 2 + 1] = (float) v;
+        } else {
+            texCoords[destTexCoordIndex * 2] = oldMesh.texCoords[srcTexCoordIndex * 2];
+            texCoords[destTexCoordIndex * 2 + 1] = oldMesh.texCoords[srcTexCoordIndex * 2 + 1];
+        }
+    }
+
+    private int getPointNewIndex(int srcPointIndex) {
+        int destPointIndex = reindex[srcPointIndex] - 1;
+        if (destPointIndex == -1) {
+            destPointIndex = calcControlPoint(srcPointIndex);
+            reindex[srcPointIndex] = destPointIndex + 1;
+        }
+        return destPointIndex;
+    }
+    
+    private int getPointNewIndex(FaceInfo faceInfo, int edgeInd) {
+        Edge edge = faceInfo.edges[edgeInd];
+        EdgeInfo edgeInfo = edgeInfos.get(edge);
+        return edgeInfo.edgePoint;
+    }
+
+    private int getPointNewIndex(FaceInfo faceInfo) {
+        return faceInfo.facePoint;
+    }
+
+    private int getTexCoordNewIndex(FaceInfo faceInfo, int srcPointIndex, int srcTexCoordIndex) {
+        int destTexCoordIndex = newTexCoordIndex;
+        newTexCoordIndex++;
+        calcControlTexCoord(faceInfo, srcPointIndex, srcTexCoordIndex, destTexCoordIndex);
+        return destTexCoordIndex;
+    }
+    
+    private int getTexCoordNewIndex(FaceInfo faceInfo, int edgeInd) {
+        int destTexCoordIndex = newTexCoordIndex;
+        newTexCoordIndex++;
+        texCoords[destTexCoordIndex * 2] = (float) faceInfo.edgeTexCoords[edgeInd].getX();
+        texCoords[destTexCoordIndex * 2 + 1] = (float) faceInfo.edgeTexCoords[edgeInd].getY();
+        return destTexCoordIndex;
+    }
+    
+    private int getTexCoordNewIndex(FaceInfo faceInfo) {
+        int destTexCoordIndex = faceInfo.newTexCoordIndex - 1;
+        if (destTexCoordIndex == -1) {
+            destTexCoordIndex = newTexCoordIndex;
+            faceInfo.newTexCoordIndex = destTexCoordIndex + 1;
+            newTexCoordIndex++;
+            texCoords[destTexCoordIndex * 2] = (float) faceInfo.texCoord.getX();
+            texCoords[destTexCoordIndex * 2 + 1] = (float) faceInfo.texCoord.getY();
+        }
+        return destTexCoordIndex;
+    }
+
+    private static class Edge {
+        int from, to;
+
+        public Edge(int from, int to) {
+            this.from = Math.min(from, to);
+            this.to = Math.max(from, to);
+        }
+
+        @Override
+        public int hashCode() {
+            int hash = 7;
+            hash = 41 * hash + this.from;
+            hash = 41 * hash + this.to;
+            return hash;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            final Edge other = (Edge) obj;
+            if (this.from != other.from) {
+                return false;
+            }
+            if (this.to != other.to) {
+                return false;
+            }
+            return true;
+        }
+    }
+    
+    private static class EdgeInfo {
+        Edge edge;
+        int edgePoint;
+        List<FaceInfo> faces = new ArrayList<>(2);
+        
+        /**
+         * an edge is in the boundary if it has only one adjacent face
+         */
+        public boolean isBoundary() {
+            return faces.size() == 1;
+        }
+    }
+    
+    private class PointInfo {
+        List<FaceInfo> faces = new ArrayList<>(4);
+        Set<Edge> edges = new HashSet<>(4);
+        
+        /**
+         * A point is in the boundary if any of its adjacent edges is in the boundary
+         */
+        public boolean isBoundary() {
+            for (Edge edge : edges) {
+                EdgeInfo edgeInfo = edgeInfos.get(edge);
+                if (edgeInfo.isBoundary())
+                    return true;
+            }
+            return false;
+        }
+        
+        /**
+         * A point is internal if at least one of its adjacent edges is not in the boundary
+         */
+        public boolean hasInternalEdge() {
+            for (Edge edge : edges) {
+                EdgeInfo edgeInfo = edgeInfos.get(edge);
+                if (!edgeInfo.isBoundary())
+                    return true;
+            }
+            return false;
+        }
+    }
+    
+    private static class FaceInfo {
+        int facePoint;
+        Point2D texCoord;
+        int newTexCoordIndex;
+        Edge[] edges;
+        Point2D[] edgeTexCoords;
+
+        public FaceInfo(int n) {
+            edges = new Edge[n];
+            edgeTexCoords = new Point2D[n];
+        }
+    }
+}
\ No newline at end of file
--- a/build.gradle	Mon Jul 01 12:20:05 2013 -0700
+++ b/build.gradle	Tue Jul 02 23:11:35 2013 -0700
@@ -2228,43 +2228,41 @@
  *   provides for copying the build applications to the artifacts tree
  *
  * The applications to be built will be under ./apps, but also must
- * be listed in the applications listed in the setting variable: JFXApplications 
+ * be listed in the applications listed in the setting variable: JFXApplications
  */
-ext.JFXRT_CP = 
+ext.JFXRT_CP =
     files(
-	project(":base").sourceSets.main.output.classesDir,
-	project(":graphics").sourceSets.main.output.classesDir,
-	project(":controls").sourceSets.main.output.classesDir,
-	project(":fxml").sourceSets.main.output.classesDir,
-	project(":swing").sourceSets.main.output.classesDir, //NOTE - used by 3Dviewer
-	//project(":swt").sourceSets.main.output.classesDir,
-	project(":builders").sourceSets.main.output.classesDir,
-        "modules/media/build/classes/main", 
-        "modules/web/build/classes/main", 
-	)
+        project(":base").sourceSets.main.output.classesDir,
+        project(":graphics").sourceSets.main.output.classesDir,
+        project(":controls").sourceSets.main.output.classesDir,
+        project(":fxml").sourceSets.main.output.classesDir,
+        project(":swing").sourceSets.main.output.classesDir, //NOTE - used by 3Dviewer
+        //project(":swt").sourceSets.main.output.classesDir,
+        project(":builders").sourceSets.main.output.classesDir,
+            "modules/media/build/classes/main",
+            "modules/web/build/classes/main",
+    )
 
 if (BINARY_STUB != null) {
-    JFXRT_CP += BINARY_STUB 
+    JFXRT_CP += BINARY_STUB
 }
 
-
-childProjects["apps"].subprojects { 
+childProjects["apps"].subprojects {
     afterEvaluate { project ->
-	// this check is to make sure we are using a java or application plugin
+        // this check is to make sure we are using a java or application plugin
         // in our child projects of ./apps
         if (project.hasProperty("jar") && project.hasProperty("compileJava")) {
-           def srcdir = new File ("$project.projectDir/src");
+            def srcdir = new File ("$project.projectDir/src");
 
-           if (srcdir.exists()) {
-               // augment the classpath with our build system classpath 
-               // which will include our local jfxrt.jar
-               project.compileJava {
-                   // TODO: don't know how to do this correctly
-                   //dependsOn project(":graphics").classes, project(":controls").classes, project(":base").classes
-                   doFirst {
-                       classpath = rootProject.JFXRT_CP + 
-                           sourceSets.main.compileClasspath
-                   }
+            if (srcdir.exists()) {
+                // augment the classpath with our build system classpath
+                // which will include our local jfxrt.jar
+                project.compileJava {
+                    // TODO: don't know how to do this correctly
+                    //dependsOn project(":graphics").classes, project(":controls").classes, project(":base").classes
+                    doFirst {
+                        classpath = rootProject.JFXRT_CP + sourceSets.main.compileClasspath
+                    }
                 }
                 test.exclude("**/*");
             } else {
@@ -2276,13 +2274,13 @@
 
             if (BUILD_CLOSED && srcdir.exists()) {
                 def cptask = project.task('copyAppsArtifacts', type: Copy ) {
-                dependsOn project.getPath() + ":jar"
-		    from project.jar.archivePath
-		    into "$rootProject.jfxArtifactsDir/apps/ga-samples"
-		}
+                    dependsOn project.getPath() + ":jar"
+                    from project.jar.archivePath
+                    into "$rootProject.jfxArtifactsDir/apps/ga-samples"
+                }
                 rootProject.apps.dependsOn(cptask)
-	    }
-	}
+            }
+        }
     }
 }
 
--- a/buildSrc/.classpath	Mon Jul 01 12:20:05 2013 -0700
+++ b/buildSrc/.classpath	Tue Jul 02 23:11:35 2013 -0700
@@ -6,8 +6,10 @@
   <classpathentry kind="lib" exported="true" path="../.libs/ant-1.8.2.jar"/>
   <classpathentry kind="lib" exported="true" path="../.libs/antlr-3.1.3.jar"/>
   <classpathentry kind="lib" exported="true" path="../.libs/antlr-runtime-3.1.3.jar"/>
+  <classpathentry kind="lib" exported="true" path="../.libs/plugin.jar"/>
   <classpathentry kind="lib" exported="true" path="../.libs/stringtemplate-3.2.jar"/>
   <classpathentry kind="lib" exported="true" path="../.libs/swt.jar"/>
+  <classpathentry kind="lib" exported="true" path="../../caches/sdk/rt/lib/ext/jfxrt.jar"/>
   <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
   <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
   <classpathentry kind="output" path="bin"/>
--- a/buildSrc/android.gradle	Mon Jul 01 12:20:05 2013 -0700
+++ b/buildSrc/android.gradle	Tue Jul 02 23:11:35 2013 -0700
@@ -23,20 +23,173 @@
  * questions.
  */
 
-/******************************************************************************
- *                                                                            *
- *                         Build Setup Sanity Checks                          *
- *                                                                            *
- *****************************************************************************/
-ext.ANDROID_CAN_BUILD = false
-if (!ANDROID_CAN_BUILD) return;
+/**
+ * Gets the most recent android platform installed, relative to the given path.
+ * The path will either be ANDROID_SDK or ANDROID_NDK
+ * TODO Shouldn't we instead just ask people to point to the one they want to use?
+ *
+ * @param path The path to the Android SDK or NDK
+ * @return The name of the most recent platform
+ */
+String getLatestPlatform(String path) {
+    def max = 0
+    file(cygpath(path + "/platforms")).eachFile() {file->
+        def pname = file.getName() - "android-"
+        def ptf = pname?.isInteger() ? pname.toInteger() : 0
+        if (max < ptf) {
+            max = ptf
+        }
+    }
+    if (max == 0) {
+        return null;
+    }
+    return "android-" + max
+}
 
-// NOTE: Android can be built from Mac, Windows, or Linux.
-// TODO Sanity check should include locating the Android SDK / NDK.
+ext.ANDROID = [:]
 
-ext.GLASS_PLATFORM = "android"
-ext.LIB_DEST = "lib/$OS_ARCH" // TODO Not sure about this.
-ext.JFXRT_JAR_EXCLUDES = [
+def closedDir = file("$projectDir/../rt-closed")
+
+defineProperty("ANDROID_CROSS_TOOLS_VER", "arm-linux-androideabi-4.4.3")
+defineProperty("ARM_ARCH", "armeabi")//armeabi-v7
+
+// Look for the the Android SDK & NDK to use, as well as the compiler stuff
+def sdk = project.hasProperty("ANDROID_SDK") ? getLatestPlatform("$ANDROID_SDK") : null;
+def ndk = project.hasProperty("ANDROID_NDK") ? getLatestPlatform("$ANDROID_NDK") : null;
+def toolsPlatform = IS_WINDOWS ? "windows" : IS_MAC ? "macosx" : "linux-x86"
+def compilerHome = sdk == null || ndk == null ? null : file("${ANDROID_NDK}/toolchains/${ANDROID_CROSS_TOOLS_VER}/prebuilt/$toolsPlatform")
+
+// We can build Android if the ANDROID_SDK and ANDROID_NDK are specified, and if
+// the targets exist.
+ANDROID.canBuild = sdk != null && ndk != null && compilerHome != null;
+if (!ANDROID.canBuild) return;
+
+// We now know that we can build Android, so time to define some useful properties
+defineProperty("ANDROID_SDK_TARGET", sdk)
+defineProperty("ANDROID_NDK_TARGET", ndk)
+
+def compiler = file("$compilerHome/bin/arm-linux-androideabi-gcc").getAbsolutePath()
+def linker = file("$compilerHome/bin/arm-linux-androideabi-g++").getAbsolutePath()
+
+// Log the settings we're building with
+logger.quiet("ANDROID_SDK: $ANDROID_SDK")
+logger.quiet("ANDROID_SDK_TARGET: $ANDROID_SDK_TARGET")
+logger.quiet("ANDROID_NDK: $ANDROID_NDK")
+logger.quiet("ANDROID_NDK_TARGET: $ANDROID_NDK_TARGET")
+logger.quiet("Android Compiler: $compiler")
+logger.quiet("Android Linker: $linker")
+
+
+project(":graphics") {
+
+    task compileDalvikLibs(type: JavaCompile, group: "Build") {
+        description = "Task compiles dalvik vm based libraries."
+        sourceCompatibility = JavaVersion.VERSION_1_6
+        targetCompatibility = JavaVersion.VERSION_1_6
+        options.bootClasspath = "${ANDROID_SDK}/platforms/${ANDROID_SDK_TARGET}/android.jar"
+        classpath = files("build/classes/main")
+        destinationDir = file("build/classes/main")
+        dependencyCacheDir = file("build/dependency-cache")
+        source "src/main/android"
+    }
+
+    task jarDalvikLibs(type: Jar, group: "Build", dependsOn: compileDalvikLibs) {
+        description = "Creates jfxdvk.jar with all dalvik based classes."
+        archiveName = "jfxdvk.jar"
+        includeEmptyDirs = false
+        from("build/classes/main")
+        include("com/oracle/dalvik/**/*")
+        dependsOn(compileDalvikLibs)
+    }
+
+    afterEvaluate {
+        addNative(project, "surface")
+        addNative(project, "vmlauncher")
+        tasks["javahAndroidVmlauncher"].dependsOn(compileDalvikLibs)
+        tasks["native"].dependsOn("nativeSurface", "nativeVmlauncher")
+
+        sdkAndroid  {
+            dependsOn(jarDalvikLibs)
+            doLast {
+                def props = project.ext["ANDROID"]
+                copy {
+                    from(
+                         "modules/graphics/build/libs/vmlauncher/android/${library(props.vmlauncher.lib)}",
+                         "modules/graphics/build/libs/surface/android/${library(props.surface.lib)}",
+                         "modules/graphics/build/libs/${props.jfxdvklib}"
+                    );
+                    def libDest = props.libDest
+                    into ("build/android-sdk/dalvik")
+                }
+            }
+        }
+    }
+}
+
+project(":web") {
+    apply plugin: 'java'
+
+    sourceSets {
+        android {
+            java {
+                //srcDir 'src/android/java'
+                srcDir '${closedDir}/javafx-android/webnode/src'
+            }
+        }
+    }
+
+    compileJava {
+        enabled = false
+    }
+
+    afterEvaluate {
+        configure(compileAndroidJava, { t ->
+                t.classpath = files(
+                    project(":graphics").sourceSets.main.output.classesDir,
+                    project(":base").sourceSets.main.output.classesDir
+                )
+                t.dependsOn(project(":graphics").classes, project(":base").classes)
+            })
+
+        addNative(project, "webview")
+        addNative(project, "dvkwebview")
+        javahAndroidWebview.dependsOn(compileAndroidJava)
+        javahAndroidDvkwebview.dependsOn(compileAndroidJava)
+
+        jfxrtAndroid {
+            from "modules/web/build/classes/android"
+        }
+
+        sdkAndroid << {
+            def props = project.ext["ANDROID"]
+            copy {
+                from(
+                     "modules/web/build/libs/webview/android/${library(props.webview.lib)}"
+                )
+                def libDest = props.libDest
+                into ("build/android-sdk/rt/$libDest")
+            }
+            copy {
+                from(
+                    "modules/web/build/libs/dvkwebview/android/${library(props.dvkwebview.lib)}"
+                )
+                def libDest = props.libDest
+                into ("build/android-sdk/dalvik")
+            }
+        }
+    }
+}
+
+ANDROID.compileSwing = false;
+ANDROID.compileSWT = false;
+ANDROID.compileFXPackager = false;
+ANDROID.compileDesignTime = false;
+ANDROID.glassPlatform = "android"
+ANDROID.armArch = "${ARM_ARCH}"
+ANDROID.libDest = "lib/${ANDROID.armArch}"
+ANDROID.jfxdvklib = "jfxdvk.jar"
+
+ANDROID.jfxrtJarExcludes = [
     "**/*.hlsl",
     "com/sun/glass/ui/win",
     "com/sun/glass/ui/accessible/win",
@@ -44,25 +197,214 @@
     "com/sun/prism/es2/gl/win",
     "com/sun/prism/null3d",
     "com/sun/scenario/effect/impl/hw/d3d",
-    
     "com/sun/glass/events/mac",
     "com/sun/glass/ui/mac",
     "com/sun/glass/ui/accessible/mac",
     "com/sun/prism/es2/gl/mac",
-    
     "com/sun/glass/ui/gtk",
-    
     "com/sun/glass/ui/ios",
-    
-    // TODO Android build will need one or more of these 4 lines removed
-    "com/sun/glass/ui/lens",
-    "com/sun/prism/es2/gl/eglfb",
     "com/sun/prism/es2/gl/eglx11",
     "com/sun/prism/es2/gl/x11",
-    
     "com/sun/glass/ui/swt", // SWT glass
-    
     "javafx/embed/swing", // Swing Interop
-    
     "javafx/embed/swt", // SWT Interop
+    "com/oracle/dalvik"
 ]
+
+ANDROID.javafxPlatformProperties = """
+javafx.platform=android
+android.glass.platform=Lens
+android.glass.lens=eglfb
+android.egl.depthSize=16
+android.prism.lcdtext=false
+android.embedded=eglfb
+android.prism.maxTextureSize=2048
+android.prism.dirtyopts=true
+android.prism.vsync=false
+android.prism.device=true
+android.use.egl=true
+android.com.sun.javafx.isEmbedded=true
+"""
+
+def ccFlags = ["-std=c99", "-DANDROID", "-c", "-nostdlib", "-DANDROID_NDK"]
+def ccOptFlags = ["-fpic", "-ffunction-sections", "-funwind-tables","-fstack-protector",
+                  "-Os", "-O2", "-fno-strict-aliasing", "-finline-limit=64", "-fomit-frame-pointer"]
+def ccWarnFlags = ["-Wa,--noexecstack", "-Wno-psabi"]
+def ccArchFlags = ["-mthumb", "-msoft-float", "-D__ARM_ARCH_5__", "-D__ARM_ARCH_5T__", "-D__ARM_ARCH_5E__",
+                   "-D__ARM_ARCH_5TE__", "-march=armv5te" , "-mtune=xscale"]
+def ccDebugFlags = [IS_DEBUG ? "-DDEBUG" : "-DNDEBUG"]
+def ccDefaultIncludeFlags = ["-I${ANDROID_NDK}/platforms/${ANDROID_NDK_TARGET}/arch-arm/usr/include"]
+
+def linkFlags = ["--sysroot=${ANDROID_NDK}/platforms/${ANDROID_NDK_TARGET}/arch-arm",
+                 "-Wl,--no-undefined", "-Wl,-z,noexecstack", "-lc", "-lm", "-shared",
+                 "-L${ANDROID_NDK}/platforms/${ANDROID_NDK_TARGET}/arch-arm/usr/lib"]
+
+
+ANDROID.vmlauncher = [:]
+ANDROID.vmlauncher.classpath =
+files("${ANDROID_SDK}/platforms/${ANDROID_SDK_TARGET}/android.jar",
+      "modules/graphics/build/classes/main")
+
+ANDROID.vmlauncher.javahClasspath = "${ANDROID_SDK}/platforms/${ANDROID_SDK_TARGET}/android.jar"
+ANDROID.vmlauncher.javahInclude = [
+    "com/oracle/dalvik/*"
+]
+ANDROID.vmlauncher.nativeSource = [
+    file("modules/graphics/src/main/native-android/VMLauncher.c"),
+    file("modules/graphics/src/main/native-android/NativePipeReader.c"),
+    file("modules/graphics/src/main/native-android/DalvikProxySelector.c")
+]
+ANDROID.vmlauncher.compiler = compiler
+ANDROID.vmlauncher.linker = linker
+ANDROID.vmlauncher.lib = "vmlauncher"
+ANDROID.vmlauncher.ccFlags = [ccFlags, ccWarnFlags, ccArchFlags, ccOptFlags,
+    ccDebugFlags, ccDefaultIncludeFlags].flatten()
+ANDROID.vmlauncher.linkFlags = [linkFlags, "-llog"].flatten()
+
+ANDROID.surface = [:]
+ANDROID.surface.javahInclude = [
+    "com/sun/glass/events/*"
+]
+ANDROID.surface.nativeSource = [
+    file("modules/graphics/src/main/native-glass/lens/android")
+]
+ANDROID.surface.compiler = compiler
+ANDROID.surface.linker = linker
+ANDROID.surface.lib = "glass-lens-android"
+ANDROID.surface.ccFlags = [ccFlags, ccWarnFlags, ccArchFlags, ccOptFlags,
+    ccDebugFlags, ccDefaultIncludeFlags, "-Isrc/main/native-glass/lens"].flatten()
+ANDROID.surface.linkFlags = [linkFlags, "-ldl", "-landroid", "-llog"].flatten()
+
+ANDROID.webview = [:]
+ANDROID.webview.sourceSet = "android"
+ANDROID.webview.javahInclude = [
+    "com/sun/webkit/NativeWebView.class"
+]
+ANDROID.webview.nativeSource = [
+    //file("modules/web/src/android/native/native_webview.c")
+    file("${closedDir}/javafx-android/webnode/jni/native_webview.c")
+]
+ANDROID.webview.compiler = compiler
+ANDROID.webview.linker = linker
+ANDROID.webview.lib = "webview"
+ANDROID.webview.ccFlags = [ccFlags, ccWarnFlags, ccArchFlags, ccOptFlags,
+    ccDebugFlags, ccDefaultIncludeFlags].flatten()
+ANDROID.webview.linkFlags = [linkFlags, "-ldl", "-llog"].flatten()
+
+ANDROID.dvkwebview = [:]
+ANDROID.dvkwebview.sourceSet = "android"
+ANDROID.dvkwebview.javahInclude = [
+    "com/sun/webkit/NativeWebView.class"
+]
+ANDROID.dvkwebview.nativeSource = [
+    //file("modules/web/src/android/native/android_webview.c")
+    file("${closedDir}/javafx-android/webnode/jni/android_webview.c")
+]
+ANDROID.dvkwebview.compiler = compiler
+ANDROID.dvkwebview.linker = linker
+ANDROID.dvkwebview.lib = "android-webview"
+ANDROID.dvkwebview.ccFlags = [ccFlags, ccWarnFlags, ccArchFlags, ccOptFlags,
+    ccDebugFlags, ccDefaultIncludeFlags].flatten()
+ANDROID.dvkwebview.linkFlags = [linkFlags, "-ldl", "-llog"].flatten()
+
+ANDROID.glass = [:]
+ANDROID.glass.variants = ["eglfb"]
+ANDROID.glass.javahInclude = [
+    "com/sun/glass/events/**",
+    "com/sun/glass/ui/*",
+    "com/sun/glass/ui/lens/*"]
+
+ANDROID.glass.eglfb = [:]
+ANDROID.glass.eglfb.nativeSource = [
+    file("modules/graphics/src/main/native-glass/lens"),
+    file("modules/graphics/src/main/native-glass/lens/wm"),
+    file("modules/graphics/src/main/native-glass/lens/cursor/nullCursor"),
+    file("modules/graphics/src/main/native-glass/lens/input/android"),
+    file("modules/graphics/src/main/native-glass/lens/wm/screen/androidScreen.c")]
+ANDROID.glass.eglfb.compiler = compiler
+ANDROID.glass.eglfb.linker = linker
+ANDROID.glass.eglfb.lib = "glass-lens-eglfb"
+ANDROID.glass.eglfb.ccFlags = [ccFlags, ccWarnFlags, ccArchFlags, ccOptFlags,
+    ccDebugFlags, ccDefaultIncludeFlags].flatten()
+ANDROID.glass.eglfb.linkFlags = [linkFlags, "-ldl", "-landroid", "-llog"].flatten()
+
+ANDROID.prism = [:]
+ANDROID.prism.javahInclude = ["com/sun/prism/impl/**/*", "com/sun/prism/PresentableState*"]
+ANDROID.prism.nativeSource = file("modules/graphics/src/main/native-prism")
+ANDROID.prism.compiler = compiler
+ANDROID.prism.ccFlags = [ccFlags, ccWarnFlags, ccArchFlags, ccOptFlags,
+    ccDebugFlags, ccDefaultIncludeFlags].flatten()
+ANDROID.prism.linker = linker
+ANDROID.prism.linkFlags = [linkFlags].flatten()
+ANDROID.prism.lib = "prism-common"
+
+ANDROID.prismSW = [:]
+ANDROID.prismSW.javahInclude = ["com/sun/pisces/**/*"]
+ANDROID.prismSW.nativeSource = file("modules/graphics/src/main/native-prism-sw")
+ANDROID.prismSW.compiler = compiler
+ANDROID.prismSW.ccFlags = [ccFlags, ccWarnFlags, ccArchFlags, ccOptFlags,
+    ccDebugFlags, ccDefaultIncludeFlags].flatten()
+ANDROID.prismSW.linker = linker
+ANDROID.prismSW.linkFlags = [linkFlags].flatten()
+ANDROID.prismSW.lib = "prism-sw"
+
+ANDROID.decora = [:]
+ANDROID.decora.compiler = compiler
+ANDROID.decora.ccFlags = [ccFlags, ccWarnFlags, ccArchFlags, ccOptFlags,
+    ccDebugFlags, ccDefaultIncludeFlags].flatten()
+ANDROID.decora.linker = linker
+ANDROID.decora.linkFlags = [linkFlags].flatten()
+ANDROID.decora.lib = "decora-sse"
+
+ANDROID.iio = [:]
+ANDROID.iio.javahInclude = ["com/sun/javafx/iio/**/*"]
+ANDROID.iio.nativeSource = [
+    file("modules/graphics/src/main/native-iio"),
+    file("modules/graphics/src/main/native-iio/libjpeg7")]
+ANDROID.iio.compiler = compiler
+ANDROID.iio.ccFlags = [ccFlags, ccWarnFlags, ccArchFlags, ccOptFlags,
+    ccDebugFlags, ccDefaultIncludeFlags].flatten()
+ANDROID.iio.linker = linker
+ANDROID.iio.linkFlags = [linkFlags].flatten()
+ANDROID.iio.lib = "javafx-iio"
+
+ANDROID.prismES2 = [:]
+ANDROID.prismES2.variants = ["eglfb"]
+ANDROID.prismES2.javahInclude = ["com/sun/prism/es2/**/*"]
+
+ANDROID.prismES2.eglfb = [:]
+ANDROID.prismES2.eglfb.nativeSource = [
+    file("modules/graphics/src/main/native-prism-es2"),
+    file("modules/graphics/src/main/native-prism-es2/GL"),
+    file("modules/graphics/src/main/native-prism-es2/eglfb")]
+ANDROID.prismES2.eglfb.compiler = compiler
+ANDROID.prismES2.eglfb.ccFlags = [ccFlags, ccWarnFlags, ccArchFlags, ccOptFlags,
+    ccDebugFlags, ccDefaultIncludeFlags, "-DIS_EGLFB"].flatten()
+ANDROID.prismES2.eglfb.linker = linker
+ANDROID.prismES2.eglfb.linkFlags = [linkFlags, "-ldl", "-llog", "-lGLESv2", "-lEGL"].flatten()
+ANDROID.prismES2.eglfb.lib = "prism-es2-eglfb"
+
+ANDROID.font = [:]
+ANDROID.font.javahInclude = [
+        "com/sun/javafx/font/**/*",
+        "com/sun/javafx/text/**/*"]
+ANDROID.font.nativeSource = [file("$closedDir/javafx-font-native/src")]
+ANDROID.font.compiler = compiler
+ANDROID.font.ccFlags = [ccFlags, ccWarnFlags, ccArchFlags, ccOptFlags,
+    ccDebugFlags, ccDefaultIncludeFlags].flatten()
+ANDROID.font.linker = linker
+ANDROID.font.linkFlags = [linkFlags].flatten()
+ANDROID.font.lib = "javafx-font"
+
+ANDROID.fontT2K = [:]
+ANDROID.fontT2K.javahInclude = ["com/sun/javafx/font/t2k/**/*"]
+ANDROID.fontT2K.nativeSource = [
+    file("$closedDir/javafx-font-t2k-native/src"),
+    file("$closedDir/javafx-font-t2k-native/src/layout"),
+    file("$closedDir/javafx-font-t2k-native/src/layoutfx")]
+ANDROID.fontT2K.compiler = compiler
+ANDROID.fontT2K.ccFlags = [ccFlags, "-fno-exceptions", "-fno-rtti", ccWarnFlags,
+    ccArchFlags, ccOptFlags, ccDebugFlags, ccDefaultIncludeFlags].flatten()
+ANDROID.fontT2K.linker = linker
+ANDROID.fontT2K.linkFlags = [linkFlags, "-lstdc++"].flatten()
+ANDROID.fontT2K.lib = "javafx-font-t2k"
\ No newline at end of file
--- a/buildSrc/armv6hf.gradle	Mon Jul 01 12:20:05 2013 -0700
+++ b/buildSrc/armv6hf.gradle	Tue Jul 02 23:11:35 2013 -0700
@@ -253,7 +253,7 @@
 ARMV6HF.glass.directfb.ccFlags = ["-ffast-math", extraCFlags, "-I$sdk/usr/include/directfb", "-DLINUX", "-DGRADLE_BUILD"].flatten()
 ARMV6HF.glass.directfb.linker = linker
 ARMV6HF.glass.directfb.linkFlags = [lensLFlags].flatten()
-ARMV6HF.glass.directfb.lib = "glass-lens-directfb"
+ARMV6HF.glass.directfb.lib = "glass-lens-dfb"
 
 ARMV6HF.glass.fb = [:]
 ARMV6HF.glass.fb.nativeSource = [
--- a/buildSrc/armv6sf.gradle	Mon Jul 01 12:20:05 2013 -0700
+++ b/buildSrc/armv6sf.gradle	Tue Jul 02 23:11:35 2013 -0700
@@ -268,7 +268,7 @@
 ARMV6SF.glass.directfb.ccFlags = ["-ffast-math", extraCFlags, "-I$sdk/usr/include/directfb", "-DLINUX", "-DGRADLE_BUILD"].flatten()
 ARMV6SF.glass.directfb.linker = linker
 ARMV6SF.glass.directfb.linkFlags = [lensLFlags].flatten()
-ARMV6SF.glass.directfb.lib = "glass-lens-directfb"
+ARMV6SF.glass.directfb.lib = "glass-lens-dfb"
 
 ARMV6SF.glass.fb = [:]
 ARMV6SF.glass.fb.nativeSource = [
--- a/gradle.properties.template	Mon Jul 01 12:20:05 2013 -0700
+++ b/gradle.properties.template	Tue Jul 02 23:11:35 2013 -0700
@@ -152,6 +152,12 @@
 #systemProp.http.proxyHost=proxy.my.com
 #systemProp.http.proxyPort=80
 
+# In order to enable Android builds, you must specify the paths to the Android SDK and NDK.
+# Uncomment the two lines below and configure them to point to the right location on your system
+
+#ANDROID_SDK = /path/to/android/sdk
+#ANDROID_NDK = /path/to/android/ndk
+
 # The COMPILE_FLAGS_FILES defines the native compilation flags to use. Each native project
 # defines a pair of flags, XXX_CC_FLAGS and XXX_LINK_FLAGS as defined below:
 #
--- a/modules/base/src/main/java/com/sun/javafx/animation/TickCalculation.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 2011, 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 com.sun.javafx.animation;
-
-import javafx.util.Duration;
-
-public class TickCalculation {
-    public static final int TICKS_PER_SECOND = 6000;
-    private static final double TICKS_PER_MILI = TICKS_PER_SECOND / 1000.0;
-    private static final double TICKS_PER_NANO =  TICKS_PER_MILI * 1e-6;
-    
-    private TickCalculation() {}
-    
-    public static long add(long op1, long op2) {
-        assert (op1 >= 0);
-
-        if (op1 == Long.MAX_VALUE || op2 == Long.MAX_VALUE) {
-            return Long.MAX_VALUE;
-        } else if (op2 == Long.MIN_VALUE) {
-            return 0;
-        }
-
-        if (op2 >= 0) {
-            final long result = op1 + op2;
-            return (result < 0)? Long.MAX_VALUE : result;
-        } else {
-            return Math.max(0, op1 + op2);
-        }
-
-    }
-
-    public static long sub(long op1, long op2) {
-        assert (op1 >= 0);
-
-        if (op1 == Long.MAX_VALUE || op2 == Long.MIN_VALUE) {
-            return Long.MAX_VALUE;
-        } else if (op2 == Long.MAX_VALUE) {
-            return 0;
-        }
-
-        if (op2 >= 0) {
-            return Math.max(0, op1 - op2);
-        } else {
-            final long result = op1 - op2;
-            return result < 0 ? Long.MAX_VALUE : result;
-        }
-
-    }
-    
-    public static long fromMillis(double millis) {
-        return Math.round(TICKS_PER_MILI * millis);
-    }
-    
-    public static long fromNano(long nano) {
-        return Math.round(TICKS_PER_NANO * nano);
-    }
-    
-    public static long fromDuration(Duration duration) {
-        return fromMillis(duration.toMillis());
-    }
-
-    public static long fromDuration(Duration duration, double rate) {
-        return Math.round(TICKS_PER_MILI * duration.toMillis() / Math.abs(rate));
-    }
-    
-    public static Duration toDuration(long ticks) {
-        return Duration.millis(toMillis(ticks));
-    }
-
-    public static double toMillis(long ticks) {
-        return ticks / TICKS_PER_MILI;
-    }
-    
-
-}
--- a/modules/base/src/main/java/com/sun/scenario/DelayedRunnable.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2008, 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 com.sun.scenario;
-
-public interface DelayedRunnable extends Runnable {
-    /**
-     * Gets the delay <strong>in milliseconds</strong>.
-     * @return delay in millis
-     */
-    public long getDelay();
-}
--- a/modules/base/src/main/java/com/sun/scenario/Settings.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,232 +0,0 @@
-/*
- * Copyright (c) 2008, 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 com.sun.scenario;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.CopyOnWriteArrayList;
-import javafx.util.Callback;
-
-/**
- * A simple class to store and retrieve internal Scenario settings in the form
- * of String key/value pairs. It is meant to be used in a similar way to System
- * Properties, but without the security restrictions. This class is designed
- * primarily to aid in testing and benchmarking Scenario itself.
- * 
- * If you are running in an environment that allows System Property access, this
- * class will attempt to look for a key's value in the System Properties if none
- * is found in Settings. This allows Settings to be set on the command line as
- * well as via the Settings API.
- * 
- */
-public class Settings {
-
-    private final Map<String, String> settings = new HashMap<>(5);
-    private final CopyOnWriteArrayList<Callback<String, Void>> listeners = new CopyOnWriteArrayList<>();
-    private static final Object SETTINGS_KEY;
-    static {
-        SETTINGS_KEY = new StringBuilder("SettingsKey");
-
-        // It seems no longer necessary to force loading of MasterTimer to pick
-        // up the hi-res timer workaround. Also, this is causing some init
-        // order problems (RT-5572), so it's being commented out.
-        // Object obj = ToolkitAccessor.getMasterTimer();
-    }
-
-    private static synchronized Settings getInstance() {
-        Map<Object, Object> contextMap = ToolkitAccessor.getContextMap();
-        Settings instance = (Settings) contextMap.get(SETTINGS_KEY);
-        if (instance == null) {
-            instance = new Settings();
-            contextMap.put(SETTINGS_KEY, instance);
-        }
-        return instance;
-    }
-
-    /**
-     * Add a new key-value setting.
-     * 
-     * Passing a value of null indicates that the value for this key should be
-     * looked for in the System Properties.
-     * 
-     * If PropertyChangeListeners have been registered for the given key, they
-     * will be notified of a change in value.
-     * 
-     * If key is "" or null, this methods throws an IllegalArgumentException.
-     */
-    public static void set(String key, String value) {
-        getInstance().setImpl(key, value);
-    }
-
-    private void setImpl(String key, String value) {
-        checkKeyArg(key);
-        settings.put(key, value);
-        for (Callback<String, Void> l : listeners) {
-            l.call(key);
-        }
-     }
-
-    /**
-     * Retrieve the value for the given key.
-     * 
-     * If the key is not present in Settings or its value is null, this methods
-     * then checks to see if a value for this key is present in the System
-     * Properties (provided you have sufficient privileges).
-     * 
-     * If no value can be found for the given key, this method returns null.
-     * 
-     * If key is "" or null, this methods throws an IllegalArgumentException.
-     */
-    public static String get(String key) {
-        return getInstance().getImpl(key);
-    }
-
-    private String getImpl(String key) {
-        checkKeyArg(key);
-        String retVal = settings.get(key);
-        if (retVal == null) {
-            try {
-                retVal = System.getProperty(key);
-            } catch (SecurityException ignore) {
-            }
-        }
-        return retVal;
-    }
-
-    /**
-     * Convenience method for boolean settings.
-     * 
-     * If the setting exists and its value is "true", true is returned.
-     * Otherwise, false is returned.
-     * 
-     * If key is "" or null, this methods throws an IllegalArgumentException.
-     */
-    public static boolean getBoolean(String key) {
-        return getInstance().getBooleanImpl(key);
-    }
-
-    private boolean getBooleanImpl(String key) {
-        // get() will call checkKeyArg(), so don't check it here
-        String value = getImpl(key);
-        return "true".equals(value);
-    }
-
-    /**
-     * Convenience method for boolean settings.
-     * 
-     * If the setting is set to "true", true is returned. If the setting is set
-     * to "false", false is returned. It the setting is set to anything else,
-     * defaultVal is returned.
-     * 
-     * If key is "" or null, this methods throws an IllegalArgumentException.
-     */
-    public static boolean getBoolean(String key, boolean defaultVal) {
-        return getInstance().getBooleanImpl(key, defaultVal);
-    }
-
-    private boolean getBooleanImpl(String key, boolean defaultVal) {
-        // get() will call checkKeyArg(), so don't check it here
-        String value = getImpl(key);
-        boolean retVal = defaultVal;
-        if (value != null) {
-            if ("false".equals(value)) {
-                retVal = false;
-            } else if ("true".equals(value)) {
-                retVal = true;
-            }
-        }
-        return retVal;
-    }
-
-    /**
-     * Convenience method for int settings.
-     * 
-     * If the setting exists and its value can be parsed to an int, the int
-     * value is returned. Otherwise, the default value is returned.
-     * 
-     * If key is "" or null, this methods throws an IllegalArgumentException.
-     */
-    public static int getInt(String key, int defaultVal) {
-        return getInstance().getIntImpl(key, defaultVal);
-    }
-
-    private int getIntImpl(String key, int defaultVal) {
-        // get() will call checkKeyArg(), so don't check it here
-        String value = getImpl(key);
-        int retVal = defaultVal;
-        try {
-            retVal = Integer.parseInt(value);
-        } catch (NumberFormatException ignore) {
-            // ignore.printStackTrace();
-        }
-        return retVal;
-    }
-
-    /**
-     * Add a PropertyChangeListener for the specified setting
-     * 
-     * Note that the PropertyChangeEvent will contain old and new values as they
-     * would be returned from get(), meaning they may come from the System
-     * Properties.
-     * 
-     * If key is "" or null, this methods throws an IllegalArgumentException. If
-     * listener is null no exception is thrown and no action is taken.
-     */
-    public static void addPropertyChangeListener(Callback<String, Void> pcl) {
-        getInstance().addPropertyChangeListenerImpl(pcl);
-    }
-
-    private void addPropertyChangeListenerImpl(Callback<String, Void> pcl) {
-        listeners.add(pcl);
-    }
-
-    /**
-     * Remove the specified PropertyChangeListener.
-     * 
-     * If listener is null, or was never added, no exception is thrown and no
-     * action is taken.
-     */
-    public static void removePropertyChangeListener(Callback<String, Void> pcl) {
-        getInstance().removePropertyChangeListenerImpl(pcl);
-    }
-
-    private void removePropertyChangeListenerImpl(Callback<String, Void> pcl) {
-        listeners.remove(pcl);
-    }
-
-    /*
-     * Check that key is a valid Settings key. If not, throw an
-     * IllegalArgumentException.
-     */
-    private void checkKeyArg(String key) {
-        if (null == key || "".equals(key)) {
-            throw new IllegalArgumentException("null key not allowed");
-        }
-    }
-
-    private Settings() {
-    }
-}
--- a/modules/base/src/main/java/com/sun/scenario/ToolkitAccessor.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 2008, 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 com.sun.scenario;
-
-import java.util.Map;
-
-import com.sun.scenario.animation.AbstractMasterTimer;
-
-/**
- * A simple java accessor to the current Toolkit.
- * This class is ONLY NECESSARY because javafx-anim is separate from javafx-ui-common.
- * When they are combined, we can remove this class.
- */
-public abstract class ToolkitAccessor {
-    private static ToolkitAccessor instance;
-
-    public static void setInstance(ToolkitAccessor accessor) {
-        instance = accessor;
-    }
-
-    private static ToolkitAccessor getInstance() {
-        if (instance == null) {
-            // running in stand alone case without toolkit
-            try {
-                Class<?> cl = Class
-                        .forName("com.sun.scenario.StandaloneAccessor");
-                setInstance((ToolkitAccessor) cl.newInstance());
-            } catch (Throwable th) {
-                // ignore
-            }
-        }
-        return instance;
-    }
-
-    public static Map<Object, Object> getContextMap() {
-        return getInstance().getContextMapImpl();
-    }
-
-    public static AbstractMasterTimer getMasterTimer() {
-        return getInstance().getMasterTimerImpl();
-    }
-
-    public abstract Map<Object, Object> getContextMapImpl();
-
-    public abstract AbstractMasterTimer getMasterTimerImpl();
-
-}
--- a/modules/base/src/main/java/com/sun/scenario/animation/AbstractMasterTimer.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,368 +0,0 @@
-/*
- * Copyright (c) 2007, 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 com.sun.scenario.animation;
-
-import java.util.Arrays;
-import javafx.animation.AnimationTimer;
-import javafx.util.Callback;
-import com.sun.javafx.animation.TickCalculation;
-import com.sun.scenario.DelayedRunnable;
-import com.sun.scenario.Settings;
-import com.sun.scenario.animation.shared.PulseReceiver;
-
-public abstract class AbstractMasterTimer {
-
-    // This PropertyChangeListener is added to Settings to listen for changes
-    // to the nogap and fullspeed properties.
-    private static Callback<String, Void> pcl = new Callback<String, Void>() {
-        public Void call(String key) {
-            switch (key) {
-                case FULLSPEED_PROP:
-                    fullspeed = Settings.getBoolean(FULLSPEED_PROP);
-                    break;
-                case ADAPTIVE_PULSE_PROP:
-                    useAdaptivePulse = Settings.getBoolean(ADAPTIVE_PULSE_PROP);
-                    break;
-                case ANIMATION_MBEAN_ENABLED:
-                    AnimationPulse.getDefaultBean()
-                                  .setEnabled(Settings.getBoolean(ANIMATION_MBEAN_ENABLED));
-                    break;
-            }
-            return null;
-        }
-    };
-    
-    protected final static String FULLSPEED_PROP = "javafx.animation.fullspeed";
-    private static boolean fullspeed = Settings.getBoolean(FULLSPEED_PROP);
-
-    // enables the code path which estimates the next pulse time to be just
-    // enough in advance of the vsync to complete rendering before it happens
-    protected final static String ADAPTIVE_PULSE_PROP = "com.sun.scenario.animation.adaptivepulse";
-    private static boolean useAdaptivePulse = Settings.getBoolean(ADAPTIVE_PULSE_PROP);
-
-    // another property which is controlling whether vsync is enabled:
-    // "com.sun.scenario.animation.vsync". if true, JSGPanel will enable vsync
-    // for the toplevel it's in. See JSGPanel.
-
-    // properties to override the default pulse rate (set in hz - number of
-    // pulses per second)
-    protected final static String PULSE_PROP = "javafx.animation.pulse";
-    protected final static String FRAMERATE_PROP = "javafx.animation.framerate";
-    protected final static String FIXED_PULSE_LENGTH_PROP = "com.sun.scenario.animation.fixed.pulse.length";
-
-    // property to enable AnimationPulse data gathering
-    // note: it can be enabled via the MBean itself too
-    protected final static String ANIMATION_MBEAN_ENABLED = "com.sun.scenario.animation.AnimationMBean.enabled";
-    protected final static boolean enableAnimationMBean = false;
-
-    private final int PULSE_DURATION_NS = getPulseDuration(1000000000);
-    private final int PULSE_DURATION_TICKS = getPulseDuration((int)TickCalculation.fromMillis(1000));
-
-    private boolean paused = false;
-    private long totalPausedTime;
-    private long startPauseTime;
-
-    // These methods only exist for the sake of testing.
-    boolean isPaused() { return paused; }
-    long getTotalPausedTime() { return totalPausedTime; }
-    long getStartPauseTime() { return startPauseTime; }
-
-    private PulseReceiver receivers[] = new PulseReceiver[2];
-    private int receiversLength;
-    private boolean receiversLocked;
-
-    // synchronize to update frameJobList and frameJobs
-    private AnimationTimer animationTimers[] = new AnimationTimer[2]; // frameJobList
-                                                                     // snapshot
-    private int animationTimersLength;
-    private boolean animationTimersLocked;
-    private final boolean shouldUseNanoTime;
-
-    // These two variables are ONLY USED if FIXED_PULSE_LENGTH_PROP is true. In this
-    // case, instead of advancing time based on the system time (nanos etc) we instead
-    // increment each animation by a fixed length of time for each pulse. This is
-    // handy while debugging.
-    private final long fixedPulseLength = Boolean.getBoolean(FIXED_PULSE_LENGTH_PROP) ? PULSE_DURATION_NS : 0;
-    private long debugNanos = 0;
-
-    private final MainLoop theMaster = new MainLoop();
-
-
-    static {
-        Settings.addPropertyChangeListener(pcl);
-        int pulse = Settings.getInt(PULSE_PROP, -1);
-        if (pulse != -1) {
-            System.err.println("Setting PULSE_DURATION to " + pulse + " hz");
-        }
-    }
-
-    // Used by Clip.create() method that doesn't take a resolution argument
-    public int getDefaultResolution() {
-        return PULSE_DURATION_TICKS;
-    }
-    
-    public void pause() {
-        if (!paused) {
-            startPauseTime = nanos();
-            paused = true;
-        }
-    }
-    
-    public void resume() {
-        if (paused) {
-            paused = false;
-            totalPausedTime += nanos() - startPauseTime;
-        }
-    }
-    
-    public long nanos() {
-        if (fixedPulseLength > 0) {
-            return debugNanos;
-        }
-
-        return paused ? startPauseTime :
-                (shouldUseNanoTime ?
-                        System.nanoTime() :
-                        System.currentTimeMillis() * 1000000) - totalPausedTime;
-    }
-
-    public boolean isFullspeed() {
-        return fullspeed;
-    }
-
-    /** Prevent external instantiation of MasterTimer. */
-    protected AbstractMasterTimer(boolean shouldUseNanoTime) {
-        this.shouldUseNanoTime = shouldUseNanoTime;
-    }
-    
-    /**
-     * Adds a PulseReceiver to the list of targets being tracked against the
-     * global schedule. The target should already have an absolute start time
-     * recorded in it and that time will be used to start the clip at the
-     * appropriate wall clock time as defined by milliTime().
-     * 
-     * Note that pulseReceiver cannot be removed from the MasterTimer directly.
-     * It is removed automatically in the timePulse-iteration if timePulse
-     * returns true.
-     * 
-     * @param target
-     *            the Clip to be added to the scheduling queue
-     */
-    public void addPulseReceiver(PulseReceiver target) {
-        boolean needMoreSize = receiversLength == receivers.length;
-        if (receiversLocked || needMoreSize) {
-            receivers = Arrays.copyOf(receivers, needMoreSize ? receivers.length * 3 / 2 + 1 : receivers.length);
-            receiversLocked = false;
-        }
-        receivers[receiversLength++] = target;
-        if (receiversLength == 1) {
-            theMaster.updateAnimationRunnable();
-        }
-    }
-
-    public void removePulseReceiver(PulseReceiver target) {
-        if (receiversLocked) { 
-            receivers = receivers.clone();
-            receiversLocked = false;
-        }
-        for (int i = 0; i < receiversLength; ++i) {
-            if (target == receivers[i]) {
-                if (i == receiversLength - 1) {
-                    receivers[i] = null;
-                } else {
-                    System.arraycopy(receivers, i + 1, receivers, i, receiversLength - i - 1);
-                }
-                --receiversLength;
-                break;
-            }
-        }
-        if (receiversLength == 0) {
-            theMaster.updateAnimationRunnable();
-        }
-    }
-
-    public void addAnimationTimer(AnimationTimer timer) {
-        boolean needMoreSize = animationTimersLength == animationTimers.length;
-        if (animationTimersLocked || needMoreSize) {
-            animationTimers = Arrays.copyOf(animationTimers, needMoreSize ? animationTimers.length * 3 / 2 + 1 : animationTimers.length);
-            animationTimersLocked = false;
-        }
-        animationTimers[animationTimersLength++] = timer;
-        if (animationTimersLength == 1) {
-            theMaster.updateAnimationRunnable();
-        }
-    }
-
-    public void removeAnimationTimer(AnimationTimer timer) {
-        if (animationTimersLocked) { 
-            animationTimers = animationTimers.clone();
-            animationTimersLocked = false;
-        }
-        for (int i = 0; i < animationTimersLength; ++i) {
-            if (timer == animationTimers[i]) {
-                if (i == animationTimersLength - 1) {
-                    animationTimers[i] = null;
-                } else {
-                    System.arraycopy(animationTimers, i + 1, animationTimers, i, animationTimersLength - i - 1);
-                }
-                --animationTimersLength;
-                break;
-            }
-        }
-        if (animationTimersLength == 0) {
-            theMaster.updateAnimationRunnable();
-        }
-    }
-
-    /*
-     * methods to record times for different stages of a pulse overriden in
-     * MasterTimer to collect data for AnimationPulse Mbean
-     */
-    protected void recordStart(long shiftMillis) {
-    }
-
-    protected void recordEnd() {
-    }
-
-    protected void recordAnimationEnd() {
-    }
-
-    /**
-     * Hidden inner class to run the main timing loop. This is the
-     * "AnimationRunnable" for Desktop and TV
-     */
-    private final class MainLoop implements DelayedRunnable {
-
-        private boolean inactive = true;
-        
-        private long nextPulseTime = nanos();
-        private long lastPulseDuration = Integer.MIN_VALUE;
-
-        @Override
-        public void run() {
-            if (paused) {
-                return;
-            }
-            final long now = nanos();
-            recordStart((nextPulseTime - now) / 1000000);
-            timePulseImpl(now);
-            recordEnd();
-            updateNextPulseTime(now);
-            // reschedule animation runnable if needed
-            updateAnimationRunnable();
-        }
-
-        @Override
-        public long getDelay() {
-            final long now = nanos();
-            final long timeUntilPulse = (nextPulseTime - now) / 1000000;
-            return Math.max(0, timeUntilPulse);
-        }
-
-        private void updateNextPulseTime(long pulseStarted) {
-            final long now = nanos();
-            if (fullspeed) {
-                nextPulseTime = now;
-            } else {
-                if (useAdaptivePulse) {
-                    // Estimate the next pulse time such that we wake up just
-                    // early enough to finish up the painting and call swap
-                    // before vsync happens. We try to minimize the amount of
-                    // time we wait for vsync blocking the EDT thread.
-                    nextPulseTime += PULSE_DURATION_NS;
-                    long pulseDuration = now - pulseStarted;
-                    // if the new duration was smaller than the previous one
-                    // we don't need to do anything (we have decreased the
-                    // duration), but if it's longer to within 1/2ms then we
-                    // try to halve the next anticipated duration (but not
-                    // closer
-                    // than 2ms within the next expected pulse)
-                    if (pulseDuration - lastPulseDuration > 500000) {
-                        pulseDuration /= 2;
-                    }
-                    if (pulseDuration < 2000000) {
-                        pulseDuration = 2000000;
-                    }
-                    // if the pulse took longer than pulse_duration_ns we
-                    // probably missed the vsync
-                    if (pulseDuration >= PULSE_DURATION_NS) {
-                        pulseDuration = 3 * PULSE_DURATION_NS / 4;
-                    }
-                    lastPulseDuration = pulseDuration;
-                    nextPulseTime = nextPulseTime - pulseDuration;
-                } else {
-                    nextPulseTime = ((nextPulseTime + PULSE_DURATION_NS) / PULSE_DURATION_NS)
-                            * PULSE_DURATION_NS;
-                }
-            }
-        }
-
-        private void updateAnimationRunnable() {
-            final boolean newInactive = (animationTimersLength == 0 && receiversLength == 0);
-            if (inactive != newInactive) {
-                inactive = newInactive;
-                final DelayedRunnable animationRunnable = inactive? null : this;
-                postUpdateAnimationRunnable(animationRunnable);
-            }
-        }
-    }
-
-    protected abstract void postUpdateAnimationRunnable(
-            DelayedRunnable animationRunnable);
-
-    protected abstract int getPulseDuration(int precision);
-
-    protected void timePulseImpl(long now) {
-        if (fixedPulseLength > 0) {
-            debugNanos += fixedPulseLength;
-            now = debugNanos;
-        }
-        final PulseReceiver receiversSnapshot[] = receivers;
-        final int rLength = receiversLength;
-        try {
-            receiversLocked = true;
-            for (int i = 0; i < rLength; i++) {
-                receiversSnapshot[i].timePulse(TickCalculation.fromNano(now));
-            }
-        } finally {
-            receiversLocked = false;
-        }
-        recordAnimationEnd();
-
-        final AnimationTimer animationTimersSnapshot[] = animationTimers;
-        final int aTLength = animationTimersLength;
-        try {
-            animationTimersLocked = true;
-            // After every frame, call any frame jobs
-            for (int i = 0; i < aTLength; i++) {
-                animationTimersSnapshot[i].handle(now);
-            }
-        } finally {
-            animationTimersLocked = false;
-        }
-    }
-
-}
--- a/modules/base/src/main/java/com/sun/scenario/animation/AnimationPulse.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,474 +0,0 @@
-/*
- * Copyright (c) 2007, 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 com.sun.scenario.animation;
-
-import java.util.Iterator;
-import java.util.Queue;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicLong;
-
-import com.sun.scenario.ToolkitAccessor;
-
-
-public class AnimationPulse implements AnimationPulseMBean {
-    public static AnimationPulse getDefaultBean() {
-        return AnimationPulseHolder.holder;
-    }
-    private static class AnimationPulseHolder {
-        private static final AnimationPulse holder = new AnimationPulse();
-    }
-    
-    private static class PulseData {
-        private final long startNanos;
-        private final long scheduledNanos;
-        
-        private long animationEndNanos = Long.MIN_VALUE;
-        private long paintingStartNanos = Long.MIN_VALUE;
-        private long paintingEndNanos = Long.MIN_VALUE;
-        private long scenePaintingStartNanos = Long.MIN_VALUE;
-        private long scenePaintingEndNanos = Long.MIN_VALUE;
-        private long endNanos = Long.MIN_VALUE;
-        
-        PulseData(long shiftNanos) {
-            startNanos = ToolkitAccessor.getMasterTimer().nanos();
-            scheduledNanos = startNanos + shiftNanos;
-        }
-        
-        //time from the scheduledNanos  
-        long getPulseStart(TimeUnit unit) {
-            return unit.convert(startNanos - scheduledNanos, TimeUnit.NANOSECONDS);            
-        }
-        
-        void recordAnimationEnd() {
-            animationEndNanos = ToolkitAccessor.getMasterTimer().nanos();
-        }
-        
-        long getAnimationDuration(TimeUnit unit) {
-            return (animationEndNanos > Long.MIN_VALUE) 
-              ? unit.convert(animationEndNanos - startNanos, TimeUnit.NANOSECONDS)
-              : 0;
-        }
-        
-        long getPaintingDuration(TimeUnit unit) {
-            return (paintingEndNanos > Long.MIN_VALUE && paintingStartNanos > Long.MIN_VALUE) 
-              ? unit.convert(paintingEndNanos - paintingStartNanos, TimeUnit.NANOSECONDS)
-              : 0;
-        }
-        
-        long getScenePaintingDuration(TimeUnit unit) {
-            return (scenePaintingEndNanos > Long.MIN_VALUE && scenePaintingStartNanos > Long.MIN_VALUE) 
-              ? unit.convert(scenePaintingEndNanos - scenePaintingStartNanos, TimeUnit.NANOSECONDS)
-              : 0;
-        }
-        
-        long getPaintingFinalizationDuration(TimeUnit unit) {
-            return (scenePaintingEndNanos > Long.MIN_VALUE && paintingEndNanos > Long.MIN_VALUE) 
-              ? unit.convert(paintingEndNanos - scenePaintingEndNanos, TimeUnit.NANOSECONDS)
-              : 0;
-        }
-        
-        void recordEnd() {
-            endNanos = ToolkitAccessor.getMasterTimer().nanos();
-        }
-        
-        long getPulseDuration(TimeUnit unit) {
-            return unit.convert(endNanos - startNanos, TimeUnit.NANOSECONDS);
-        }
-        
-        //time from the scheduledNanos        
-        long getPulseEnd(TimeUnit unit) {
-            return unit
-                    .convert(endNanos - scheduledNanos, TimeUnit.NANOSECONDS);
-        }
-        
-        long getPulseStartFromNow(TimeUnit unit) {
-            return unit.convert(ToolkitAccessor.getMasterTimer().nanos() - startNanos,
-                    TimeUnit.NANOSECONDS);
-        }
-        
-        long getSkippedPulses() {
-            return getPulseEnd(TimeUnit.MILLISECONDS) 
-              / AnimationPulse.getDefaultBean().getPULSE_DURATION();
-        }
-        
-        static interface Accessor {
-            public long get(PulseData pulseData, TimeUnit unit);
-        }
-        
-        static final Accessor PulseStartAccessor = new Accessor() {
-            @Override
-            public long get(PulseData pulseData, TimeUnit unit) {
-                return pulseData.getPulseStart(unit);
-            }
-        };
-        
-        static final Accessor AnimationDurationAccessor = new Accessor() {
-            @Override
-            public long get(PulseData pulseData, TimeUnit unit) {
-                return pulseData.getAnimationDuration(unit);
-            }
-        };
-        
-        static final Accessor PaintingDurationAccessor = new Accessor() {
-            @Override
-            public long get(PulseData pulseData, TimeUnit unit) {
-                return pulseData.getPaintingDuration(unit);
-            }
-        };
-        
-        static final Accessor ScenePaintingDurationAccessor = new Accessor() {
-            @Override
-            public long get(PulseData pulseData, TimeUnit unit) {
-                return pulseData.getScenePaintingDuration(unit);
-            }
-        };
-        
-        static final Accessor PulseDurationAccessor = new Accessor() {
-            @Override
-            public long get(PulseData pulseData, TimeUnit unit) {
-               return pulseData.getPulseDuration(unit);
-            }  
-        };
-        
-        static final Accessor PulseEndAccessor = new Accessor() {
-            @Override
-            public long get(PulseData pulseData, TimeUnit unit) {
-               return pulseData.getPulseEnd(unit);
-            }  
-        };
-        
-        static final Accessor PaintingPreparationDuration = new Accessor() {
-            @Override
-            public long get(PulseData pulseData, TimeUnit unit) {
-               return pulseData.getPaintingDuration(unit);
-            }  
-        };
-        
-        static final Accessor PaintingFinalizationDuration = new Accessor() {
-            @Override
-            public long get(PulseData pulseData, TimeUnit unit) {
-               return pulseData.getPaintingFinalizationDuration(unit);
-            }  
-        };
-        
-//        @Override
-//        public String toString() {
-//            StringBuilder sb = new StringBuilder(super.toString());
-//            TimeUnit unit = TimeUnit.MILLISECONDS;
-//            sb.append(" start: ").append(getPulseStart(unit))
-//            .append(" animation: ").append(getAnimationDuration(unit))
-//            .append(" painting: ").append(getPaintingDuration(unit))
-//            .append(" pulseDuration: ").append(getPulseDuration(unit))
-//            .append(" pulseEnd: ").append(getPulseEnd(unit));
-//            return sb.toString();
-//        }
-    }
-    
-    private final Queue<PulseData> pulseDataQueue = new ConcurrentLinkedQueue<>();
-    
-    //to be accessed from the EDT
-    private PulseData pulseData = null;
-    
-    
-
-    private volatile boolean isEnabled = false; 
-    @Override
-    public boolean getEnabled() {
-        return isEnabled;
-    }
-    
-    @Override
-    public void setEnabled(boolean enabled) {
-        if (enabled == isEnabled) {
-            return;
-        }
-        isEnabled = enabled;
-        //we may want to clean the state on setEanbled(false)
-    }
-    
-    @Override
-    public long getPULSE_DURATION() {
-        return ToolkitAccessor.getMasterTimer().getPulseDuration(1000);
-    }
-    
-    
-    @Override
-    public long getSkippedPulses() {
-        return skippedPulses.get();
-    }
-    
-    @Override
-    public long getSkippedPulsesIn1Sec() {
-        long rv = 0;
-        for (PulseData pulseData : pulseDataQueue) {
-            if (pulseData.getPulseStartFromNow(TimeUnit.SECONDS) == 0) {
-                rv += pulseData.getSkippedPulses();
-            }
-        }
-        return rv;
-    }
-     
-    
-    public void recordStart(long shiftMillis) {
-        if (! getEnabled()) {
-            return;
-        }
-        pulseData = new PulseData(TimeUnit.MILLISECONDS.toNanos(shiftMillis));
-    }
-
-    // cleans items older than 1sec from the queue
-    private void purgeOldPulseData() {
-        Iterator<PulseData> iterator = pulseDataQueue.iterator();
-        while (iterator.hasNext() 
-                && iterator.next().getPulseStartFromNow(TimeUnit.SECONDS) > 1) {
-            iterator.remove();
-        }
-    }
-
-    private final AtomicLong pulseCounter = new AtomicLong();
-    
-    private final AtomicLong startMax = new AtomicLong();
-    private final AtomicLong startSum = new AtomicLong();
-    private final AtomicLong startAv = new AtomicLong();
-    
-    private final AtomicLong endMax = new AtomicLong();
-    private final AtomicLong endSum = new AtomicLong();
-    private final AtomicLong endAv = new AtomicLong();
-    
-    private final AtomicLong animationDurationMax = new AtomicLong(); 
-    private final AtomicLong animationDurationSum = new AtomicLong();
-    private final AtomicLong animationDurationAv = new AtomicLong();
-    
-    private final AtomicLong paintingDurationMax = new AtomicLong();
-    private final AtomicLong paintingDurationSum = new AtomicLong();
-    private final AtomicLong paintingDurationAv = new AtomicLong();
-    
-    private final AtomicLong pulseDurationMax = new AtomicLong();
-    private final AtomicLong pulseDurationSum = new AtomicLong();
-    private final AtomicLong pulseDurationAv = new AtomicLong();
-    
-    private final AtomicLong[] maxAndAv = new AtomicLong[] {
-            startMax, startSum, startAv,
-            endMax, endSum, endAv,
-            animationDurationMax, animationDurationSum, animationDurationAv,
-            paintingDurationMax, paintingDurationSum, paintingDurationAv,
-            pulseDurationMax, pulseDurationSum, pulseDurationAv
-    };
-    private final PulseData.Accessor[] maxAndAvAccessors = new PulseData.Accessor[] {
-            PulseData.PulseStartAccessor,
-            PulseData.PulseEndAccessor,
-            PulseData.AnimationDurationAccessor,
-            PulseData.PaintingDurationAccessor,
-            PulseData.PulseDurationAccessor
-    };
-    
-    private void updateMaxAndAv() {
-        long pulseCounterLong = pulseCounter.incrementAndGet();
-        for (int i = 0; i < maxAndAvAccessors.length; i++) {
-            int j = i * 3;
-            long tmpLong = maxAndAvAccessors[i].get(pulseData, TimeUnit.MILLISECONDS);
-            maxAndAv[j].set(Math.max(maxAndAv[j].get(), tmpLong));
-            maxAndAv[j + 1].addAndGet(tmpLong);
-            maxAndAv[j + 2].set(maxAndAv[j + 1].get() / pulseCounterLong);
-        }
-    }
-    
-    private final AtomicLong skippedPulses = new AtomicLong();
-    
-    private int skipPulses = 100;
-    public void recordEnd() {
-        if (! getEnabled()) {
-            return;
-        }
-        if (skipPulses > 0) {
-            //do not gather data for the first 'skipPulses' pulses
-            //let the application to warm up
-            skipPulses--;
-            pulseData = null;
-            return;
-        }
-        pulseData.recordEnd();
-        purgeOldPulseData();
-        updateMaxAndAv();
-        skippedPulses.addAndGet(pulseData.getSkippedPulses());
-        pulseDataQueue.add(pulseData);
-        pulseData = null;
-    }
-
-    /* 
-     * implementation detail: I wish we had deque in 1.5 but we do not so here we 
-     * iterate over the whole thing.
-     */
-    private long getAv(PulseData.Accessor accessor, long timeOut, TimeUnit unit) {
-        if (! getEnabled()) {
-            return 0;
-        }
-        long time = 0;
-        long items = 0;
-        for (PulseData currentPulseData : pulseDataQueue) {
-            if (currentPulseData.getPulseStartFromNow(unit) <= timeOut) {
-                time += accessor.get(currentPulseData, unit);
-                items++;
-            }
-        }
-        return (items == 0) ? 0 : time / items;
-    }
-    
-    private long getMax(PulseData.Accessor accessor, long timeOut, TimeUnit unit) {
-        if (! getEnabled()) {
-            return 0;
-        }
-        long max = 0;
-        for (PulseData currentPulseData : pulseDataQueue) {
-            if (currentPulseData.getPulseStartFromNow(unit) <= timeOut) {
-                max = Math.max(accessor.get(currentPulseData, unit), max);
-            }
-        }
-        return max;
-    }
-    
-    @Override
-    public long getStartMax() {
-        return startMax.get();
-    }
-    
-    @Override
-    public long getStartAv() {
-        return startAv.get();
-    }
-    
-    @Override
-    public long getStartMaxIn1Sec() {
-        return getMax(PulseData.PulseStartAccessor, 1000, TimeUnit.MILLISECONDS);
-    }
-    
-    @Override
-    public long getStartAvIn100Millis() {
-        return getAv(PulseData.PulseStartAccessor, 100, TimeUnit.MILLISECONDS);
-    }
-    
-    @Override
-    public long getEndMax() {
-        return endMax.get();
-    }
-    
-    @Override
-    public long getEndMaxIn1Sec() {
-        return getMax(PulseData.PulseEndAccessor, 1000, TimeUnit.MILLISECONDS);
-    }
-    
-    @Override
-    public long getEndAv() {
-        return endAv.get();
-    }
-    
-    @Override
-    public long getEndAvIn100Millis() {
-        return getAv(PulseData.PulseEndAccessor, 100, TimeUnit.MILLISECONDS);
-    }
-    
-    public void recordAnimationEnd() {
-        if (getEnabled() && pulseData != null) {
-            pulseData.recordAnimationEnd();
-        }
-    }
-    
-    @Override
-    public long getAnimationDurationMax() {
-        return animationDurationMax.get();
-    }
-    
-    @Override
-    public long getAnimationMaxIn1Sec() {
-        return getMax(PulseData.AnimationDurationAccessor, 1000, TimeUnit.MILLISECONDS);
-    }
-    
-    @Override
-    public long getAnimationDurationAv() {
-        return animationDurationAv.get();
-    }
-    
-    @Override
-    public long getAnimationDurationAvIn100Millis() {
-        return getAv(PulseData.AnimationDurationAccessor, 100, TimeUnit.MILLISECONDS);
-    }
-    
-    @Override
-    public long getPaintingDurationMax() {
-        return paintingDurationMax.get();
-    }
-    
-    @Override
-    public long getPaintingDurationMaxIn1Sec() {
-        return getMax(PulseData.PaintingDurationAccessor, 1000, TimeUnit.MILLISECONDS);
-    }
-    
-    @Override
-    public long getPaintingDurationAv() {
-        return paintingDurationAv.get();
-    }
-    
-    @Override
-    public long getPaintingDurationAvIn100Millis() {
-        return getAv(PulseData.PaintingDurationAccessor, 100, TimeUnit.MILLISECONDS);
-    }
-    
-    @Override
-    public long getScenePaintingDurationMaxIn1Sec() {
-        return getMax(PulseData.ScenePaintingDurationAccessor, 1000, TimeUnit.MILLISECONDS);
-    }
-    
-    @Override
-    public long getPulseDurationMax() {
-        return pulseDurationMax.get();
-    }
-    
-    @Override
-    public long getPulseDurationMaxIn1Sec() {
-        return getMax(PulseData.PulseDurationAccessor, 1000, TimeUnit.MILLISECONDS);
-    }
-    
-    @Override
-    public long getPulseDurationAv() {
-        return pulseDurationAv.get();
-    }
-    
-    @Override
-    public long getPulseDurationAvIn100Millis() {
-        return getAv(PulseData.PulseDurationAccessor, 100, TimeUnit.MILLISECONDS);
-    }
-    
-    @Override
-    public long getPaintingPreparationDurationMaxIn1Sec() {
-        return getMax(PulseData.PaintingPreparationDuration, 1000, TimeUnit.MILLISECONDS);    
-    }
-    
-    @Override
-    public long getPaintingFinalizationDurationMaxIn1Sec() {
-        return getMax(PulseData.PaintingFinalizationDuration, 1000, TimeUnit.MILLISECONDS);
-    }
-}
--- a/modules/base/src/main/java/com/sun/scenario/animation/AnimationPulseMBean.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2007, 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 com.sun.scenario.animation;
-
-public interface AnimationPulseMBean {
-    public boolean getEnabled();
-
-    public void setEnabled(boolean enabled);
-
-    // we are using millis as time units here
-
-    public long getPULSE_DURATION();
-
-    public long getSkippedPulses();
-
-    public long getSkippedPulsesIn1Sec();
-
-    // from the scheduled time
-    public long getStartMax();
-
-    public long getStartMaxIn1Sec();
-
-    public long getStartAv();
-
-    public long getStartAvIn100Millis();
-
-    public long getEndMax();
-
-    public long getEndMaxIn1Sec();
-
-    public long getEndAv();
-
-    public long getEndAvIn100Millis();
-
-    public long getAnimationDurationMax();
-
-    public long getAnimationMaxIn1Sec();
-
-    public long getAnimationDurationAv();
-
-    public long getAnimationDurationAvIn100Millis();
-
-    public long getPaintingDurationMax();
-
-    public long getPaintingDurationMaxIn1Sec();
-
-    public long getPaintingDurationAv();
-
-    public long getPaintingDurationAvIn100Millis();
-
-    public long getScenePaintingDurationMaxIn1Sec();
-
-    public long getPaintingPreparationDurationMaxIn1Sec();
-
-    public long getPaintingFinalizationDurationMaxIn1Sec();
-
-    public long getPulseDurationMax();
-
-    public long getPulseDurationMaxIn1Sec();
-
-    public long getPulseDurationAv();
-
-    public long getPulseDurationAvIn100Millis();
-}
--- a/modules/base/src/main/java/com/sun/scenario/animation/NumberTangentInterpolator.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,105 +0,0 @@
-/*
- * Copyright (c) 2011, 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 com.sun.scenario.animation;
-
-import com.sun.javafx.animation.TickCalculation;
-import javafx.animation.Interpolator;
-import javafx.util.Duration;
-
-public class NumberTangentInterpolator extends Interpolator {
-
-    private final double inValue, outValue;
-    private final long inTicks, outTicks;
-
-    public double getInValue() { return inValue; }
-
-    public double getOutValue() { return outValue; }
-
-    public double getInTicks() { return inTicks; }
-
-    public double getOutTicks() { return outTicks; }
-
-    public NumberTangentInterpolator(Duration inDuration, double inValue, Duration outDuration, double outValue) {
-        this.inTicks = TickCalculation.fromDuration(inDuration);
-        this.inValue = inValue;
-        this.outTicks = TickCalculation.fromDuration(outDuration);
-        this.outValue = outValue;
-    }
-
-    public NumberTangentInterpolator(Duration duration, double value) {
-        this.outTicks = this.inTicks = TickCalculation.fromDuration(duration);
-        this.inValue = this.outValue = value;
-    }
-
-    @Override
-    public String toString() {
-        return "NumberTangentInterpolator [inValue=" + inValue
-                + ", inDuration=" + TickCalculation.toDuration(inTicks) + ", outValue="
-                + outValue + ", outDuration=" + TickCalculation.toDuration(outTicks) + "]";
-    }
-
-    @Override
-    public int hashCode() {
-        int hash = 7;
-        hash = 59 * hash + (int) (Double.doubleToLongBits(this.inValue) ^ (Double.doubleToLongBits(this.inValue) >>> 32));
-        hash = 59 * hash + (int) (Double.doubleToLongBits(this.outValue) ^ (Double.doubleToLongBits(this.outValue) >>> 32));
-        hash = 59 * hash + (int) (this.inTicks ^ (this.inTicks >>> 32));
-        hash = 59 * hash + (int) (this.outTicks ^ (this.outTicks >>> 32));
-        return hash;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == null) {
-            return false;
-        }
-        if (getClass() != obj.getClass()) {
-            return false;
-        }
-        final NumberTangentInterpolator other = (NumberTangentInterpolator) obj;
-        if (Double.doubleToLongBits(this.inValue) != Double.doubleToLongBits(other.inValue)) {
-            return false;
-        }
-        if (Double.doubleToLongBits(this.outValue) != Double.doubleToLongBits(other.outValue)) {
-            return false;
-        }
-        if (this.inTicks != other.inTicks) {
-            return false;
-        }
-        if (this.outTicks != other.outTicks) {
-            return false;
-        }
-        return true;
-    }
-
-    @Override
-    protected double curve(double t) {
-        // Fallback: If NumberTangentInterpolator is used with a target, that is
-        // not a number,
-        // it behaves like linear interpolation.
-        return t;
-    }
-}
--- a/modules/base/src/main/java/com/sun/scenario/animation/SplineInterpolator.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,320 +0,0 @@
-/*
- * Copyright (c) 2011, 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 com.sun.scenario.animation;
-
-import javafx.animation.Interpolator;
-
-/**
- * An implementation of a spline interpolator for temporal interpolation that
- * tries to follow the specification referenced by:
- * http://www.w3.org/TR/SMIL/animation.html#animationNS-OverviewSpline .
- * <p>
- * Basically, a cubic Bezier curve is created with start point (0,0) and
- * endpoint (1,1). The other two control points (px1, py1) and (px2, py2) are
- * given by the user, where px1, py1, px1, and px2 are all in the range [0,1]. A
- * property of this specially constrained Bezier curve is that it is strictly
- * monotonically increasing in both X and Y with t in range [0,1].
- * <p>
- * The interpolator works by giving it a value for X. It then finds what
- * parameter t would generate this X value for the curve. Then this t parameter
- * is applied to the curve to solve for Y. As X increases from 0 to 1, t also
- * increases from 0 to 1, and correspondingly Y increases from 0 to 1. The
- * X-to-Y mapping is not a function of path/curve length.
- * 
- */
-public class SplineInterpolator extends Interpolator {
-
-    /**
-     * The coordinates of the 2 2D control points for a cubic Bezier curve, with
-     * implicit start point (0,0) and end point (1,1) -- each individual
-     * coordinate value must be in range [0,1].
-     */
-    private final double x1, y1, x2, y2;
-
-    /**
-     * Do the input control points form a line with (0,0) and (1,1), i.e., x1 ==
-     * y1 and x2 == y2 -- if so, then all x(t) == y(t) for the curve.
-     */
-    private final boolean isCurveLinear;
-
-    /**
-     * Power of 2 sample size for lookup table of x values.
-     */
-    private static final int SAMPLE_SIZE = 16;
-
-    /**
-     * Difference in t used to calculate each of the xSamples values -- power of
-     * 2 sample size should provide exact representation of this value and its
-     * integer multiples (integer in range of [0..SAMPLE_SIZE].
-     */
-    private static final double SAMPLE_INCREMENT = 1.0 / SAMPLE_SIZE;
-
-    /**
-     * X values for the bezier curve, sampled at increments of 1/SAMPLE_SIZE --
-     * this is used to find the good initial guess for parameter t, given an x.
-     */
-    private final double[] xSamples = new double[SAMPLE_SIZE + 1];
-
-    /**
-     * Creates a new instance with control points (0,0) (px1,py1) (px2,py2)
-     * (1,1) -- px1, py1, px2, py2 all in range [0,1].
-     * 
-     * @param px1
-     *            X coordinate of first control point, in range [0,1]
-     * @param py1
-     *            Y coordinate of first control point, in range [0,1]
-     * @param px2
-     *            X coordinate of second control point, in range [0,1]
-     * @param py2
-     *            Y coordinate of second control point, in range [0,1]
-     */
-    public SplineInterpolator(double px1, double py1, double px2, double py2) {
-        // check user input for precondition
-        if (px1 < 0 || px1 > 1 || py1 < 0 || py1 > 1 || px2 < 0 || px2 > 1
-                || py2 < 0 || py2 > 1) {
-            throw new IllegalArgumentException(
-                    "Control point coordinates must " + "all be in range [0,1]");
-        }
-
-        // save control point data
-        this.x1 = px1;
-        this.y1 = py1;
-        this.x2 = px2;
-        this.y2 = py2;
-
-        // calc linearity/identity curve
-        isCurveLinear = ((x1 == y1) && (x2 == y2));
-
-        // make the array of x value samples
-        if (!isCurveLinear) {
-            for (int i = 0; i < SAMPLE_SIZE + 1; ++i) {
-                xSamples[i] = eval(i * SAMPLE_INCREMENT, x1, x2);
-            }
-        }
-    }
-
-    public double getX1() {
-        return x1;
-    }
-
-    public double getY1() {
-        return y1;
-    }
-
-    public double getX2() {
-        return x2;
-    }
-
-    public double getY2() {
-        return y2;
-    }
-
-    @Override
-    public int hashCode() {
-        int hash = 7;
-        hash = 19 * hash + (int) (Double.doubleToLongBits(this.x1) ^ (Double.doubleToLongBits(this.x1) >>> 32));
-        hash = 19 * hash + (int) (Double.doubleToLongBits(this.y1) ^ (Double.doubleToLongBits(this.y1) >>> 32));
-        hash = 19 * hash + (int) (Double.doubleToLongBits(this.x2) ^ (Double.doubleToLongBits(this.x2) >>> 32));
-        hash = 19 * hash + (int) (Double.doubleToLongBits(this.y2) ^ (Double.doubleToLongBits(this.y2) >>> 32));
-        return hash;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == null) {
-            return false;
-        }
-        if (getClass() != obj.getClass()) {
-            return false;
-        }
-        final SplineInterpolator other = (SplineInterpolator) obj;
-        if (Double.doubleToLongBits(this.x1) != Double.doubleToLongBits(other.x1)) {
-            return false;
-        }
-        if (Double.doubleToLongBits(this.y1) != Double.doubleToLongBits(other.y1)) {
-            return false;
-        }
-        if (Double.doubleToLongBits(this.x2) != Double.doubleToLongBits(other.x2)) {
-            return false;
-        }
-        if (Double.doubleToLongBits(this.y2) != Double.doubleToLongBits(other.y2)) {
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Returns the y-value of the cubic bezier curve that corresponds to the x
-     * input.
-     * 
-     * @param x
-     *            is x-value of cubic bezier curve, in range [0,1]
-     * @return corresponding y-value of cubic bezier curve -- in range [0,1]
-     */
-    @Override
-    public double curve(double x) {
-        // check user input for precondition
-        if (x < 0 || x > 1) {
-            throw new IllegalArgumentException("x must be in range [0,1]");
-        }
-
-        // check quick exit identity cases (linear curve or curve endpoints)
-        if (isCurveLinear || x == 0 || x == 1) {
-            return x;
-        }
-
-        // find the t parameter for a given x value, and use this t to calculate
-        // the corresponding y value
-        return eval(findTForX(x), y1, y2);
-    }
-
-    /**
-     * Use Bernstein basis to evaluate 1D cubic Bezier curve (quicker and more
-     * numerically stable than power basis) -- 1D control coordinates are (0,
-     * p1, p2, 1), where p1 and p2 are in range [0,1], and there is no ordering
-     * constraint on p1 and p2, i.e., p1 &lt;= p2 does not have to be true.
-     * 
-     * @param t
-     *            is the paramaterized value in range [0,1]
-     * @param p1
-     *            is 1st control point coordinate in range [0,1]
-     * @param p2
-     *            is 2nd control point coordinate in range [0,1]
-     * @return the value of the Bezier curve at parameter t
-     */
-    private double eval(double t, double p1, double p2) {
-        // Use optimized version of the normal Bernstein basis form of Bezier:
-        // (3*(1-t)*(1-t)*t*p1)+(3*(1-t)*t*t*p2)+(t*t*t), since p0=0, p3=1.
-        // The above unoptimized version is best using -server, but since we
-        // are probably doing client-side animation, this is faster.
-        double compT = 1 - t;
-        return t * (3 * compT * (compT * p1 + t * p2) + (t * t));
-    }
-
-    /**
-     * Evaluates Bernstein basis derivative of 1D cubic Bezier curve, where 1D
-     * control points are (0, p1, p2, 1), where p1 and p2 are in range [0,1],
-     * and there is no ordering constraint on p1 and p2, i.e., p1 &lt;= p2 does
-     * not have to be true.
-     * 
-     * @param t
-     *            is the paramaterized value in range [0,1]
-     * @param p1
-     *            is 1st control point coordinate in range [0,1]
-     * @param p2
-     *            is 2nd control point coordinate in range [0,1]
-     * @return the value of the Bezier curve at parameter t
-     */
-    private double evalDerivative(double t, double p1, double p2) {
-        // use optimized version of Berstein basis Bezier derivative:
-        // (3*(1-t)*(1-t)*p1)+(6*(1-t)*t*(p2-p1))+(3*t*t*(1-p2)), since
-        // p0=0 and p3=1. The above unoptimized version is best using -server,
-        // but since we are probably doing client-side animation, this is
-        // faster.
-        double compT = 1 - t;
-        return 3 * (compT * (compT * p1 + 2 * t * (p2 - p1)) + t * t * (1 - p2));
-    }
-
-    /**
-     * Find an initial good guess for what parameter t might produce the x-value
-     * on the Bezier curve -- uses linear interpolation on the x-value sample
-     * array that was created on construction.
-     * 
-     * @param x
-     *            is x-value of cubic bezier curve, in range [0,1]
-     * @return a good initial guess for parameter t (in range [0,1]) that gives
-     *         x
-     */
-    private double getInitialGuessForT(double x) {
-        // find which places in the array that x would be sandwiched between,
-        // and then linearly interpolate a reasonable value of t -- array values
-        // are ascending (or at least never descending) -- binary search is
-        // probably more trouble than it is worth here
-        for (int i = 1; i < SAMPLE_SIZE + 1; ++i) {
-            if (xSamples[i] >= x) {
-                double xRange = xSamples[i] - xSamples[i - 1];
-                if (xRange == 0) {
-                    // no change in value between samples, so use earlier time
-                    return (i - 1) * SAMPLE_INCREMENT;
-                } else {
-                    // linearly interpolate the time value
-                    return ((i - 1) + ((x - xSamples[i - 1]) / xRange))
-                            * SAMPLE_INCREMENT;
-                }
-            }
-        }
-
-        // shouldn't get here since 0 <= x <= 1, and xSamples[0] == 0 and
-        // xSamples[SAMPLE_SIZE] == 1 (using power of 2 SAMPLE_SIZE for more
-        // exact increment arithmetic)
-        return 1;
-    }
-
-    /**
-     * Finds the parameter t that produces the given x-value for the curve --
-     * uses Newton-Raphson to refine the value as opposed to subdividing until
-     * we are within some tolerance.
-     * 
-     * @param x
-     *            is x-value of cubic bezier curve, in range [0,1]
-     * @return the parameter t (in range [0,1]) that produces x
-     */
-    private double findTForX(double x) {
-        // get an initial good guess for t
-        double t = getInitialGuessForT(x);
-
-        // use Newton-Raphson to refine the value for t -- for this constrained
-        // Bezier with float accuracy (7 digits), any value not converged by 4
-        // iterations is cycling between values, which can minutely affect the
-        // accuracy of the last digit
-        final int numIterations = 4;
-        for (int i = 0; i < numIterations; ++i) {
-            // stop if this value of t gives us exactly x
-            double xT = (eval(t, x1, x2) - x);
-            if (xT == 0) {
-                break;
-            }
-
-            // stop if derivative is 0
-            double dXdT = evalDerivative(t, x1, x2);
-            if (dXdT == 0) {
-                break;
-            }
-
-            // refine t
-            t -= xT / dXdT;
-        }
-
-        return t;
-    }
-
-    @Override
-    public String toString() {
-        return "SplineInterpolator [x1=" + x1 + ", y1=" + y1 + ", x2=" + x2
-                + ", y2=" + y2 + "]";
-    }
-
-}
--- a/modules/base/src/main/java/com/sun/scenario/animation/shared/AnimationAccessor.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2011, 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 com.sun.scenario.animation.shared;
-
-import javafx.animation.Animation;
-
-public abstract class AnimationAccessor {
- public static AnimationAccessor DEFAULT;
-
-    public static AnimationAccessor getDefault() {
-        if (DEFAULT != null) {
-            return DEFAULT;
-        }
-
-        // invokes static initializer of Animation.class
-        // that will assign value to the DEFAULT field above
-        Class c = Animation.class;
-        try {
-            Class.forName(c.getName());
-        } catch (ClassNotFoundException ex) {
-            assert false : ex;
-        }
-        assert DEFAULT != null : "The DEFAULT field must be initialized";
-        return DEFAULT;
-    }
-
-    public abstract void setCurrentRate(Animation animation, double currentRate);
-
-    public abstract void setCurrentTicks(Animation animation, long ticks);
-
-    public abstract void playTo(Animation animation, long pos, long cycleTicks);
-
-    public abstract void jumpTo(Animation animation, long pos, long cycleTicks, boolean forceJump);
-
-    public abstract void finished(Animation animation);
-
-
-}
--- a/modules/base/src/main/java/com/sun/scenario/animation/shared/ClipEnvelope.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,125 +0,0 @@
-/*
- * Copyright (c) 2008, 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 com.sun.scenario.animation.shared;
-
-import javafx.animation.Animation;
-import javafx.util.Duration;
-import com.sun.javafx.animation.TickCalculation;
-
-/**
- * An instance of ClipEnvelope handles the loop-part of a clip.
- * 
- * The functionality to react on a pulse-signal from the timer is implemented in
- * two classes: ClipEnvelope and ClipCore. ClipEnvelope is responsible for the
- * "loop-part" (keeping track of the number of cycles, handling the direction of
- * the clip etc.). ClipCore takes care of the inner part (interpolating the
- * values, triggering the action-functions, ...)
- * 
- * Both classes have an abstract public definition and can only be created using
- * the factory method create(). The intent is to provide a general
- * implementation plus eventually some fast-track implementations for common use
- * cases.
- */
-
-public abstract class ClipEnvelope {
-
-    protected static final long INDEFINITE = Long.MAX_VALUE;
-    protected static final double EPSILON = 1e-12;
-
-    protected Animation animation;
-    protected double rate = 1;
-    protected long cycleTicks = 0;
-
-    // internal state-variables used by all implementations
-    protected long deltaTicks = 0;
-    protected long ticks = 0;
-    protected double currentRate = rate;
-    protected boolean inTimePulse = false;
-    protected boolean aborted = false;
-    
-    protected ClipEnvelope(Animation animation) {
-        this.animation = animation;
-        if (animation != null) {
-            final Duration cycleDuration = animation.getCycleDuration();
-            cycleTicks = TickCalculation.fromDuration(cycleDuration);
-            rate = animation.getRate();
-        }
-    }
-
-    public static ClipEnvelope create(Animation animation) {
-        if ((animation.getCycleCount() == 1) || (animation.getCycleDuration().isIndefinite())) {
-            return new SingleLoopClipEnvelope(animation);
-        } else if (animation.getCycleCount() == Animation.INDEFINITE) {
-            return new InfiniteClipEnvelope(animation);
-        } else {
-            return new FiniteClipEnvelope(animation);
-        }
-    }
-
-    public abstract ClipEnvelope setCycleDuration(Duration cycleDuration);
-    public abstract void setRate(double rate);
-    public abstract void setAutoReverse(boolean autoReverse);
-    public abstract ClipEnvelope setCycleCount(int cycleCount);
-
-    protected void updateCycleTicks(Duration cycleDuration) {
-        cycleTicks = TickCalculation.fromDuration(cycleDuration);
-    }
-
-    public boolean wasSynched() {
-        return cycleTicks != 0;
-    }
-
-    public void start() {
-        setCurrentRate(calculateCurrentRate());
-        deltaTicks = ticks;
-    }
-
-    public abstract void timePulse(long currentTick);
-
-    public abstract void jumpTo(long ticks);
-
-    public void abortCurrentPulse() {
-        if (inTimePulse) {
-            aborted = true;
-            inTimePulse = false;
-        }
-    }
-    
-    protected abstract double calculateCurrentRate();
-    
-    protected void setCurrentRate(double currentRate) {
-        this.currentRate = currentRate;
-        AnimationAccessor.getDefault().setCurrentRate(animation, currentRate);
-    }
-
-    protected static long checkBounds(long value, long max) {
-        return Math.max(0L, Math.min(value, max));
-    }
-
-    public double getCurrentRate() {
-        return currentRate;
-    }
-}
--- a/modules/base/src/main/java/com/sun/scenario/animation/shared/ClipInterpolator.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2008, 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 com.sun.scenario.animation.shared;
-
-import javafx.animation.KeyFrame;
-import javafx.util.Duration;
-
-public abstract class ClipInterpolator {
-
-    static ClipInterpolator create(KeyFrame[] keyFrames, long[] keyFrameTicks) {
-        return (ClipInterpolator.getRealKeyFrameCount(keyFrames) == 2) ? (keyFrames.length == 1) ? new SimpleClipInterpolator(
-                keyFrames[0], keyFrameTicks[0]) : new SimpleClipInterpolator(keyFrames[0],
-                keyFrames[1], keyFrameTicks[1])
-                : new GeneralClipInterpolator(keyFrames, keyFrameTicks);
-    }
-
-    /**
-     * Figures out the number of "real" key frames. The user may not have specified the "zero" key
-     * frame, in which case we end up inferring an additional zero key frame on the array.
-     * 
-     * @param keyFrames The key frames. Must not be null.
-     * @return The "real" number of key frames
-     */
-    static int getRealKeyFrameCount(KeyFrame[] keyFrames) {
-        final int length = keyFrames.length;
-        return (length == 0) ? 0 : (keyFrames[0].getTime()
-                .greaterThan(Duration.ZERO)) ? length + 1 : length;
-    }
-
-    /**
-     * Changes the keyframes.
-     * 
-     * The optimal implementation for the new keyFrames might be different. For
-     * this reason, setKeyFrames returns a ClipInterpolator implementation with
-     * the updated values. This can either be the same object or a newly created
-     * one.
-     * 
-     * @param keyFrames
-     *            The new sorted array of keyframes of this clip
-     * @param keyFrameTicks 
-     *            tick duration of corresponding keyFrames
-     * @return The ClipInterpolator implementation to use after changing the
-     *         keyframes.
-     */
-    abstract ClipInterpolator setKeyFrames(KeyFrame[] keyFrames, long[] keyFrameTicks);
-
-    abstract void interpolate(long ticks);
-
-    abstract void validate(boolean forceSync);
-}
--- a/modules/base/src/main/java/com/sun/scenario/animation/shared/FiniteClipEnvelope.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,197 +0,0 @@
-/*
- * Copyright (c) 2011, 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 com.sun.scenario.animation.shared;
-
-import javafx.animation.Animation;
-import javafx.animation.Animation.Status;
-import javafx.util.Duration;
-
-public class FiniteClipEnvelope extends ClipEnvelope {
-    
-    private boolean autoReverse;
-    private int cycleCount;
-    private long totalTicks;
-    private long pos;
-    
-    protected FiniteClipEnvelope(Animation animation) {
-        super(animation);
-        if (animation != null) {
-            autoReverse = animation.isAutoReverse();
-            cycleCount = animation.getCycleCount();
-        }
-        updateTotalTicks();
-    }
-
-    @Override
-    public void setAutoReverse(boolean autoReverse) {
-        this.autoReverse = autoReverse;
-    }
-
-    @Override
-    protected double calculateCurrentRate() {
-        return !autoReverse? rate
-                : (ticks % (2 * cycleTicks) < cycleTicks) == (rate > 0)? rate : -rate;
-    }
-    
-    @Override
-    public ClipEnvelope setCycleDuration(Duration cycleDuration) {
-        if (cycleDuration.isIndefinite()) {
-            return create(animation);
-        }
-        updateCycleTicks(cycleDuration);
-        updateTotalTicks();
-        return this;
-    }
-
-    @Override
-    public ClipEnvelope setCycleCount(int cycleCount) {
-        if ((cycleCount == 1) || (cycleCount == Animation.INDEFINITE)) {
-            return create(animation);
-        }
-        this.cycleCount = cycleCount;
-        updateTotalTicks();
-        return this;
-    }
-    
-    @Override
-    public void setRate(double rate) {
-        final boolean toggled = rate * this.rate < 0;
-        final long newTicks = toggled? totalTicks - ticks : ticks;
-        final Status status = animation.getStatus();
-        if (status != Status.STOPPED) {
-            if (status == Status.RUNNING) {
-                setCurrentRate((Math.abs(currentRate - this.rate) < EPSILON) ? rate : -rate);
-            }
-            deltaTicks = newTicks - Math.round((ticks - deltaTicks) * Math.abs(rate / this.rate));
-            abortCurrentPulse();
-        }
-        ticks = newTicks;
-        this.rate = rate;
-    }
-    
-    private void updateTotalTicks() {
-        totalTicks = cycleCount * cycleTicks;
-    }
-
-    @Override
-    public void timePulse(long currentTick) {
-        if (cycleTicks == 0L) {
-            return;
-        }
-        aborted = false;
-        inTimePulse = true;
-
-        try {
-            final long oldTicks = ticks;
-            ticks = ClipEnvelope.checkBounds(deltaTicks + Math.round(currentTick * Math.abs(rate)), totalTicks);
-
-            final boolean reachedEnd = ticks >= totalTicks; 
-            
-            long overallDelta = ticks - oldTicks; // overall delta between current position and new position
-            if (overallDelta == 0) {
-                return;
-            }
-            
-            long cycleDelta = (currentRate > 0)? cycleTicks - pos : pos; // delta to reach end of cycle
-            
-            while (overallDelta >= cycleDelta) {
-                if (cycleDelta > 0) {
-                    pos = (currentRate > 0)? cycleTicks : 0;
-                    overallDelta -= cycleDelta;
-                    AnimationAccessor.getDefault().playTo(animation, pos, cycleTicks);
-                    if (aborted) {
-                        return;
-                    }
-                }
-
-                if (!reachedEnd || (overallDelta > 0)) {
-                    if (autoReverse) {
-                        setCurrentRate(-currentRate);
-                    } else {
-                        pos = (currentRate > 0)? 0 : cycleTicks;
-                        AnimationAccessor.getDefault().jumpTo(animation, pos, cycleTicks, false);
-                    }
-                }
-                cycleDelta = cycleTicks;
-            }
-
-            if (overallDelta > 0 && !reachedEnd) {
-                pos += (currentRate > 0)? overallDelta : -overallDelta;
-                AnimationAccessor.getDefault().playTo(animation, pos, cycleTicks);
-            }
-            
-            if(reachedEnd && !aborted) {
-                AnimationAccessor.getDefault().finished(animation);
-            }
-
-        } finally {
-            inTimePulse = false;
-        }
-    }
-
-    @Override
-    public void jumpTo(long newTicks) {
-        if (cycleTicks == 0L) {
-            return;
-        }
-        
-        final long oldTicks = ticks;
-        if (rate < 0) {
-            newTicks = totalTicks - newTicks;
-        }
-        ticks = ClipEnvelope.checkBounds(newTicks, totalTicks);
-        final long delta = ticks - oldTicks;
-        if (delta != 0) {
-            deltaTicks += delta;
-            if (autoReverse) {
-                final boolean forward = ticks % (2 * cycleTicks) < cycleTicks;
-                if (forward == (rate > 0)) {
-                    pos = ticks % cycleTicks;
-                    if (animation.getStatus() == Status.RUNNING) {
-                        setCurrentRate(Math.abs(rate));
-                    }
-                } else {
-                    pos = cycleTicks - (ticks % cycleTicks);
-                    if (animation.getStatus() == Status.RUNNING) {
-                        setCurrentRate(-Math.abs(rate));
-                    }
-                }
-            } else {
-                pos = ticks % cycleTicks;
-                if (rate < 0) {
-                    pos = cycleTicks - pos;
-                }
-                if ((pos == 0) && (ticks > 0)) {
-                    pos = cycleTicks;
-                }
-            }
-            
-            AnimationAccessor.getDefault().jumpTo(animation, pos, cycleTicks, false);
-            abortCurrentPulse();
-        }
-    }
-
-}
--- a/modules/base/src/main/java/com/sun/scenario/animation/shared/GeneralClipInterpolator.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,193 +0,0 @@
-/*
- * Copyright (c) 2008, 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 com.sun.scenario.animation.shared;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javafx.animation.KeyFrame;
-import javafx.animation.KeyValue;
-import javafx.beans.value.WritableValue;
-
-/**
- * General implementation of ClipInterpolator, which covers all use-cases.
- */
-
-// @@OPT:
-// - A binary search in interpolate might make sense.
-// - Prepare only first segment when starting timeline and do the rest later =>
-// improves startup time?
-// - Store 1 / (rightMillis - leftMillis) for each interval and multiply
-class GeneralClipInterpolator extends ClipInterpolator {
-
-    private KeyFrame[] keyFrames;
-    private long[] keyFrameTicks;
-
-    // List of interpolation-points associated with each target
-    private InterpolationInterval[][] interval = new InterpolationInterval[0][];
-
-    // List of indexes for targets with undefined start value
-    private int[] undefinedStartValues = new int[0];
-    // Is internal representation up-to-date?
-    private boolean invalid = true;
-
-    GeneralClipInterpolator(KeyFrame[] keyFrames, long[] keyFrameTicks) {
-        this.keyFrames = keyFrames;
-        this.keyFrameTicks = keyFrameTicks;
-    }
-
-    // See comment in ClipInterpolator
-    @Override
-    ClipInterpolator setKeyFrames(KeyFrame[] keyFrames, long[] keyFrameTicks) {
-        if (ClipInterpolator.getRealKeyFrameCount(keyFrames) == 2) {
-            return ClipInterpolator.create(keyFrames, keyFrameTicks);
-        }
-        this.keyFrames = keyFrames;
-        this.keyFrameTicks = keyFrameTicks;
-        invalid = true;
-        return this;
-    }
-
-    @Override
-    void validate(boolean forceSync) {
-        if (invalid) {
-            final Map<WritableValue<?>, KeyValue> lastKeyValues = new HashMap<>();
-            final int n = keyFrames.length;
-            int index;
-            for (index = 0; index < n; index++) {
-                final KeyFrame keyFrame = keyFrames[index];
-                if (keyFrameTicks[index] == 0) {
-                    for (final KeyValue keyValue : keyFrame.getValues()) {
-                        lastKeyValues.put(keyValue.getTarget(), keyValue);
-                    }
-                } else {
-                    break;
-                }
-            }
-
-            final Map<WritableValue<?>, List<InterpolationInterval>> map = new HashMap<>();
-            final Set<WritableValue<?>> undefinedValues = new HashSet<>();
-            // iterate through all keyFrames
-            for (; index < n; index++) {
-                final KeyFrame keyFrame = keyFrames[index];
-                final long ticks = keyFrameTicks[index];
-                // iterate through all keyValues in this keyFrame
-                for (final KeyValue rightKeyValue : keyFrame.getValues()) {
-                    final WritableValue<?> target = rightKeyValue.getTarget();
-                    List<InterpolationInterval> list = map.get(target);
-                    final KeyValue leftKeyValue = lastKeyValues.get(target);
-                    if (list == null) {
-                        // first encounter of a particular target, generate a
-                        // new interval list
-                        list = new ArrayList<>();
-                        map.put(target, list);
-                        if (leftKeyValue == null) {
-                            list.add(InterpolationInterval.create(
-                                    rightKeyValue, ticks));
-                            undefinedValues.add(target);
-                        } else {
-                            list.add(InterpolationInterval
-                                    .create(rightKeyValue, ticks,
-                                            leftKeyValue, ticks));
-                        }
-                    } else {
-                        assert leftKeyValue != null;
-                        list.add(InterpolationInterval.create(rightKeyValue,
-                                ticks, leftKeyValue,
-                                ticks - list.get(list.size() - 1).ticks));
-                    }
-                    lastKeyValues.put(target, rightKeyValue);
-                }
-            }
-
-            // copy everything to arrays
-            final int targetCount = map.size();
-            if (interval.length != targetCount) {
-                interval = new InterpolationInterval[targetCount][];
-            }
-            final int undefinedStartValuesCount = undefinedValues.size();
-            if (undefinedStartValues.length != undefinedStartValuesCount) {
-                undefinedStartValues = new int[undefinedStartValuesCount];
-            }
-            int undefinedStartValuesIndex = 0;
-            final Iterator<Map.Entry<WritableValue<?>, List<InterpolationInterval>>> iterator = map
-                    .entrySet().iterator();
-            for (int i = 0; i < targetCount; i++) {
-                final Map.Entry<WritableValue<?>, List<InterpolationInterval>> entry = iterator
-                        .next();
-                interval[i] = new InterpolationInterval[entry.getValue().size()];
-                entry.getValue().toArray(interval[i]);
-                if (undefinedValues.contains(entry.getKey())) {
-                    undefinedStartValues[undefinedStartValuesIndex++] = i;
-                }
-            }
-            invalid = false;
-        } else if (forceSync) {
-            final int n = undefinedStartValues.length;
-            for (int i = 0; i < n; i++) {
-                final int index = undefinedStartValues[i];
-                interval[index][0].recalculateStartValue();
-            }
-        }
-    }
-
-    @Override
-    void interpolate(long ticks) {
-        final int targetCount = interval.length;
-        // iterate through all targets
-        targetLoop: for (int targetIndex = 0; targetIndex < targetCount; targetIndex++) {
-            InterpolationInterval[] intervalList = interval[targetIndex];
-            final int intervalCount = intervalList.length;
-            // leftMillis keeps the timestamp of the left side of the interval
-            long leftTicks = 0;
-            // iterate through all intervals except the last one
-            for (int intervalIndex = 0; intervalIndex < intervalCount - 1; intervalIndex++) {
-                final InterpolationInterval i = intervalList[intervalIndex];
-                final long rightTicks = i.ticks;
-                if (ticks <= rightTicks) {
-                    // we found the current interval
-                    final double frac = (double)(ticks - leftTicks)
-                            / (rightTicks - leftTicks);
-                    i.interpolate(frac);
-                    continue targetLoop;
-                }
-                leftTicks = rightTicks;
-            }
-            // we did not find a current interval, use the last one
-            final InterpolationInterval i = intervalList[intervalCount - 1];
-            // the last interval may end before the timeline ends, make sure we
-            // set the end value
-            final double frac = Math.min(1.0, (double)(ticks - leftTicks)
-                    / (i.ticks - leftTicks));
-            i.interpolate(frac);
-        }
-    }
-}
--- a/modules/base/src/main/java/com/sun/scenario/animation/shared/InfiniteClipEnvelope.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,167 +0,0 @@
-/*
- * Copyright (c) 2011, 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 com.sun.scenario.animation.shared;
-
-import javafx.animation.Animation;
-import javafx.animation.Animation.Status;
-import javafx.util.Duration;
-
-public class InfiniteClipEnvelope extends ClipEnvelope {
-    
-    private boolean autoReverse;
-    private long pos;
-    
-    protected InfiniteClipEnvelope(Animation animation) {
-        super(animation);
-        if (animation != null) {
-            autoReverse = animation.isAutoReverse();
-        }
-    }
-
-    @Override
-    public void setAutoReverse(boolean autoReverse) {
-        this.autoReverse = autoReverse;
-    }
-
-    @Override
-    protected double calculateCurrentRate() {
-        return !autoReverse? rate
-                : (ticks % (2 * cycleTicks) < cycleTicks)? rate : -rate;
-    }
-    
-    @Override
-    public ClipEnvelope setCycleDuration(Duration cycleDuration) {
-        if (cycleDuration.isIndefinite()) {
-            return create(animation);
-        }
-        updateCycleTicks(cycleDuration);
-        return this;
-    }
-
-    @Override
-    public ClipEnvelope setCycleCount(int cycleCount) {
-       return (cycleCount != Animation.INDEFINITE)? create(animation) : this;
-    }
-
-    @Override
-    public void setRate(double rate) {
-        final Status status = animation.getStatus();
-        if (status != Status.STOPPED) {
-            if (status == Status.RUNNING) {
-                setCurrentRate((Math.abs(currentRate - this.rate) < EPSILON) ? rate : -rate);
-            }
-            deltaTicks = ticks - Math.round((ticks - deltaTicks) * Math.abs(rate / this.rate));
-            if (rate * this.rate < 0) {
-                final long delta = 2 * cycleTicks - pos;
-                deltaTicks += delta;
-                ticks += delta;
-            }
-            abortCurrentPulse();
-        }
-        this.rate = rate;
-    }
-    
-    @Override
-    public void timePulse(long currentTick) {
-        if (cycleTicks == 0L) {
-            return;
-        }
-        aborted = false;
-        inTimePulse = true;
-
-        try {
-            final long oldTicks = ticks;
-            ticks = Math.max(0, deltaTicks + Math.round(currentTick * Math.abs(rate)));
-
-            long overallDelta = ticks - oldTicks; // overall delta between current position and new position
-            if (overallDelta == 0) {
-                return;
-            }
-
-            long cycleDelta = (currentRate > 0)? cycleTicks - pos : pos; // delta to reach end of cycle
-
-            while (overallDelta >= cycleDelta) {
-                if (cycleDelta > 0) {
-                    pos = (currentRate > 0)? cycleTicks : 0;
-                    overallDelta -= cycleDelta;
-                    AnimationAccessor.getDefault().playTo(animation, pos, cycleTicks);
-                    if (aborted) {
-                        return;
-                    }
-                }
-                if (autoReverse) {
-                    setCurrentRate(-currentRate);
-                } else {
-                    pos = (currentRate > 0)? 0 : cycleTicks;
-                    AnimationAccessor.getDefault().jumpTo(animation, pos, cycleTicks, false);
-                }
-                cycleDelta = cycleTicks;
-            }
-
-            if (overallDelta > 0) {
-                pos += (currentRate > 0)? overallDelta : -overallDelta;
-                AnimationAccessor.getDefault().playTo(animation, pos, cycleTicks);
-            }
-
-        } finally {
-            inTimePulse = false;
-        }
-    }
-
-    @Override
-    public void jumpTo(long newTicks) {
-        if (cycleTicks == 0L) {
-            return;
-        }
-        final long oldTicks = ticks;
-        ticks = Math.max(0, newTicks) % (2 * cycleTicks);
-        final long delta = ticks - oldTicks;
-        if (delta != 0) {
-            deltaTicks += delta;
-            if (autoReverse) {
-                if (ticks > cycleTicks) {
-                    pos = 2 * cycleTicks - ticks;
-                    if (animation.getStatus() == Status.RUNNING) {
-                        setCurrentRate(-rate);
-                    }
-                } else {
-                    pos = ticks;
-                    if (animation.getStatus() == Status.RUNNING) {
-                        setCurrentRate(rate);
-                    }
-                }
-            } else {
-                pos = ticks % cycleTicks;
-                if (pos == 0) {
-                    pos = ticks;
-                }
-            }
-            AnimationAccessor.getDefault().jumpTo(animation, pos, cycleTicks, false);
-            abortCurrentPulse();
-        }
-    }
-
-}
--- a/modules/base/src/main/java/com/sun/scenario/animation/shared/InterpolationInterval.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,553 +0,0 @@
-/*
- * Copyright (c) 2011, 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 com.sun.scenario.animation.shared;
-
-import javafx.animation.Interpolator;
-import javafx.animation.KeyValue;
-import javafx.beans.value.WritableBooleanValue;
-import javafx.beans.value.WritableDoubleValue;
-import javafx.beans.value.WritableFloatValue;
-import javafx.beans.value.WritableIntegerValue;
-import javafx.beans.value.WritableLongValue;
-import javafx.beans.value.WritableValue;
-
-import com.sun.scenario.animation.NumberTangentInterpolator;
-
-public abstract class InterpolationInterval {
-
-    protected final long ticks;
-    protected final Interpolator rightInterpolator;
-
-    protected InterpolationInterval(long ticks,
-            Interpolator rightInterpolator) {
-        this.ticks = ticks;
-        this.rightInterpolator = rightInterpolator;
-    }
-
-    public abstract void interpolate(double frac);
-
-    public abstract void recalculateStartValue();
-
-    public static InterpolationInterval create(KeyValue rightKeyValue,
-            long ticks, KeyValue leftKeyValue, long duration) {
-        switch (rightKeyValue.getType()) {
-            case BOOLEAN:
-                return new BooleanInterpolationInterval(rightKeyValue, ticks,
-                        leftKeyValue.getEndValue());
-            case DOUBLE:
-                return ((leftKeyValue.getInterpolator() instanceof NumberTangentInterpolator) || (rightKeyValue
-                        .getInterpolator() instanceof NumberTangentInterpolator)) ? new TangentDoubleInterpolationInterval(
-                        rightKeyValue, ticks, leftKeyValue, duration)
-                        : new DoubleInterpolationInterval(rightKeyValue,
-                                ticks, leftKeyValue.getEndValue());
-            case FLOAT:
-                return ((leftKeyValue.getInterpolator() instanceof NumberTangentInterpolator) || (rightKeyValue
-                        .getInterpolator() instanceof NumberTangentInterpolator)) ? new TangentFloatInterpolationInterval(
-                        rightKeyValue, ticks, leftKeyValue, duration)
-                        : new FloatInterpolationInterval(rightKeyValue, ticks,
-                                leftKeyValue.getEndValue());
-            case INTEGER:
-                return ((leftKeyValue.getInterpolator() instanceof NumberTangentInterpolator) || (rightKeyValue
-                        .getInterpolator() instanceof NumberTangentInterpolator)) ? new TangentIntegerInterpolationInterval(
-                        rightKeyValue, ticks, leftKeyValue, duration)
-                        : new IntegerInterpolationInterval(rightKeyValue,
-                                ticks, leftKeyValue.getEndValue());
-            case LONG:
-                return ((leftKeyValue.getInterpolator() instanceof NumberTangentInterpolator) || (rightKeyValue
-                        .getInterpolator() instanceof NumberTangentInterpolator)) ? new TangentLongInterpolationInterval(
-                        rightKeyValue, ticks, leftKeyValue, duration)
-                        : new LongInterpolationInterval(rightKeyValue, ticks,
-                                leftKeyValue.getEndValue());
-            case OBJECT:
-                return new ObjectInterpolationInterval(rightKeyValue, ticks,
-                        leftKeyValue.getEndValue());
-        }
-        throw new RuntimeException("Should not reach here");
-    }
-
-    public static InterpolationInterval create(KeyValue rightKeyValue,
-            long ticks) {
-        switch (rightKeyValue.getType()) {
-            case BOOLEAN:
-                return new BooleanInterpolationInterval(rightKeyValue, ticks);
-            case DOUBLE:
-                return (rightKeyValue.getInterpolator() instanceof NumberTangentInterpolator) ? new TangentDoubleInterpolationInterval(
-                        rightKeyValue, ticks)
-                        : new DoubleInterpolationInterval(rightKeyValue, ticks);
-            case FLOAT:
-                return (rightKeyValue.getInterpolator() instanceof NumberTangentInterpolator) ? new TangentFloatInterpolationInterval(
-                        rightKeyValue, ticks)
-                        : new FloatInterpolationInterval(rightKeyValue, ticks);
-            case INTEGER:
-                return (rightKeyValue.getInterpolator() instanceof NumberTangentInterpolator) ? new TangentIntegerInterpolationInterval(
-                        rightKeyValue, ticks)
-                        : new IntegerInterpolationInterval(rightKeyValue,
-                                ticks);
-            case LONG:
-                return (rightKeyValue.getInterpolator() instanceof NumberTangentInterpolator) ? new TangentLongInterpolationInterval(
-                        rightKeyValue, ticks) : new LongInterpolationInterval(
-                        rightKeyValue, ticks);
-            case OBJECT:
-                return new ObjectInterpolationInterval(rightKeyValue, ticks);
-        }
-        throw new RuntimeException("Should not reach here");
-    }
-
-    private static abstract class TangentInterpolationInterval extends
-            InterpolationInterval {
-
-        private final double duration;
-        private final double p2;
-        protected final double p3;
-        private final NumberTangentInterpolator leftInterpolator;
-
-        protected double p0;
-        private double p1;
-
-        private TangentInterpolationInterval(KeyValue rightKeyValue,
-                long ticks, KeyValue leftKeyValue, long duration) {
-            super(ticks, rightKeyValue.getInterpolator());
-            assert (rightKeyValue.getEndValue() instanceof Number)
-                    && (leftKeyValue.getEndValue() instanceof Number);
-
-            this.duration = duration;
-            final Interpolator rawLeftInterpolator = leftKeyValue
-                    .getInterpolator();
-            leftInterpolator = (rawLeftInterpolator instanceof NumberTangentInterpolator) ? (NumberTangentInterpolator) rawLeftInterpolator
-                    : null;
-            recalculateStartValue(((Number) leftKeyValue.getEndValue())
-                    .doubleValue());
-
-            final NumberTangentInterpolator interpolator = (rightInterpolator instanceof NumberTangentInterpolator) ? (NumberTangentInterpolator) rightInterpolator
-                    : null;
-            p3 = ((Number) rightKeyValue.getEndValue()).doubleValue();
-            final double p2Delta = (interpolator == null) ? 0 : (interpolator
-                    .getInValue() - p3)
-                    * duration
-                    / interpolator.getInTicks()
-                    / 3;
-            p2 = p3 + p2Delta;
-        }
-
-        private TangentInterpolationInterval(KeyValue rightKeyValue,
-                long ticks) {
-            super(ticks, rightKeyValue.getInterpolator());
-            assert rightKeyValue.getEndValue() instanceof Number;
-
-            this.duration = ticks;
-            leftInterpolator = null;
-
-            final NumberTangentInterpolator interpolator = (rightInterpolator instanceof NumberTangentInterpolator) ? (NumberTangentInterpolator) rightInterpolator
-                    : null;
-            p3 = ((Number) rightKeyValue.getEndValue()).doubleValue();
-            final double p2Delta = (interpolator == null) ? 0 : (interpolator
-                    .getInValue() - p3)
-                    * duration
-                    / interpolator.getInTicks()
-                    / 3;
-            p2 = p3 + p2Delta;
-        }
-
-        protected double calculate(double t) {
-            final double oneMinusT = 1.0 - t;
-            final double tSquared = t * t;
-            final double oneMinusTSquared = oneMinusT * oneMinusT;
-
-            return oneMinusTSquared * oneMinusT * p0 + 3 * oneMinusTSquared * t
-                    * p1 + 3 * oneMinusT * tSquared * p2 + tSquared * t * p3;
-        }
-
-        protected final void recalculateStartValue(double leftValue) {
-            p0 = leftValue;
-            final double p1Delta = (leftInterpolator == null) ? 0
-                    : (leftInterpolator.getOutValue() - p0) * duration
-                            / leftInterpolator.getOutTicks() / 3;
-            p1 = p0 + p1Delta;
-        }
-    }
-
-    private static class BooleanInterpolationInterval extends
-            InterpolationInterval {
-
-        private final WritableBooleanValue target;
-        private boolean leftValue;
-        private final boolean rightValue;
-
-        private BooleanInterpolationInterval(KeyValue keyValue, long ticks,
-                Object leftValue) {
-            super(ticks, keyValue.getInterpolator());
-            assert (keyValue.getTarget() instanceof WritableBooleanValue)
-                    && (keyValue.getEndValue() instanceof Boolean)
-                    && (leftValue instanceof Boolean);
-            this.target = (WritableBooleanValue) keyValue.getTarget();
-            this.rightValue = (Boolean) keyValue.getEndValue();
-            this.leftValue = (Boolean) leftValue;
-        }
-
-        private BooleanInterpolationInterval(KeyValue keyValue, long ticks) {
-            super(ticks, keyValue.getInterpolator());
-            assert (keyValue.getTarget() instanceof WritableBooleanValue)
-                    && (keyValue.getEndValue() instanceof Boolean);
-            this.target = (WritableBooleanValue) keyValue.getTarget();
-            this.rightValue = (Boolean) keyValue.getEndValue();
-            this.leftValue = target.get();
-        }
-
-        @Override
-        public void interpolate(double frac) {
-            final boolean value = rightInterpolator.interpolate(leftValue,
-                    rightValue, frac);
-            target.set(value);
-        }
-
-        @Override
-        public void recalculateStartValue() {
-            leftValue = target.get();
-        }
-    }
-
-    private static class DoubleInterpolationInterval extends
-            InterpolationInterval {
-
-        private final WritableDoubleValue target;
-        private double leftValue;
-        private final double rightValue;
-
-        private DoubleInterpolationInterval(KeyValue keyValue, long ticks,
-                Object leftValue) {
-            super(ticks, keyValue.getInterpolator());
-            assert (keyValue.getTarget() instanceof WritableDoubleValue)
-                    && (keyValue.getEndValue() instanceof Number)
-                    && (leftValue instanceof Number);
-            this.target = (WritableDoubleValue) keyValue.getTarget();
-            this.rightValue = ((Number) keyValue.getEndValue()).doubleValue();
-            this.leftValue = ((Number) leftValue).doubleValue();
-        }
-
-        private DoubleInterpolationInterval(KeyValue keyValue, long ticks) {
-            super(ticks, keyValue.getInterpolator());
-            assert (keyValue.getTarget() instanceof WritableDoubleValue)
-                    && (keyValue.getEndValue() instanceof Number);
-            this.target = (WritableDoubleValue) keyValue.getTarget();
-            this.rightValue = ((Number) keyValue.getEndValue()).doubleValue();
-            this.leftValue = target.get();
-        }
-
-        @Override
-        public void interpolate(double frac) {
-            final double value = rightInterpolator.interpolate(leftValue,
-                    rightValue, frac);
-            target.set(value);
-        }
-
-        @Override
-        public void recalculateStartValue() {
-            leftValue = target.get();
-        }
-    }
-
-    private static class TangentDoubleInterpolationInterval extends
-            TangentInterpolationInterval {
-
-        private final WritableDoubleValue target;
-
-        private TangentDoubleInterpolationInterval(KeyValue rightKeyValue,
-                long ticks, KeyValue leftKeyValue, long duration) {
-            super(rightKeyValue, ticks, leftKeyValue, duration);
-            assert rightKeyValue.getTarget() instanceof WritableDoubleValue;
-            this.target = (WritableDoubleValue) rightKeyValue.getTarget();
-        }
-
-        private TangentDoubleInterpolationInterval(KeyValue rightKeyValue,
-                long ticks) {
-            super(rightKeyValue, ticks);
-            assert rightKeyValue.getTarget() instanceof WritableDoubleValue;
-            this.target = (WritableDoubleValue) rightKeyValue.getTarget();
-            recalculateStartValue(target.get());
-        }
-
-        @Override
-        public void interpolate(double frac) {
-            target.set(calculate(frac));
-        }
-
-        @Override
-        public void recalculateStartValue() {
-            recalculateStartValue(target.get());
-        }
-    }
-
-    private static class FloatInterpolationInterval extends
-            InterpolationInterval {
-
-        private final WritableFloatValue target;
-        private float leftValue;
-        private final float rightValue;
-
-        private FloatInterpolationInterval(KeyValue keyValue, long ticks,
-                Object leftValue) {
-            super(ticks, keyValue.getInterpolator());
-            assert (keyValue.getTarget() instanceof WritableFloatValue)
-                    && (keyValue.getEndValue() instanceof Number)
-                    && (leftValue instanceof Number);
-            this.target = (WritableFloatValue) keyValue.getTarget();
-            this.rightValue = ((Number) keyValue.getEndValue()).floatValue();
-            this.leftValue = ((Number) leftValue).floatValue();
-        }
-
-        private FloatInterpolationInterval(KeyValue keyValue, long ticks) {
-            super(ticks, keyValue.getInterpolator());
-            assert (keyValue.getTarget() instanceof WritableFloatValue)
-                    && (keyValue.getEndValue() instanceof Number);
-            this.target = (WritableFloatValue) keyValue.getTarget();
-            this.rightValue = ((Number) keyValue.getEndValue()).floatValue();
-            this.leftValue = target.get();
-        }
-
-        @Override
-        public void interpolate(double frac) {
-            final float value = (float) rightInterpolator.interpolate(
-                    leftValue, rightValue, frac);
-            target.set(value);
-        }
-
-        @Override
-        public void recalculateStartValue() {
-            leftValue = target.get();
-        }
-    }
-
-    private static class TangentFloatInterpolationInterval extends
-            TangentInterpolationInterval {
-
-        private final WritableFloatValue target;
-
-        private TangentFloatInterpolationInterval(KeyValue rightKeyValue,
-                long ticks, KeyValue leftKeyValue, long duration) {
-            super(rightKeyValue, ticks, leftKeyValue, duration);
-            assert rightKeyValue.getTarget() instanceof WritableFloatValue;
-            this.target = (WritableFloatValue) rightKeyValue.getTarget();
-        }
-
-        private TangentFloatInterpolationInterval(KeyValue rightKeyValue,
-                long ticks) {
-            super(rightKeyValue, ticks);
-            assert rightKeyValue.getTarget() instanceof WritableFloatValue;
-            this.target = (WritableFloatValue) rightKeyValue.getTarget();
-            recalculateStartValue(target.get());
-        }
-
-        @Override
-        public void interpolate(double frac) {
-            target.set((float) calculate(frac));
-        }
-
-        @Override
-        public void recalculateStartValue() {
-            recalculateStartValue(target.get());
-        }
-    }
-
-    private static class IntegerInterpolationInterval extends
-            InterpolationInterval {
-
-        private final WritableIntegerValue target;
-        private int leftValue;
-        private final int rightValue;
-
-        private IntegerInterpolationInterval(KeyValue keyValue, long ticks,
-                Object leftValue) {
-            super(ticks, keyValue.getInterpolator());
-            assert (keyValue.getTarget() instanceof WritableIntegerValue)
-                    && (keyValue.getEndValue() instanceof Number)
-                    && (leftValue instanceof Number);
-            this.target = (WritableIntegerValue) keyValue.getTarget();
-            this.rightValue = ((Number) keyValue.getEndValue()).intValue();
-            this.leftValue = ((Number) leftValue).intValue();
-        }
-
-        private IntegerInterpolationInterval(KeyValue keyValue, long ticks) {
-            super(ticks, keyValue.getInterpolator());
-            assert (keyValue.getTarget() instanceof WritableIntegerValue)
-                    && (keyValue.getEndValue() instanceof Number);
-            this.target = (WritableIntegerValue) keyValue.getTarget();
-            this.rightValue = ((Number) keyValue.getEndValue()).intValue();
-            this.leftValue = target.get();
-        }
-
-        @Override
-        public void interpolate(double frac) {
-            final int value = rightInterpolator.interpolate(leftValue,
-                    rightValue, frac);
-            target.set(value);
-        }
-
-        @Override
-        public void recalculateStartValue() {
-            leftValue = target.get();
-        }
-    }
-
-    private static class TangentIntegerInterpolationInterval extends
-            TangentInterpolationInterval {
-
-        private final WritableIntegerValue target;
-
-        private TangentIntegerInterpolationInterval(KeyValue rightKeyValue,
-                long ticks, KeyValue leftKeyValue, long duration) {
-            super(rightKeyValue, ticks, leftKeyValue, duration);
-            assert rightKeyValue.getTarget() instanceof WritableIntegerValue;
-            this.target = (WritableIntegerValue) rightKeyValue.getTarget();
-        }
-
-        private TangentIntegerInterpolationInterval(KeyValue rightKeyValue,
-                long ticks) {
-            super(rightKeyValue, ticks);
-            assert rightKeyValue.getTarget() instanceof WritableIntegerValue;
-            this.target = (WritableIntegerValue) rightKeyValue.getTarget();
-            recalculateStartValue(target.get());
-        }
-
-        @Override
-        public void interpolate(double frac) {
-            target.set((int) Math.round(calculate(frac)));
-        }
-
-        @Override
-        public void recalculateStartValue() {
-            recalculateStartValue(target.get());
-        }
-    }
-
-    private static class LongInterpolationInterval extends
-            InterpolationInterval {
-
-        private final WritableLongValue target;
-        private long leftValue;
-        private final long rightValue;
-
-        private LongInterpolationInterval(KeyValue keyValue, long ticks,
-                Object leftValue) {
-            super(ticks, keyValue.getInterpolator());
-            assert (keyValue.getTarget() instanceof WritableLongValue)
-                    && (keyValue.getEndValue() instanceof Number)
-                    && (leftValue instanceof Number);
-            this.target = (WritableLongValue) keyValue.getTarget();
-            this.rightValue = ((Number) keyValue.getEndValue()).longValue();
-            this.leftValue = ((Number) leftValue).longValue();
-        }
-
-        private LongInterpolationInterval(KeyValue keyValue, long ticks) {
-            super(ticks, keyValue.getInterpolator());
-            assert (keyValue.getTarget() instanceof WritableLongValue)
-                    && (keyValue.getEndValue() instanceof Number);
-            this.target = (WritableLongValue) keyValue.getTarget();
-            this.rightValue = ((Number) keyValue.getEndValue()).longValue();
-            this.leftValue = target.get();
-        }
-
-        @Override
-        public void interpolate(double frac) {
-            final long value = rightInterpolator.interpolate(leftValue,
-                    rightValue, frac);
-            target.set(value);
-        }
-
-        @Override
-        public void recalculateStartValue() {
-            leftValue = target.get();
-        }
-    }
-
-    private static class TangentLongInterpolationInterval extends
-            TangentInterpolationInterval {
-
-        private final WritableLongValue target;
-
-        private TangentLongInterpolationInterval(KeyValue rightKeyValue,
-                long ticks, KeyValue leftKeyValue, long duration) {
-            super(rightKeyValue, ticks, leftKeyValue, duration);
-            assert rightKeyValue.getTarget() instanceof WritableLongValue;
-            this.target = (WritableLongValue) rightKeyValue.getTarget();
-        }
-
-        private TangentLongInterpolationInterval(KeyValue rightKeyValue,
-                long ticks) {
-            super(rightKeyValue, ticks);
-            assert rightKeyValue.getTarget() instanceof WritableLongValue;
-            this.target = (WritableLongValue) rightKeyValue.getTarget();
-            recalculateStartValue(target.get());
-        }
-
-        @Override
-        public void interpolate(double frac) {
-            target.set(Math.round(calculate(frac)));
-        }
-
-        @Override
-        public void recalculateStartValue() {
-            recalculateStartValue(target.get());
-        }
-    }
-
-    private static class ObjectInterpolationInterval extends
-            InterpolationInterval {
-
-        @SuppressWarnings("rawtypes")
-        private final WritableValue target;
-        private Object leftValue;
-        private final Object rightValue;
-
-        private ObjectInterpolationInterval(KeyValue keyValue, long ticks,
-                Object leftValue) {
-            super(ticks, keyValue.getInterpolator());
-            this.target = keyValue.getTarget();
-            this.rightValue = keyValue.getEndValue();
-            this.leftValue = leftValue;
-        }
-
-        private ObjectInterpolationInterval(KeyValue keyValue, long ticks) {
-            super(ticks, keyValue.getInterpolator());
-            this.target = keyValue.getTarget();
-            this.rightValue = keyValue.getEndValue();
-            this.leftValue = target.getValue();
-        }
-
-        @SuppressWarnings("unchecked")
-        @Override
-        public void interpolate(double frac) {
-            final Object value = rightInterpolator.interpolate(leftValue,
-                    rightValue, frac);
-            target.setValue(value);
-        }
-
-        @Override
-        public void recalculateStartValue() {
-            leftValue = target.getValue();
-        }
-    }
-
-}
--- a/modules/base/src/main/java/com/sun/scenario/animation/shared/PulseReceiver.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2008, 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 com.sun.scenario.animation.shared;
-
-/**
- * A PulseReceiver can receive regular pulses from the MasterTimer. Removing
- * receivers from the MasterTimer needs to be in-sync with the
- * timePulse-iteration. The receiver is removed if timePulse returns true.
- * The reason we do not use Callback or some other pre-existing interface
- * is that we want an interface that takes a primitive long, whereas Callback
- * would require a wrapped Long and would have some impact on performance.
- */
-public interface PulseReceiver {
-    /**
-     * Callback triggered to send regular pulses to the PulseReceiver
-     * 
-     * @param now
-     *            Timestamp of the pulse.
-     * @return true if PulseReceiver should be removed from the MasterTimer.
-     */
-    void timePulse(long now);
-}
--- a/modules/base/src/main/java/com/sun/scenario/animation/shared/SimpleClipInterpolator.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,140 +0,0 @@
-/*
- * Copyright (c) 2008, 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 com.sun.scenario.animation.shared;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javafx.animation.KeyFrame;
-import javafx.animation.KeyValue;
-import javafx.beans.value.WritableValue;
-import javafx.util.Duration;
-
-/**
- * Simplified implementation of ClipCore, which is used for timelines with
- * exactly two keyframes.
- */
-
-class SimpleClipInterpolator extends ClipInterpolator {
-
-    private static final KeyFrame ZERO_FRAME = new KeyFrame(Duration.ZERO);
-
-    // The list of all targets in this clip
-    private KeyFrame startKeyFrame;
-    private KeyFrame endKeyFrame;
-    private long endTicks;
-    private InterpolationInterval[] interval;
-    private int undefinedStartValueCount;
-    private long ticks;
-
-    // Is internal representation uptodate?
-    private boolean invalid = true;
-
-    SimpleClipInterpolator(KeyFrame startKeyFrame, KeyFrame endKeyFrame, long ticks) {
-        this.startKeyFrame = startKeyFrame;
-        this.endKeyFrame = endKeyFrame;
-        this.endTicks = ticks;
-    }
-
-    SimpleClipInterpolator(KeyFrame endKeyFrame, long ticks) {
-        this.startKeyFrame = ZERO_FRAME;
-        this.endKeyFrame = endKeyFrame;
-        this.endTicks = ticks;
-    }
-
-    // See comment in ClipInterpolator
-    @Override
-    ClipInterpolator setKeyFrames(KeyFrame[] keyFrames, long[] keyFrameTicks) {
-        if (ClipInterpolator.getRealKeyFrameCount(keyFrames) != 2) {
-            return ClipInterpolator.create(keyFrames, keyFrameTicks);
-        }
-        if (keyFrames.length == 1) {
-            startKeyFrame = ZERO_FRAME;
-            endKeyFrame = keyFrames[0];
-            endTicks = keyFrameTicks[0];
-        } else {
-            startKeyFrame = keyFrames[0];
-            endKeyFrame = keyFrames[1];
-            endTicks = keyFrameTicks[1];
-        }
-        invalid = true;
-        return this;
-    }
-
-    @Override
-    void validate(boolean forceSync) {
-        if (invalid) {
-            ticks = endTicks;
-            
-            final Map<WritableValue<?>, KeyValue> map = new HashMap<>();
-            // create a map from target => keyValues of endFrame
-            for (final KeyValue keyValue : endKeyFrame.getValues()) {
-                map.put(keyValue.getTarget(), keyValue);
-            }
-
-            final int valueCount = map.size();
-            interval = new InterpolationInterval[valueCount];
-
-            // iterate through keyValues in startFrame and generate intervals
-            // if we find a matching keyValue in the startFrame, the entry is
-            // removed from the map
-            int i = 0;
-            for (final KeyValue startKeyValue : startKeyFrame.getValues()) {
-                final WritableValue<?> target = startKeyValue.getTarget();
-                final KeyValue endKeyValue = map.get(target);
-                if (endKeyValue != null) {
-                    interval[i++] = InterpolationInterval.create(endKeyValue,
-                            ticks, startKeyValue, ticks);
-                    map.remove(target);
-                }
-            }
-
-            // remaining entries in the map have no start value defined
-            undefinedStartValueCount = map.values().size();
-            for (final KeyValue endKeyValue : map.values()) {
-                interval[i++] = InterpolationInterval.create(endKeyValue,
-                        ticks);
-            }
-
-            invalid = false;
-        } else if (forceSync) {
-            // iterate through keyValues with undefined start value
-            final int n = interval.length;
-            for (int i = n - undefinedStartValueCount; i < n; i++) {
-                interval[i].recalculateStartValue();
-            }
-        }
-    }
-
-    @Override
-    void interpolate(long ticks) {
-        final double frac = ((double)ticks / this.ticks);
-        final int n = interval.length;
-        for (int i = 0; i < n; i++) {
-            interval[i].interpolate(frac);
-        }
-    }
-}
--- a/modules/base/src/main/java/com/sun/scenario/animation/shared/SingleLoopClipEnvelope.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,124 +0,0 @@
-/*
- * Copyright (c) 2011, 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 com.sun.scenario.animation.shared;
-
-import javafx.animation.Animation;
-import javafx.animation.Animation.Status;
-import javafx.util.Duration;
-
-public class SingleLoopClipEnvelope extends ClipEnvelope {
-    
-    private int cycleCount;
-    
-    @Override
-    public void setRate(double rate) {
-        final Status status = animation.getStatus();
-        if (status != Status.STOPPED) {
-            if (status == Status.RUNNING) {
-                setCurrentRate((Math.abs(currentRate - this.rate) < EPSILON) ? rate : -rate);
-            }
-            deltaTicks = ticks - Math.round((ticks - deltaTicks) * rate / this.rate);
-            abortCurrentPulse();
-        }
-        this.rate = rate;
-    }
-
-    @Override
-    public void setAutoReverse(boolean autoReverse) {
-        // ignore autoReverse
-    }
-
-    @Override
-    protected double calculateCurrentRate() {
-        return rate;
-    }
-    
-    protected SingleLoopClipEnvelope(Animation animation) {
-        super(animation);
-        if (animation != null) {
-            cycleCount = animation.getCycleCount();
-        }
-    }
-
-    @Override
-    public boolean wasSynched() {
-        return super.wasSynched() && cycleCount != 0;
-    }
-
-    @Override
-    public ClipEnvelope setCycleDuration(Duration cycleDuration) {
-        if ((cycleCount != 1) && !cycleDuration.isIndefinite()) {
-            return create(animation);
-        }
-        updateCycleTicks(cycleDuration);
-        return this;
-    }
-
-    @Override
-    public ClipEnvelope setCycleCount(int cycleCount) {
-        if ((cycleCount != 1) && (cycleTicks != ClipEnvelope.INDEFINITE)) {
-            return create(animation);
-        }
-        this.cycleCount = cycleCount;
-        return this;
-    }
-
-    @Override
-    public void timePulse(long currentTick) {
-        if (cycleTicks == 0L) {
-            return;
-        }
-        aborted = false;
-        inTimePulse = true;
-
-        try {
-            ticks = ClipEnvelope.checkBounds(deltaTicks + Math.round(currentTick * currentRate), cycleTicks);
-            AnimationAccessor.getDefault().playTo(animation, ticks, cycleTicks);
-    
-            final boolean reachedEnd = (currentRate > 0)? (ticks == cycleTicks) : (ticks == 0);
-            if(reachedEnd && !aborted) {
-                AnimationAccessor.getDefault().finished(animation);
-            }
-        } finally {
-            inTimePulse = false;
-        }
-    }
-
-    @Override
-    public void jumpTo(long ticks) {
-        if (cycleTicks == 0L) {
-            return;
-        }
-        final long newTicks = ClipEnvelope.checkBounds(ticks, cycleTicks);
-        deltaTicks += (newTicks - this.ticks);
-        this.ticks = newTicks;
-
-        AnimationAccessor.getDefault().jumpTo(animation, newTicks, cycleTicks, false);
-
-        abortCurrentPulse();
-    }
-
-}
--- a/modules/base/src/main/java/com/sun/scenario/animation/shared/TimelineClipCore.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,238 +0,0 @@
-/*
- * Copyright (c) 2008, 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 com.sun.scenario.animation.shared;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Comparator;
-import javafx.animation.Animation.Status;
-import javafx.animation.KeyFrame;
-import javafx.animation.Timeline;
-import javafx.event.ActionEvent;
-import javafx.event.EventHandler;
-import javafx.util.Duration;
-import com.sun.javafx.animation.TickCalculation;
-
-/**
- * An instance of ClipCore handles the core part of a clip.
- * 
- * The functionality to react on a pulse-signal from the timer is implemented in
- * two classes: ClipEnvelope and ClipCore. ClipEnvelope is responsible for the
- * "loop-part" (keeping track of the number of cycles, handling the direction of
- * the clip etc.). ClipCore takes care of the inner part (interpolating the
- * values, triggering the action-functions, ...)
- * 
- * Both classes have an abstract public definition and can only be created using
- * the factory method create(). The intend is to provide a general
- * implementation plus eventually some fast-track implementations for common use
- * cases.
- */
-
-// @@OPT
-// - Use known information (kf) in visitKeyFrame to set values?
-
-public class TimelineClipCore {
-
-    private static final int UNDEFINED_KEYFRAME = -1;
-
-    /**
-     * Note: this comparator imposes orderings that are inconsistent with
-     * equals.
-     */
-    private static final Comparator<KeyFrame> KEY_FRAME_COMPARATOR = new Comparator<KeyFrame>() {
-        @Override
-        public int compare(KeyFrame kf1, KeyFrame kf2) {
-            return kf1.getTime().compareTo(kf2.getTime());
-        }
-    };
-
-    // The owner of this ClipCore
-    Timeline timeline;
-
-    // The sorted list of keyframes
-    private KeyFrame[] keyFrames = new KeyFrame[0];
-    private long[] keyFrameTicks = new long[0];
-
-    private ClipInterpolator clipInterpolator;
-
-    public TimelineClipCore(Timeline timeline) {
-        this.timeline = timeline;
-        this.clipInterpolator = ClipInterpolator.create(keyFrames, keyFrameTicks);
-    }
-
-    /**
-     * Changes the keyframes.
-     */
-    public Duration setKeyFrames(Collection<KeyFrame> keyFrames) {
-        final int n = keyFrames.size();
-        final KeyFrame[] sortedKeyFrames = new KeyFrame[n];
-        keyFrames.toArray(sortedKeyFrames);
-        Arrays.sort(sortedKeyFrames, KEY_FRAME_COMPARATOR);
-        
-        this.keyFrames = sortedKeyFrames;
-        keyFrameTicks = new long[n];
-        for (int i = 0; i < n; ++i) {
-            keyFrameTicks[i] = TickCalculation.fromDuration(this.keyFrames[i].getTime());
-        }
-        clipInterpolator = clipInterpolator.setKeyFrames(sortedKeyFrames, keyFrameTicks);
-        return (n == 0) ? Duration.ZERO
-                : sortedKeyFrames[n-1].getTime();
-    }
-
-    public void notifyCurrentRateChanged() {
-        // special case: if clip is toggled while stopped, we want to revisit
-        // all key frames
-        if (timeline.getStatus() != Status.RUNNING) {
-            clearLastKeyFrame();
-        }
-    }
-
-    /**
-     * This method is called if while visiting a keyframe of a timeline the time
-     * or rate are changed, or if the timeline is stopped. In these cases
-     * visiting the keyframes must be aborted.
-     */
-    public void abort() {
-        aborted = true;
-    }
-
-    private boolean aborted = false;
-
-    // The index of the keyframe that was visited last
-    private int lastKF = UNDEFINED_KEYFRAME;
-
-    // The position where clip currently stands
-    private long curTicks = 0;
-
-    private void clearLastKeyFrame() {
-        lastKF = UNDEFINED_KEYFRAME;
-    }
-
-    public void jumpTo(long ticks, boolean forceJump) {
-        lastKF = UNDEFINED_KEYFRAME;
-        curTicks = ticks;
-        if (timeline.getStatus() != Status.STOPPED || forceJump) {
-            if (forceJump) {
-                clipInterpolator.validate(false);
-            }
-            clipInterpolator.interpolate(ticks);
-        }
-    }
-
-    public void start(boolean forceSync) {
-        clearLastKeyFrame();
-        clipInterpolator.validate(forceSync);
-        if (curTicks > 0) {
-            clipInterpolator.interpolate(curTicks);
-        }
-    }
-
-    /**
-     * Called to visit all keyframes within a specified time-interval.
-     */
-    public void playTo(long ticks) {
-        aborted = false;
-        final boolean forward = curTicks <= ticks;
-
-        if (forward) {
-            final int fromKF = (lastKF == UNDEFINED_KEYFRAME) ? 0
-                    : (keyFrameTicks[lastKF] <= curTicks) ? lastKF + 1
-                            : lastKF;
-            final int toKF = keyFrames.length;
-            for (int fi = fromKF; fi < toKF; fi++) {
-                final long kfTicks = keyFrameTicks[fi];
-                if (kfTicks > ticks) {
-                    lastKF = fi - 1;
-                    break;
-                }
-                if (kfTicks >= curTicks) {
-                    visitKeyFrame(fi, kfTicks);
-                    if (aborted) {
-                        break;
-                    }
-                }
-            }
-        } else {
-            final int fromKF = (lastKF == UNDEFINED_KEYFRAME) ? keyFrames.length - 1
-                    : (keyFrameTicks[lastKF] >= curTicks) ? lastKF - 1
-                            : lastKF;
-            for (int fi = fromKF; fi >= 0; fi--) {
-                final long kfTicks = keyFrameTicks[fi];
-                if (kfTicks < ticks) {
-                    lastKF = fi + 1;
-                    break;
-                }
-                if (kfTicks <= curTicks) {
-                    visitKeyFrame(fi, kfTicks);
-                    if (aborted) {
-                        break;
-                    }
-                }
-            }
-        }
-        if (!aborted
-                && ((lastKF == UNDEFINED_KEYFRAME)
-                        || keyFrameTicks[lastKF] != ticks || (keyFrames[lastKF]
-                        .getOnFinished() == null))) {
-            setTime(ticks);
-            clipInterpolator.interpolate(ticks);
-        }
-    }
-
-    private void setTime(long ticks) {
-        curTicks = ticks;
-        AnimationAccessor.getDefault().setCurrentTicks(timeline, ticks);
-    }
-
-    /**
-     * Visit a single keyframe.
-     * 
-     * @param kfIndex
-     *            the index of the keyframe in the keyframe-array
-     * @param kfTicks
-     *            the time of that keyframe
-     */
-    private void visitKeyFrame(int kfIndex, long kfTicks) {
-        if (kfIndex != lastKF) { // suppress double visiting on toggle for
-                                 // autoReverse
-            lastKF = kfIndex;
-
-            final KeyFrame kf = keyFrames[kfIndex];
-            final EventHandler<ActionEvent> onFinished = kf.getOnFinished();
-
-            if (onFinished != null) {
-                // visit the action of this keyframe
-                setTime(kfTicks);
-                clipInterpolator.interpolate(kfTicks);
-                try {
-                    onFinished.handle(new ActionEvent(kf, null));
-                } catch (Throwable ex) {
-                    ex.printStackTrace();
-                }
-            }
-        }
-    }
-}
--- a/modules/base/src/main/java/javafx/animation/Animation.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1119 +0,0 @@
-/*
- * Copyright (c) 2010, 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.animation;
-
-import java.util.HashMap;
-import javafx.beans.property.BooleanProperty;
-import javafx.beans.property.DoubleProperty;
-import javafx.beans.property.DoublePropertyBase;
-import javafx.beans.property.IntegerProperty;
-import javafx.beans.property.IntegerPropertyBase;
-import javafx.beans.property.ObjectProperty;
-import javafx.beans.property.ObjectPropertyBase;
-import javafx.beans.property.ReadOnlyDoubleProperty;
-import javafx.beans.property.ReadOnlyDoublePropertyBase;
-import javafx.beans.property.ReadOnlyObjectProperty;
-import javafx.beans.property.ReadOnlyObjectPropertyBase;
-import javafx.beans.property.SimpleBooleanProperty;
-import javafx.beans.property.SimpleObjectProperty;
-import javafx.collections.FXCollections;
-import javafx.collections.ObservableMap;
-import javafx.event.ActionEvent;
-import javafx.event.EventHandler;
-import javafx.util.Duration;
-import com.sun.javafx.animation.TickCalculation;
-import com.sun.scenario.ToolkitAccessor;
-import com.sun.scenario.animation.AbstractMasterTimer;
-import com.sun.scenario.animation.shared.ClipEnvelope;
-import com.sun.scenario.animation.shared.PulseReceiver;
-
-import static com.sun.javafx.animation.TickCalculation.*;
-
-/**
- * The class {@code Animation} provides the core functionality of all animations
- * used in the JavaFX runtime.
- * <p>
- * An animation can run in a loop by setting {@link #cycleCount}. To make an
- * animation run back and forth while looping, set the {@link #autoReverse}
- * -flag.
- * <p>
- * Call {@link #play()} or {@link #playFromStart()} to play an {@code Animation}
- * . The {@code Animation} progresses in the direction and speed specified by
- * {@link #rate}, and stops when its duration is elapsed. An {@code Animation}
- * with indefinite duration (a {@link #cycleCount} of {@link #INDEFINITE}) runs
- * repeatedly until the {@link #stop()} method is explicitly called, which will
- * stop the running {@code Animation} and reset its play head to the initial
- * position.
- * <p>
- * An {@code Animation} can be paused by calling {@link #pause()}, and the next
- * {@link #play()} call will resume the {@code Animation} from where it was
- * paused.
- * <p>
- * An {@code Animation}'s play head can be randomly positioned, whether it is
- * running or not. If the {@code Animation} is running, the play head jumps to
- * the specified position immediately and continues playing from new position.
- * If the {@code Animation} is not running, the next {@link #play()} will start
- * the {@code Animation} from the specified position.
- * <p>
- * Inverting the value of {@link #rate} toggles the play direction.
- * 
- * @see Timeline
- * @see Transition
- * 
- * @since JavaFX 2.0
- */
-public abstract class Animation {
-
-    static {
-        AnimationAccessorImpl.DEFAULT = new AnimationAccessorImpl();
-    }
-
-    /**
-     * Used to specify an animation that repeats indefinitely, until the
-     * {@code stop()} method is called.
-     */
-    public static final int INDEFINITE = -1;
-
-    /**
-     * The possible states for {@link Animation#statusProperty status}.
-     * @since JavaFX 2.0
-     */
-    public static enum Status {
-        /**
-         * The paused state.
-         */
-        PAUSED,
-        /**
-         * The running state.
-         */
-        RUNNING,
-        /**
-         * The stopped state.
-         */
-        STOPPED
-    }
-
-    private static final double EPSILON = 1e-12;
-
-    /*
-        These four fields and associated methods were moved here from AnimationPulseReceiver
-        when that class was removed. They could probably be integrated much cleaner into Animation,
-        but to make sure the change was made without introducing regressions, this code was
-        moved pretty much verbatim.
-     */
-    private long startTime;
-    private long pauseTime;
-    private boolean paused = false;
-    private final AbstractMasterTimer timer;
-
-    private long now() {
-        return TickCalculation.fromNano(timer.nanos());
-    }
-
-    void startReceiver(long delay) {
-        paused = false;
-        startTime = now() + delay;
-        timer.addPulseReceiver(pulseReceiver);
-    }
-
-    void pauseReceiver() {
-        if (!paused) {
-            pauseTime = now();
-            paused = true;
-            timer.removePulseReceiver(pulseReceiver);
-        }
-    }
-
-    void resumeReceiver() {
-        if (paused) {
-            final long deltaTime = now() - pauseTime;
-            startTime += deltaTime;
-            paused = false;
-            timer.addPulseReceiver(pulseReceiver);
-        }
-    }
-
-    // package private only for the sake of testing
-    final PulseReceiver pulseReceiver = new PulseReceiver() {
-        @Override public void timePulse(long now) {
-            final long elapsedTime = now - startTime;
-            if (elapsedTime < 0) {
-                return;
-            }
-
-            impl_timePulse(elapsedTime);
-        }
-    };
-
-    private class CurrentRateProperty extends ReadOnlyDoublePropertyBase {
-        private double value;
-        
-        @Override
-        public Object getBean() {
-            return Animation.this;
-        }
-
-        @Override
-        public String getName() {
-            return "currentRate";
-        }
-
-        @Override
-        public double get() {
-            return value;
-        }
-        
-        private void set(double value) {
-            this.value = value;
-            fireValueChangedEvent();
-        }
-    }
-    
-    private class AnimationReadOnlyProperty<T> extends ReadOnlyObjectPropertyBase<T> {
-        
-        private final String name;
-        private T value;
-        
-        private AnimationReadOnlyProperty(String name, T value) {
-            this.name = name;
-            this.value = value;
-        }
-
-        @Override
-        public Object getBean() {
-            return Animation.this;
-        }
-
-        @Override
-        public String getName() {
-            return name;
-        }
-
-        @Override
-        public T get() {
-            return value;
-        }
-        
-        private void set(T value) {
-            this.value = value;
-            fireValueChangedEvent();
-        }
-    }
-    
-    /**
-     * The parent of this {@code Animation}. If this animation has not been
-     * added to another animation, such as {@link ParallelTransition} and
-     * {@link SequentialTransition}, then parent will be null.
-     *
-     * @defaultValue null
-     */
-    Animation parent = null;
-
-    /* Package-private for testing purposes */
-    ClipEnvelope clipEnvelope;
-
-    private boolean lastPlayedFinished = false;
-    
-    private boolean lastPlayedForward = true;
-    /**
-     * Defines the direction/speed at which the {@code Animation} is expected to
-     * be played.
-     * <p>
-     * The absolute value of {@code rate} indicates the speed which the
-     * {@code Animation} is to be played, while the sign of {@code rate}
-     * indicates the direction. A positive value of {@code rate} indicates
-     * forward play, a negative value indicates backward play and {@code 0.0} to
-     * stop a running {@code Animation}.
-     * <p>
-     * Rate {@code 1.0} is normal play, {@code 2.0} is 2 time normal,
-     * {@code -1.0} is backwards, etc...
-     * 
-     * <p>
-     * Inverting the rate of a running {@code Animation} will cause the
-     * {@code Animation} to reverse direction in place and play back over the
-     * portion of the {@code Animation} that has already elapsed.
-     * 
-     * @defaultValue 1.0
-     */
-    private DoubleProperty rate;
-    private static final double DEFAULT_RATE = 1.0;
-
-    public final void setRate(double value) {
-        if ((rate != null) || (Math.abs(value - DEFAULT_RATE) > EPSILON)) {
-            rateProperty().set(value);
-        }
-    }
-
-    public final double getRate() {
-        return (rate == null)? DEFAULT_RATE : rate.get();
-    }
-
-    public final DoubleProperty rateProperty() {
-        if (rate == null) {
-            rate = new DoublePropertyBase(DEFAULT_RATE) {
-
-                @Override
-                public void invalidated() {
-                    final double newRate = getRate();
-                    if (isRunningEmbedded()) {
-                        if (isBound()) {
-                            unbind();
-                        }
-                        set(oldRate);
-                        throw new IllegalArgumentException("Cannot set rate of embedded animation while running.");
-                    } else {
-                        if (Math.abs(newRate) < EPSILON) {
-                            if (getStatus() == Status.RUNNING) {
-                                lastPlayedForward = (Math.abs(getCurrentRate()
-                                        - oldRate) < EPSILON);
-                            }
-                            setCurrentRate(0.0);
-                            pauseReceiver();
-                        } else {
-                            if (getStatus() == Status.RUNNING) {
-                                final double currentRate = getCurrentRate();
-                                if (Math.abs(currentRate) < EPSILON) {
-                                    setCurrentRate(lastPlayedForward ? newRate : -newRate);
-                                    resumeReceiver();
-                                } else {
-                                    final boolean playingForward = Math.abs(currentRate - oldRate) < EPSILON;
-                                    setCurrentRate(playingForward ? newRate : -newRate);
-                                }
-                            }
-                            oldRate = newRate;
-                        }
-                        clipEnvelope.setRate(newRate);
-                    }
-                }
-
-                @Override
-                public Object getBean() {
-                    return Animation.this;
-                }
-
-                @Override
-                public String getName() { 
-                    return "rate";
-                }
-            };
-        }
-        return rate;
-    }
-
-    private boolean isRunningEmbedded() {
-        if (parent == null) {
-            return false;
-        }
-        return parent.getStatus() != Status.STOPPED || parent.isRunningEmbedded();
-    }
-
-    private double oldRate = 1.0;
-    /**
-     * Read-only variable to indicate current direction/speed at which the
-     * {@code Animation} is being played.
-     * <p>
-     * {@code currentRate} is not necessary equal to {@code rate}.
-     * {@code currentRate} is set to {@code 0.0} when animation is paused or
-     * stopped. {@code currentRate} may also point to different direction during
-     * reverse cycles when {@code autoReverse} is {@code true}
-     * 
-     * @defaultValue 0.0
-     */
-    private ReadOnlyDoubleProperty currentRate;
-    private static final double DEFAULT_CURRENT_RATE = 0.0;
-    
-    private void setCurrentRate(double value) {
-        if ((currentRate != null) || (Math.abs(value - DEFAULT_CURRENT_RATE) > EPSILON)) {
-            ((CurrentRateProperty)currentRateProperty()).set(value);
-        }
-    }
-
-    public final double getCurrentRate() {
-        return (currentRate == null)? DEFAULT_CURRENT_RATE : currentRate.get();
-    }
-
-    public final ReadOnlyDoubleProperty currentRateProperty() {
-        if (currentRate == null) {
-            currentRate = new CurrentRateProperty();
-        }
-        return currentRate;
-    }
-
-    /**
-     * Read-only variable to indicate the duration of one cycle of this
-     * {@code Animation}: the time it takes to play from time 0 to the
-     * end of the Animation (at the default {@code rate} of
-     * 1.0).
-     * 
-     * @defaultValue 0ms
-     */
-    private ReadOnlyObjectProperty<Duration> cycleDuration;
-    private static final Duration DEFAULT_CYCLE_DURATION = Duration.ZERO;
-
-    protected final void setCycleDuration(Duration value) {
-        if ((cycleDuration != null) || (!DEFAULT_CYCLE_DURATION.equals(value))) {
-            if (value.lessThan(Duration.ZERO)) {
-                throw new IllegalArgumentException("Cycle duration cannot be negative");
-            }
-            ((AnimationReadOnlyProperty<Duration>)cycleDurationProperty()).set(value);
-            updateTotalDuration();
-        }
-    }
-
-    public final Duration getCycleDuration() {
-        return (cycleDuration == null)? DEFAULT_CYCLE_DURATION : cycleDuration.get();
-    }
-
-    public final ReadOnlyObjectProperty<Duration> cycleDurationProperty() {
-        if (cycleDuration == null) {
-            cycleDuration = new AnimationReadOnlyProperty<Duration>("cycleDuration", DEFAULT_CYCLE_DURATION);
-        }
-        return cycleDuration;
-    }
-
-    /**
-     * Read-only variable to indicate the total duration of this
-     * {@code Animation}, including repeats. A {@code Animation} with a {@code cycleCount}
-     * of {@code Animation.INDEFINITE} will have a {@code totalDuration} of
-     * {@code Duration.INDEFINITE}.
-     * 
-     * <p>
-     * This is set to cycleDuration * cycleCount.
-     * 
-     * @defaultValue 0ms
-     */
-    private ReadOnlyObjectProperty<Duration> totalDuration;
-    private static final Duration DEFAULT_TOTAL_DURATION = Duration.ZERO;
-
-    public final Duration getTotalDuration() {
-        return (totalDuration == null)? DEFAULT_TOTAL_DURATION : totalDuration.get();
-    }
-
-    public final ReadOnlyObjectProperty<Duration> totalDurationProperty() {
-        if (totalDuration == null) {
-            totalDuration = new AnimationReadOnlyProperty<Duration>("totalDuration", DEFAULT_TOTAL_DURATION);
-        }
-        return totalDuration;
-    }
-
-    private void updateTotalDuration() {
-        // Implementing the bind eagerly, because cycleCount and
-        // cycleDuration should not change that often
-        final int cycleCount = getCycleCount();
-        final Duration cycleDuration = getCycleDuration();
-        final Duration newTotalDuration = Duration.ZERO.equals(cycleDuration) ? Duration.ZERO
-                : (cycleCount == Animation.INDEFINITE) ? Duration.INDEFINITE
-                        : (cycleCount <= 1) ? cycleDuration : cycleDuration
-                                .multiply(cycleCount);
-        if ((totalDuration != null) || (!DEFAULT_TOTAL_DURATION.equals(newTotalDuration))) {
-            ((AnimationReadOnlyProperty<Duration>)totalDurationProperty()).set(newTotalDuration);
-        }
-        if (newTotalDuration.lessThan(getCurrentTime())) {
-            jumpTo(newTotalDuration);
-        }
-    }
-
-    /**
-     * Defines the {@code Animation}'s play head position.
-     * 
-     * @defaultValue 0ms
-     */
-    private CurrentTimeProperty currentTime;
-    private long currentTicks;
-    private class CurrentTimeProperty extends ReadOnlyObjectPropertyBase<Duration> {
-        
-        @Override
-        public Object getBean() {
-            return Animation.this;
-        }
-
-        @Override
-        public String getName() {
-            return "currentTime";
-        }
-
-        @Override
-        public Duration get() {
-            return getCurrentTime();
-        }
-        
-        @Override
-        public void fireValueChangedEvent() {
-            super.fireValueChangedEvent();
-        }
-        
-    }
-    
-    public final Duration getCurrentTime() {
-        return TickCalculation.toDuration(currentTicks);
-    }
-
-    public final ReadOnlyObjectProperty<Duration> currentTimeProperty() {
-        if (currentTime == null) {
-            currentTime = new CurrentTimeProperty();
-        }
-        return currentTime;
-    }
-
-    /**
-     * Delays the start of an animation.
-     *
-     * Cannot be negative. Setting to a negative number will result in {@link IllegalArgumentException}.
-     * 
-     * @defaultValue 0ms
-     */
-    private ObjectProperty<Duration> delay;
-    private static final Duration DEFAULT_DELAY = Duration.ZERO;
-
-    public final void setDelay(Duration value) {
-        if ((delay != null) || (!DEFAULT_DELAY.equals(value))) {
-            delayProperty().set(value);
-        }
-    }
-
-    public final Duration getDelay() {
-        return (delay == null)? DEFAULT_DELAY : delay.get();
-    }
-
-    public final ObjectProperty<Duration> delayProperty() {
-        if (delay == null) {
-            delay = new ObjectPropertyBase<Duration>(DEFAULT_DELAY) {
-
-                @Override
-                public Object getBean() {
-                    return Animation.this;
-                }
-
-                @Override
-                public String getName() {
-                    return "delay";
-                }
-
-                @Override
-                protected void invalidated() {
-                        final Duration newDuration = get();
-                        if (newDuration.lessThan(Duration.ZERO)) {
-                            if (isBound()) {
-                                unbind();
-                            }
-                            set(Duration.ZERO);
-                            throw new IllegalArgumentException("Cannot set delay to negative value. Setting to Duration.ZERO");
-                        }
-                }
-                
-            };
-        }
-        return delay;
-    }
-
-    /**
-     * Defines the number of cycles in this animation. The {@code cycleCount}
-     * may be {@code INDEFINITE} for animations that repeat indefinitely, but
-     * must otherwise be > 0.
-     * <p>
-     * It is not possible to change the {@code cycleCount} of a running
-     * {@code Animation}. If the value of {@code cycleCount} is changed for a
-     * running {@code Animation}, the animation has to be stopped and started again to pick
-     * up the new value.
-     * 
-     * @defaultValue 1.0
-     * 
-     */
-    private IntegerProperty cycleCount;
-    private static final int DEFAULT_CYCLE_COUNT = 1;
-
-    public final void setCycleCount(int value) {
-        if ((cycleCount != null) || (value != DEFAULT_CYCLE_COUNT)) {
-            cycleCountProperty().set(value);
-        }
-    }
-
-    public final int getCycleCount() {
-        return (cycleCount == null)? DEFAULT_CYCLE_COUNT : cycleCount.get();
-    }
-
-    public final IntegerProperty cycleCountProperty() {
-        if (cycleCount == null) {
-            cycleCount = new IntegerPropertyBase(DEFAULT_CYCLE_COUNT) {
-
-                @Override
-                public void invalidated() {
-                    updateTotalDuration();
-                }
-
-                @Override
-                public Object getBean() {
-                    return Animation.this;
-                }
-
-                @Override
-                public String getName() {
-                    return "cycleCount";
-                }
-            };
-        }
-        return cycleCount;
-    }
-
-    /**
-     * Defines whether this
-     * {@code Animation} reverses direction on alternating cycles. If
-     * {@code true}, the
-     * {@code Animation} will proceed forward on the first cycle,
-     * then reverses on the second cycle, and so on. Otherwise, animation will
-     * loop such that each cycle proceeds forward from the start.
-     * 
-     * It is not possible to change the {@code autoReverse} flag of a running
-     * {@code Animation}. If the value of {@code autoReverse} is changed for a
-     * running {@code Animation}, the animation has to be stopped and started again to pick
-     * up the new value.
-     * 
-     * @defaultValue false
-     */
-    private BooleanProperty autoReverse;
-    private static final boolean DEFAULT_AUTO_REVERSE = false;
-
-    public final void setAutoReverse(boolean value) {
-        if ((autoReverse != null) || (value != DEFAULT_AUTO_REVERSE)) {
-            autoReverseProperty().set(value);
-        }
-    }
-
-    public final boolean isAutoReverse() {
-        return (autoReverse == null)? DEFAULT_AUTO_REVERSE : autoReverse.get();
-    }
-
-    public final BooleanProperty autoReverseProperty() {
-        if (autoReverse == null) {
-            autoReverse = new SimpleBooleanProperty(this, "autoReverse", DEFAULT_AUTO_REVERSE);
-        }
-        return autoReverse;
-    }
-
-    /**
-     * The status of the {@code Animation}.
-     * 
-     * In {@code Animation} can be in one of three states:
-     * {@link Status#STOPPED}, {@link Status#PAUSED} or {@link Status#RUNNING}.
-     */
-    private ReadOnlyObjectProperty<Status> status;
-    private static final Status DEFAULT_STATUS = Status.STOPPED;
-
-    protected final void setStatus(Status value) {
-        if ((status != null) || (!DEFAULT_STATUS.equals(value))) {
-            ((AnimationReadOnlyProperty<Status>)statusProperty()).set(value);
-        }
-    }
-
-    public final Status getStatus() {
-        return (status == null)? DEFAULT_STATUS : status.get();
-    }
-
-    public final ReadOnlyObjectProperty<Status> statusProperty() {
-        if (status == null) {
-            status = new AnimationReadOnlyProperty<Status>("status", Status.STOPPED);
-        }
-        return status;
-    }
-    
-    private final double targetFramerate;
-    private final int resolution;
-    private long lastPulse;
-
-    /**
-     * The target framerate is the maximum framerate at which this {@code Animation}
-     * will run, in frames per second. This can be used, for example, to keep
-     * particularly complex {@code Animations} from over-consuming system resources.
-     * By default, an {@code Animation}'s framerate is not explicitly limited, meaning
-     * the {@code Animation} will run at an optimal framerate for the underlying platform.
-     *
-     * @return the target framerate
-     */
-    public final double getTargetFramerate() {
-        return targetFramerate;
-    }
-
-    /**
-     * The action to be executed at the conclusion of this {@code Animation}.
-     *
-     * @defaultValue null
-     */
-    private ObjectProperty<EventHandler<ActionEvent>> onFinished;
-    private static final EventHandler<ActionEvent> DEFAULT_ON_FINISHED = null;
-
-    public final void setOnFinished(EventHandler<ActionEvent> value) {
-        if ((onFinished != null) || (value != null /* DEFAULT_ON_FINISHED */)) {
-            onFinishedProperty().set(value);
-        }
-    }
-
-    public final EventHandler<ActionEvent> getOnFinished() {
-        return (onFinished == null)? DEFAULT_ON_FINISHED : onFinished.get();
-    }
-
-    public final ObjectProperty<EventHandler<ActionEvent>> onFinishedProperty() {
-        if (onFinished == null) {
-            onFinished = new SimpleObjectProperty<EventHandler<ActionEvent>>(this, "onFinished", DEFAULT_ON_FINISHED);
-        }
-        return onFinished;
-    }
-
-    private final ObservableMap<String, Duration> cuePoints = FXCollections
-            .observableMap(new HashMap<String, Duration>(0));
-
-    /**
-     * The cue points can be
-     * used to mark important positions of the {@code Animation}. Once a cue
-     * point was defined, it can be used as an argument of
-     * {@link #jumpTo(String) jumpTo()} and {@link #playFrom(String) playFrom()}
-     * to move to the associated position quickly.
-     * <p>
-     * Every {@code Animation} has two predefined cue points {@code "start"} and
-     * {@code "end"}, which are set at the start respectively the end of the
-     * {@code Animation}. The predefined cuepoints do not appear in the map,
-     * attempts to override them have no effect.
-     * <p>
-     * Another option to define a cue point in a {@code Animation} is to set the
-     * {@link KeyFrame#name} property of a {@link KeyFrame}.
-     *
-     * @return {@link javafx.collections.ObservableMap} of cue points
-     */
-    public final ObservableMap<String, Duration> getCuePoints() {
-        return cuePoints;
-    }
-
-    /**
-     * Jumps to a given position in this {@code Animation}.
-     * 
-     * If the given time is less than {@link Duration#ZERO}, this method will
-     * jump to the start of the animation. If the given time is larger than the
-     * duration of this {@code Animation}, this method will jump to the end.
-     * 
-     * @param time
-     *            the new position
-     * @throws NullPointerException
-     *             if {@code time} is {@code null}
-     * @throws IllegalArgumentException
-     *             if {@code time} is {@link Duration#UNKNOWN}
-     * @throws IllegalStateException
-     *             if embedded in another animation,
-     *                such as {@link SequentialTransition} or {@link ParallelTransition}
-     */
-    public void jumpTo(Duration time) {
-        if (time == null) {
-            throw new NullPointerException("Time needs to be specified.");
-        }
-        if (time.isUnknown()) {
-            throw new IllegalArgumentException("The time is invalid");
-        }
-        if (parent != null) {
-            throw new IllegalStateException("Cannot jump when embedded in another animation");
-        }
-
-        lastPlayedFinished = false;
-        
-        final Duration totalDuration = getTotalDuration();
-        time = time.lessThan(Duration.ZERO) ? Duration.ZERO : time
-                .greaterThan(totalDuration) ? totalDuration : time;
-        final long ticks = fromDuration(time);
-
-        if (getStatus() == Status.STOPPED) {
-            syncClipEnvelope();
-        }
-        clipEnvelope.jumpTo(ticks);
-    }
-
-    /**
-     * Jumps to a predefined position in this {@code Animation}. This method
-     * looks for an entry in cue points and jumps to the associated
-     * position, if it finds one.
-     * <p>
-     * If the cue point is behind the end of this {@code Animation}, calling
-     * {@code jumpTo} will result in a jump to the end. If the cue point has a
-     * negative {@link javafx.util.Duration} it will result in a jump to the
-     * beginning. If the cue point has a value of
-     * {@link javafx.util.Duration#UNKNOWN} calling {@code jumpTo} will have no
-     * effect for this cue point.
-     * <p>
-     * There are two predefined cue points {@code "start"} and {@code "end"}
-     * which are defined to be at the start respectively the end of this
-     * {@code Animation}.
-     * 
-     * @param cuePoint
-     *            the name of the cue point
-     * @throws NullPointerException
-     *             if {@code cuePoint} is {@code null}
-     * @throws IllegalStateException
-     *             if embedded in another animation,
-     *                such as {@link SequentialTransition} or {@link ParallelTransition}
-     * @see #getCuePoints()
-     */
-    public void jumpTo(String cuePoint) {
-        if (cuePoint == null) {
-            throw new NullPointerException("CuePoint needs to be specified");
-        }
-        if ("start".equalsIgnoreCase(cuePoint)) {
-            jumpTo(Duration.ZERO);
-        } else if ("end".equalsIgnoreCase(cuePoint)) {
-            jumpTo(getTotalDuration());
-        } else {
-            final Duration target = getCuePoints().get(cuePoint);
-            if (target != null) {
-                jumpTo(target);
-            }
-        }
-    }
-
-    /**
-     * A convenience method to play this {@code Animation} from a predefined
-     * position. The position has to be predefined in cue points.
-     * Calling this method is equivalent to
-     * 
-     * <pre>
-     * <code>
-     * animation.jumpTo(cuePoint);
-     * animation.play();
-     * </code>
-     * </pre>
-     * 
-     * Note that unlike {@link #playFromStart()} calling this method will not
-     * change the playing direction of this {@code Animation}.
-     * 
-     * @param cuePoint
-     *            name of the cue point
-     * @throws NullPointerException
-     *             if {@code cuePoint} is {@code null}
-     * @throws IllegalStateException
-     *             if embedded in another animation,
-     *                such as {@link SequentialTransition} or {@link ParallelTransition}
-     * @see #getCuePoints()
-     */
-    public void playFrom(String cuePoint) {
-        jumpTo(cuePoint);
-        play();
-    }
-
-    /**
-     * A convenience method to play this {@code Animation} from a specific
-     * position. Calling this method is equivalent to
-     * 
-     * <pre>
-     * <code>
-     * animation.jumpTo(time);
-     * animation.play();
-     * </code>
-     * </pre>
-     * 
-     * Note that unlike {@link #playFromStart()} calling this method will not
-     * change the playing direction of this {@code Animation}.
-     * 
-     * @param time
-     *            position where to play from
-     * @throws NullPointerException
-     *             if {@code time} is {@code null}
-     * @throws IllegalArgumentException
-     *             if {@code time} is {@link Duration#UNKNOWN}
-     * @throws IllegalStateException
-     *             if embedded in another animation,
-     *                such as {@link SequentialTransition} or {@link ParallelTransition}
-     */
-    public void playFrom(Duration time) {
-        jumpTo(time);
-        play();
-    }
-
-    /**
-     * Plays {@code Animation} from current position in the direction indicated
-     * by {@code rate}. If the {@code Animation} is running, it has no effect.
-     * <p>
-     * When {@code rate} > 0 (forward play), if an {@code Animation} is already
-     * positioned at the end, the first cycle will not be played, it is
-     * considered to have already finished. This also applies to a backward (
-     * {@code rate} < 0) cycle if an {@code Animation} is positioned at the beginning.
-     * However, if the {@code Animation} has {@code cycleCount} > 1, following
-     * cycle(s) will be played as usual.
-     * <p>
-     * When the {@code Animation} reaches the end, the {@code Animation} is stopped and
-     * the play head remains at the end.
-     * <p>
-     * To play an {@code Animation} backwards from the end:<br>
-     * <code>
-     *  animation.setRate(negative rate);<br>
-     *  animation.jumpTo(overall duration of animation);<br>
-     *  animation.play();<br>
-     * </code>
-     * <p>
-     * Note: <ul>
-     * <li>{@code play()} is an asynchronous call, the {@code Animation} may not
-     * start immediately. </ul>
-     *
-     * @throws IllegalStateException
-     *             if embedded in another animation,
-     *                such as {@link SequentialTransition} or {@link ParallelTransition}
-     */
-    public void play() {
-        play(true);
-    }
-
-    private void play(boolean forceSync) {
-        if (parent != null) {
-            throw new IllegalStateException("Cannot start when embedded in another animation");
-        }
-        switch (getStatus()) {
-            case STOPPED:
-                if (impl_startable(forceSync)) {
-                    final double rate = getRate();
-                    if (lastPlayedFinished) {
-                        jumpTo((rate < 0)? getTotalDuration() : Duration.ZERO);
-                    }
-                    lastPlayedFinished = false;
-                    impl_start(forceSync);
-                    startReceiver(TickCalculation.fromDuration(getDelay()));
-                    if (Math.abs(rate) < EPSILON) {
-                        pauseReceiver();
-                    } else {
-                        
-                    }
-                } else {
-                    final EventHandler<ActionEvent> handler = getOnFinished();
-                    if (handler != null) {
-                        handler.handle(new ActionEvent(this, null));
-                    }
-                }
-                break;
-            case PAUSED:
-                impl_resume();
-                if (Math.abs(getRate()) >= EPSILON) {
-                    resumeReceiver();
-                }
-                break;
-        }
-    }
-
-    /**
-     * Plays an {@code Animation} from initial position in forward direction.
-     * <p>
-     * It is equivalent to
-     * <p>
-     * <code>
-     *      animation.stop();<br>
-     *      animation.setRate = setRate(Math.abs(animation.getRate())); </br>
-     *      animation.jumpTo(Duration.ZERO);<br>
-     *      animation.play();<br>
-     *  </code>
-     * 
-     * <p>
-     * Note: <ul>
-     * <li>{@code playFromStart()} is an asynchronous call, {@code Animation} may
-     * not start immediately. </ul>
-     * <p>
-     *
-     * @throws IllegalStateException
-     *             if embedded in another animation,
-     *                such as {@link SequentialTransition} or {@link ParallelTransition}
-     */
-    public void playFromStart() {
-        stop();
-        setRate(Math.abs(getRate()));
-        jumpTo(Duration.ZERO);
-        play(true);
-    }
-
-    /**
-     * Stops the animation and resets the play head to its initial position. If
-     * the animation is not currently running, this method has no effect.
-     * <p>
-     * Note: <ul>
-     * <li>{@code stop()} is an asynchronous call, the {@code Animation} may not stop
-     * immediately. </ul>
-     * @throws IllegalStateException
-     *             if embedded in another animation,
-     *                such as {@link SequentialTransition} or {@link ParallelTransition}
-     */
-    public void stop() {
-        if (parent != null) {
-            throw new IllegalStateException("Cannot stop when embedded in another animation");
-        }
-        if (getStatus() != Status.STOPPED) {
-            clipEnvelope.abortCurrentPulse();
-            impl_stop();
-            jumpTo(Duration.ZERO);
-        }
-    }
-
-    /**
-     * Pauses the animation. If the animation is not currently running, this
-     * method has no effect.
-     * <p>
-     * Note: <ul>
-     * <li>{@code pause()} is an asynchronous call, the {@code Animation} may not pause
-     * immediately. </ul>
-     * @throws IllegalStateException
-     *             if embedded in another animation,
-     *                such as {@link SequentialTransition} or {@link ParallelTransition}
-     */
-    public void pause() {
-        if (parent != null) {
-            throw new IllegalStateException("Cannot pause when embedded in another animation");
-        }
-        if (getStatus() == Status.RUNNING) {
-            clipEnvelope.abortCurrentPulse();
-            pauseReceiver();
-            impl_pause();
-        }
-    }
-
-    /**
-     * The constructor of {@code Animation}.
-     * 
-     * This constructor allows to define a target framerate.
-     * 
-     * @param targetFramerate
-     *            The custom target frame rate for this {@code Animation}
-     * @see #getTargetFramerate()
-     */
-    protected Animation(double targetFramerate) {
-        this.targetFramerate = targetFramerate;
-        this.resolution = (int) Math.max(1, Math.round(TickCalculation.TICKS_PER_SECOND / targetFramerate));
-        this.clipEnvelope = ClipEnvelope.create(this);
-        this.timer = ToolkitAccessor.getMasterTimer();
-    }
-
-    /**
-     * The constructor of {@code Animation}.
-     */
-    protected Animation() {
-        this.resolution = 1;
-        this.targetFramerate = TickCalculation.TICKS_PER_SECOND / ToolkitAccessor.getMasterTimer().getDefaultResolution();
-        this.clipEnvelope = ClipEnvelope.create(this);
-        this.timer = ToolkitAccessor.getMasterTimer();
-    }
-
-    // These constructors are only for testing purposes
-    Animation(AbstractMasterTimer timer) {
-        this.resolution = 1;
-        this.targetFramerate = TickCalculation.TICKS_PER_SECOND / timer.getDefaultResolution();
-        this.clipEnvelope = ClipEnvelope.create(this);
-        this.timer = timer;
-    }
-
-    // These constructors are only for testing purposes
-    Animation(AbstractMasterTimer timer, ClipEnvelope clipEnvelope, int resolution) {
-        this.resolution = resolution;
-        this.targetFramerate = TickCalculation.TICKS_PER_SECOND / resolution;
-        this.clipEnvelope = clipEnvelope;
-        this.timer = timer;
-    }
-
-    boolean impl_startable(boolean forceSync) {
-        return (fromDuration(getCycleDuration()) > 0L)
-                || (!forceSync && clipEnvelope.wasSynched());
-    }
-
-    void impl_sync(boolean forceSync) {
-        if (forceSync || !clipEnvelope.wasSynched()) {
-            syncClipEnvelope();
-        }
-    }
-    
-    private void syncClipEnvelope() {
-        final int publicCycleCount = getCycleCount();
-        final int internalCycleCount = (publicCycleCount <= 0)
-                && (publicCycleCount != INDEFINITE) ? 1 : publicCycleCount;
-        clipEnvelope = clipEnvelope.setCycleCount(internalCycleCount);
-        clipEnvelope.setCycleDuration(getCycleDuration());
-        clipEnvelope.setAutoReverse(isAutoReverse());
-    }
-
-    void impl_start(boolean forceSync) {
-        impl_sync(forceSync);
-        setStatus(Status.RUNNING);
-        clipEnvelope.start();
-        setCurrentRate(clipEnvelope.getCurrentRate());
-        lastPulse = 0;
-    }
-
-    void impl_pause() {
-        final double currentRate = getCurrentRate();
-        if (Math.abs(currentRate) >= EPSILON) {
-            lastPlayedForward = Math.abs(getCurrentRate() - getRate()) < EPSILON;
-        }
-        setCurrentRate(0.0);
-        setStatus(Status.PAUSED);
-    }
-
-    void impl_resume() {
-        setStatus(Status.RUNNING);
-        setCurrentRate(lastPlayedForward ? getRate() : -getRate());
-    }
-
-    void impl_stop() {
-        if (!paused) {
-            timer.removePulseReceiver(pulseReceiver);
-        }
-        setStatus(Status.STOPPED);
-        setCurrentRate(0.0);
-    }
-
-    void impl_timePulse(long elapsedTime) {
-        if (resolution == 1) { // fullspeed
-            clipEnvelope.timePulse(elapsedTime);
-        } else if (elapsedTime - lastPulse >= resolution) {
-            lastPulse = (elapsedTime / resolution) * resolution;
-            clipEnvelope.timePulse(elapsedTime);
-        }
-    }
-
-    abstract void impl_playTo(long currentTicks, long cycleTicks);
-
-    abstract void impl_jumpTo(long currentTicks, long cycleTicks, boolean forceJump);
-
-    void impl_setCurrentTicks(long ticks) {
-        currentTicks = ticks;
-        if (currentTime != null) {
-            currentTime.fireValueChangedEvent();
-        }
-    }
-
-    void impl_setCurrentRate(double currentRate) {
-//        if (getStatus() == Status.RUNNING) {
-            setCurrentRate(currentRate);
-//        }
-    }
-
-    final void impl_finished() {
-        lastPlayedFinished = true;
-        impl_stop();
-        final EventHandler<ActionEvent> handler = getOnFinished();
-        if (handler != null) {
-            try {
-                handler.handle(new ActionEvent(this, null));
-            } catch (Exception ex) {
-                ex.printStackTrace();
-            }
-        }
-    }
-}
--- a/modules/base/src/main/java/javafx/animation/AnimationAccessorImpl.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2010, 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.animation;
-
-import com.sun.scenario.animation.shared.AnimationAccessor;
-
-final class AnimationAccessorImpl extends AnimationAccessor{
-
-    @Override
-    public void setCurrentRate(Animation animation, double currentRate) {
-        animation.impl_setCurrentRate(currentRate);
-    }
-
-    @Override
-    public void playTo(Animation animation, long pos, long cycleTicks) {
-        animation.impl_playTo(pos, cycleTicks);
-    }
-
-    @Override
-    public void jumpTo(Animation animation, long pos, long cycleTicks, boolean forceJump) {
-        animation.impl_jumpTo(pos, cycleTicks, forceJump);
-    }
-
-    @Override
-    public void finished(Animation animation) {
-        animation.impl_finished();
-    }
-
-    @Override
-    public void setCurrentTicks(Animation animation, long ticks) {
-        animation.impl_setCurrentTicks(ticks);
-    }
-
-    
-}
--- a/modules/base/src/main/java/javafx/animation/AnimationTimer.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 2011, 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.animation;
-
-import com.sun.scenario.ToolkitAccessor;
-import com.sun.scenario.animation.AbstractMasterTimer;
-
-/**
- * The class {@code AnimationTimer} allows to create a timer, that is called in
- * each frame while it is active.
- * 
- * An extending class has to override the method {@link #handle(long)} which
- * will be called in every frame.
- * 
- * The methods {@link AnimationTimer#start()} and {@link #stop()} allow to start
- * and stop the timer.
- * 
- * 
- * @since JavaFX 2.0
- */
-public abstract class AnimationTimer {
-    
-    private final AbstractMasterTimer timer;
-    private boolean active;
-    
-    public AnimationTimer() {
-        timer = ToolkitAccessor.getMasterTimer();
-    }
-    
-    // For testing only
-    AnimationTimer(AbstractMasterTimer timer) {
-        this.timer = timer;
-    }
-    
-    /**
-     * This method needs to be overridden by extending classes. It is going to
-     * be called in every frame while the {@code AnimationTimer} is active.
-     * 
-     * @param now
-     *            The timestamp of the current frame given in nanoseconds. This
-     *            value will be the same for all {@code AnimationTimers} called
-     *            during one frame.
-     */
-    public abstract void handle(long now);
-
-    /**
-     * Starts the {@code AnimationTimers}. Once it is started, the
-     * {@link #handle(long)} method of this {@code AnimationTimers} will be
-     * called in every frame.
-     * 
-     * The {@code AnimationTimers} can be stopped by calling {@link #stop()}.
-     */
-    public void start() {
-        if (!active) {
-            timer.addAnimationTimer(this);
-            active = true;
-        }
-    }
-
-    /**
-     * Stops the {@code AnimationTimers}. It can be activated again by calling
-     * {@link #start()}.
-     */
-    public void stop() {
-        if (active) {
-            timer.removeAnimationTimer(this);
-            active = false;
-        }
-    }
-}
--- a/modules/base/src/main/java/javafx/animation/Interpolatable.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2010, 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.animation;
-
-/**
- * A value that can be interpolated. It defines single
- * {@link #interpolate(Object, double)} method, which returns interpolated value
- * of given fraction.
- * @since JavaFX 2.0
- */
-public interface Interpolatable<T> {
-
-    /**
-     * The function calculates an interpolated value along the fraction
-     * {@code t} between {@code 0.0} and {@code 1.0}. When {@code t} = 1.0,
-     * {@code endVal} is returned.
-     * 
-     * @param endValue
-     *            target value
-     * @param t
-     *            fraction between {@code 0.0} and {@code 1.0}
-     * @return interpolated value
-     */
-    public T interpolate(T endValue, double t);
-}
--- a/modules/base/src/main/java/javafx/animation/Interpolator.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,400 +0,0 @@
-/*
- * Copyright (c) 2010, 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.animation;
-
-import javafx.util.Duration;
-
-import com.sun.scenario.animation.NumberTangentInterpolator;
-import com.sun.scenario.animation.SplineInterpolator;
-
-/**
- * The abstract class defines several {@code interpolate} methods, which are
- * used to calculate interpolated values. Various built-in implementations of
- * this class are offered. Applications may choose to implement their own
- * {@code Interpolator} to get custom interpolation behavior.
- * <p>
- * A custom {@code Interpolator} has to be defined in terms of a "
- * {@link #curve(double) curve()}".
- * @since JavaFX 2.0
- */
-public abstract class Interpolator {
-
-    private static final double EPSILON = 1e-12;
-
-    /**
-     * The constructor of {@code Interpolator}.
-     */
-    protected Interpolator() {
-    }
-
-    /**
-     * Built-in interpolator that provides discrete time interpolation. The
-     * return value of {@code interpolate()} is {@code endValue} only when the
-     * input {@code fraction} is 1.0, and {@code startValue} otherwise.
-     */
-    public static final Interpolator DISCRETE = new Interpolator() {
-        @Override
-        protected double curve(double t) {
-            return (Math.abs(t - 1.0) < EPSILON) ? 1.0 : 0.0;
-        }
-
-        @Override
-        public String toString() {
-            return "Interpolator.DISCRETE";
-        }
-    };
-
-    /**
-     * Built-in interpolator that provides linear time interpolation. The return
-     * value of {@code interpolate()} is {@code startValue} + ({@code endValue}
-     * - {@code startValue}) * {@code fraction}.
-     */
-    public static final Interpolator LINEAR = new Interpolator() {
-        @Override
-        protected double curve(double t) {
-            return t;
-        }
-
-        @Override
-        public String toString() {
-            return "Interpolator.LINEAR";
-        }
-    };
-
-    /*
-     * Easing is calculated with the following algorithm (taken from SMIL 3.0
-     * specs). The result is clamped because of possible rounding errors.
-     * 
-     * double runRate = 1.0 / (1.0 - acceleration/2.0 - deceleration/2.0); if
-     * (fraction < acceleration) { double averageRunRate = runRate * (fraction /
-     * acceleration) / 2; fraction *= averageRunRate; } else if (fraction > (1.0
-     * - deceleration)) { // time spent in deceleration portion double tdec =
-     * fraction - (1.0 - deceleration); // proportion of tdec to total
-     * deceleration time double pdec = tdec / deceleration; fraction = runRate *
-     * (1.0 - ( acceleration / 2) - deceleration + tdec * (2 - pdec) / 2); }
-     * else { fraction = runRate * (fraction - (acceleration / 2)); }
-     */
-
-    /**
-     * Built-in interpolator instance that provides ease in/out behavior.
-     * <p>
-     * An ease-both interpolator will make an animation start slow, then
-     * accelerate and slow down again towards the end, all in a smooth manner.
-     * <p>
-     * The implementation uses the algorithm for easing defined in SMIL 3.0
-     * with an acceleration and deceleration factor of 0.2, respectively.
-     */
-    public static final Interpolator EASE_BOTH = new Interpolator() {
-        @Override
-        protected double curve(double t) {
-            // See the SMIL 3.1 specification for details on this calculation
-            // acceleration = 0.2, deceleration = 0.2
-            return Interpolator.clamp((t < 0.2) ? 3.125 * t * t
-                    : (t > 0.8) ? -3.125 * t * t + 6.25 * t - 2.125
-                            : 1.25 * t - 0.125);
-        }
-
-        @Override
-        public String toString() {
-            return "Interpolator.EASE_BOTH";
-        }
-    };
-    /**
-     * Built-in interpolator instance that provides ease in behavior.
-     * <p>
-     * An ease-in interpolator will make an animation start slow and then
-     * accelerate smoothly.
-     * <p>
-     * The implementation uses the algorithm for easing defined in SMIL 3.0
-     * with an acceleration factor of 0.2.
-     */
-    public static final Interpolator EASE_IN = new Interpolator() {
-        private static final double S1 = 25.0 / 9.0;
-        private static final double S3 = 10.0 / 9.0;
-        private static final double S4 = 1.0 / 9.0;
-
-        @Override
-        protected double curve(double t) {
-            // See the SMIL 3.1 specification for details on this calculation
-            // acceleration = 0.2, deceleration = 0.0
-            return Interpolator.clamp((t < 0.2) ? S1 * t * t : S3 * t - S4);
-        }
-
-        @Override
-        public String toString() {
-            return "Interpolator.EASE_IN";
-        }
-    };
-
-    /**
-     * Built-in interpolator instance that provides ease out behavior.
-     * <p>
-     * An ease-out interpolator will make an animation slow down toward the
-     * end smoothly.
-     * <p>
-     * The implementation uses the algorithm for easing defined in SMIL 3.0 
-     * with an deceleration factor of 0.2.
-     */
-    public static final Interpolator EASE_OUT = new Interpolator() {
-        private static final double S1 = -25.0 / 9.0;
-        private static final double S2 = 50.0 / 9.0;
-        private static final double S3 = -16.0 / 9.0;
-        private static final double S4 = 10.0 / 9.0;
-
-        @Override
-        protected double curve(double t) {
-            // See the SMIL 3.1 specification for details on this calculation
-            // acceleration = 0.2, deceleration = 0.0
-            return Interpolator.clamp((t > 0.8) ? S1 * t * t + S2 * t + S3 : S4
-                    * t);
-        }
-
-        @Override
-        public String toString() {
-            return "Interpolator.EASE_OUT";
-        }
-    };
-
-    /**
-     * Creates an {@code Interpolator}, which {@link #curve(double) curve()} is
-     * shaped using the spline control points defined by ({@code x1}, {@code y1}
-     * ) and ({@code x2}, {@code y2}). The anchor points of the spline are
-     * implicitly defined as ({@code 0.0}, {@code 0.0}) and ({@code 1.0},
-     * {@code 1.0}).
-     * 
-     * @param x1
-     *            x coordinate of the first control point
-     * @param y1
-     *            y coordinate of the first control point
-     * @param x2
-     *            x coordinate of the second control point
-     * @param y2
-     *            y coordinate of the second control point
-     * @return A spline interpolator
-     */
-    public static Interpolator SPLINE(double x1, double y1, double x2, double y2) {
-        return new SplineInterpolator(x1, y1, x2, y2);
-    }
-
-    /**
-     * Create a tangent interpolator. A tangent interpolator allows to define
-     * the behavior of an animation curve very precisely by defining the
-     * tangents close to a key frame.
-     * 
-     * A tangent interpolator defines the behavior to the left and to the right
-     * of a key frame, therefore it is only useful within a {@link Timeline}.
-     * If used in a {@link KeyFrame} after a KeyFrame that has different interpolator,
-     * it's treated as if the out-tangent of that KeyFrame was equal to the value in the KeyFrame.
-     *
-     * <p>
-     * <img src="doc-files/tangent_interpolator.png"/>
-     * 
-     * <p>
-     * The parameters define the tangent of the animation curve for the in
-     * tangent (before a key frame) and out tangent (after a key frame). Each
-     * tangent is specified with a pair, the distance to the key frame and the
-     * value of the tangent at this moment.
-     * <p>
-     * The interpolation then follows a bezier curve, with 2 control points defined by the specified tangent and
-     * positioned at 1/3 of the duration before the second KeyFrame or after the first KeyFrame. See the picture above.
-     * 
-     * @param t1
-     *            The delta time of the in-tangent, relative to the KeyFrame
-     * @param v1
-     *            The value of the in-tangent
-     * @param t2
-     *            The delta time of the out-tangent, relative to the KeyFrame
-     * @param v2
-     *            The value of the out-tangent
-     * @return the new tangent interpolator
-     */
-    public static Interpolator TANGENT(Duration t1, double v1, Duration t2,
-            double v2) {
-        return new NumberTangentInterpolator(t1, v1, t2, v2);
-    }
-
-    /**
-     * Creates a tangent interpolator, for which in-tangent and out-tangent are
-     * identical. This is especially useful for the first and the last key frame
-     * of a {@link Timeline}, because for these key frames only one tangent is
-     * used.
-     * 
-     * @see #TANGENT(Duration, double, Duration, double)
-     * 
-     * @param t
-     *            The delta time of the tangent
-     * @param v
-     *            The value of the tangent
-     * @return the new Tangent interpolator
-     */
-    public static Interpolator TANGENT(Duration t, double v) {
-        return new NumberTangentInterpolator(t, v);
-    }
-
-    /**
-     * This method takes two {@code Objects} along with a {@code fraction}
-     * between {@code 0.0} and {@code 1.0} and returns the interpolated value.
-     * <p>
-     * If both {@code Objects} implement {@code Number}, their values are
-     * interpolated. If {@code startValue} implements {@link Interpolatable} the
-     * calculation defined in {@link Interpolatable#interpolate(Object, double)
-     * interpolate()} is used. If neither of these conditions are met, a
-     * discrete interpolation is used, i.e. {@code endValue} is returned if and
-     * only if {@code fraction} is {@code 1.0}, otherwise {@code startValue} is
-     * returned.
-     * <p>
-     * Before calculating the interpolated value, the fraction is altered
-     * according to the function defined in {@link #curve(double) curve()}.
-     * 
-     * @param startValue
-     *            start value
-     * @param endValue
-     *            end value
-     * @param fraction
-     *            a value between 0.0 and 1.0
-     * @return interpolated value
-     */
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    public Object interpolate(Object startValue, Object endValue,
-            double fraction) {
-        if ((startValue instanceof Number) && (endValue instanceof Number)) {
-            final double start = ((Number) startValue).doubleValue();
-            final double end = ((Number) endValue).doubleValue();
-            final double val = start + (end - start) * curve(fraction);
-            if ((startValue instanceof Double) || (endValue instanceof Double)) {
-                return Double.valueOf(val);
-            }
-            if ((startValue instanceof Float) || (endValue instanceof Float)) {
-                return Float.valueOf((float) val);
-            }
-            if ((startValue instanceof Long) || (endValue instanceof Long)) {
-                return Long.valueOf(Math.round(val));
-            }
-            return Integer.valueOf((int) Math.round(val));
-        } else if ((startValue instanceof Interpolatable) && (endValue instanceof Interpolatable)) {
-            return ((Interpolatable) startValue).interpolate(endValue,
-                    curve(fraction));
-        } else {
-            // discrete
-            return (curve(fraction) == 1.0) ? endValue : startValue;
-        }
-    }
-
-    /**
-     * This method takes two {@code boolean} values along with a
-     * {@code fraction} between {@code 0.0} and {@code 1.0} and returns the
-     * interpolated value.
-     * <p>
-     * Before calculating the interpolated value, the fraction is altered
-     * according to the function defined in {@link #curve(double) curve()}.
-     * 
-     * @param startValue
-     *            the first data point
-     * @param endValue
-     *            the second data point
-     * @param fraction
-     *            the fraction in {@code [0.0...1.0]}
-     */
-    public boolean interpolate(boolean startValue, boolean endValue,
-            double fraction) {
-        return (Math.abs(curve(fraction) - 1.0) < EPSILON) ? endValue
-                : startValue;
-    }
-
-    /**
-     * This method takes two {@code double} values along with a {@code fraction}
-     * between {@code 0.0} and {@code 1.0} and returns the interpolated value.
-     * <p>
-     * Before calculating the interpolated value, the fraction is altered
-     * according to the function defined in {@link #curve(double) curve()}.
-     * 
-     * @param startValue
-     *            the first data point
-     * @param endValue
-     *            the second data point
-     * @param fraction
-     *            the fraction in {@code [0.0...1.0]}
-     */
-    public double interpolate(double startValue, double endValue,
-            double fraction) {
-        return startValue + (endValue - startValue) * curve(fraction);
-    }
-
-    /**
-     * This method takes two {@code int} values along with a {@code fraction}
-     * between {@code 0.0} and {@code 1.0} and returns the interpolated value.
-     * <p>
-     * Before calculating the interpolated value, the fraction is altered
-     * according to the function defined in {@link #curve(double) curve()}.
-     * 
-     * @param startValue
-     *            the first data point
-     * @param endValue
-     *            the second data point
-     * @param fraction
-     *            the fraction in {@code [0.0...1.0]}
-     */
-    public int interpolate(int startValue, int endValue, double fraction) {
-        return startValue
-                + (int) Math.round((endValue - startValue) * curve(fraction));
-    }
-
-    /**
-     * This method takes two {@code int} values along with a {@code fraction}
-     * between {@code 0.0} and {@code 1.0} and returns the interpolated value.
-     * <p>
-     * Before calculating the interpolated value, the fraction is altered
-     * according to the function defined in {@link #curve(double) curve()}.
-     * 
-     * @param startValue
-     *            the first data point
-     * @param endValue
-     *            the second data point
-     * @param fraction
-     *            the fraction in {@code [0.0...1.0]}
-     */
-    public long interpolate(long startValue, long endValue,
-            double fraction) {
-        return startValue
-                + Math.round((endValue - startValue) * curve(fraction));
-    }
-
-    private static double clamp(double t) {
-        return (t < 0.0) ? 0.0 : (t > 1.0) ? 1.0 : t;
-    }
-
-    /**
-     * Mapping from [0.0..1.0] to itself.
-     * 
-     * @param t
-     *            time, but normalized to the range [0.0..1.0], where 0.0 is the
-     *            start of the current interval, while 1.0 is the end of the
-     *            current interval. Usually a function that increases
-     *            monotonically.
-     */
-    protected abstract double curve(double t);
-
-}
--- a/modules/base/src/main/java/javafx/animation/KeyFrame.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,313 +0,0 @@
-/*
- * Copyright (c) 2010, 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.animation;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Set;
-import java.util.concurrent.CopyOnWriteArraySet;
-
-import javafx.event.ActionEvent;
-import javafx.event.EventHandler;
-import javafx.util.Duration;
-
-/**
- * Defines target values at a specified point in time for a set of variables
- * that are interpolated along a {@link Timeline}.
- * <p>
- * The developer controls the interpolation of a set of variables for the
- * interval between successive key frames by providing a target value and an
- * {@link Interpolator} associated with each variable. The variables are
- * interpolated such that they will reach their target value at the specified
- * time. An {@link #onFinished} function is invoked on each {@code KeyFrame} if one
- * is provided. A {@code KeyFrame} can optionally have a {@link #name}, which
- * will result in a cuepoint that is automatically added to the {@code Timeline}.
- * 
- * @see Timeline
- * @see KeyValue
- * @see Interpolator
- * 
- * @since JavaFX 2.0
- */
-public final class KeyFrame {
-
-    private static final EventHandler<ActionEvent> DEFAULT_ON_FINISHED = null;
-    private static final String DEFAULT_NAME = null;
-
-    /**
-     * Returns the time offset of this {@code KeyFrame}.
-     * 
-     * The returned {@link javafx.util.Duration} defines the time offset within
-     * a single cycle of a {@link Timeline} at which the {@link KeyValue
-     * KeyValues} will be set and at which the {@link #onFinished} function
-     * variable will be called.
-     * <p>
-     * The {@code time} of a {@code KeyFrame} has to be greater than or equal to
-     * {@link javafx.util.Duration#ZERO} and it cannot be
-     * {@link javafx.util.Duration#UNKNOWN}.
-     * 
-     * Note: While the unit of {@code time} is a millisecond, the granularity
-     * depends on the underlying operating system and will in general be larger.
-     * For example animations on desktop systems usually run with a maximum of
-     * 60fps which gives a granularity of ~17 ms.
-     */
-    public Duration getTime() {
-        return time;
-    }
-    private final Duration time;
-
-    /**
-     * Returns an immutable {@code Set} of {@link KeyValue} instances. 
-     * 
-     * A {@code KeyValue} defines a target and the desired value that should be
-     * interpolated at the specified time of this {@code KeyFrame}.
-     */
-    public Set<KeyValue> getValues() {
-        return values;
-    }
-    private final Set<KeyValue> values;
-
-    /**
-     * Returns the {@code onFinished} event handler of this {@code KeyFrame}.
-     * 
-     * The {@code onFinished} event handler is a function that is called when
-     * the elapsed time on a cycle passes the specified time of this
-     * {@code KeyFrame}. The {@code onFinished} function variable will be called
-     * if the elapsed time passes the indicated value, even if it never equaled
-     * the time value exactly.
-     */
-    public EventHandler<ActionEvent> getOnFinished() {
-        return onFinished;
-    }
-    private final EventHandler<ActionEvent> onFinished;
-
-    /**
-     * Returns the {@code name} of this {@code KeyFrame}.
-     * 
-     * If a named {@code KeyFrame} is added to a {@link Timeline}, a cuepoint
-     * with the {@code name} and the {@link #time} of the {@code KeyFrame} will
-     * be added automatically. If the {@code KeyFrame} is removed, the cuepoint
-     * will also be removed.
-     */
-    public String getName() {
-        return name;
-    }
-    private final String name;
-
-    /**
-     * Constructor of {@code KeyFrame}
-     * <p>
-     * If a passed in {@code KeyValue} is {@code null} or a duplicate, it will
-     * be ignored.
-     * 
-     * @param time
-     *            the {@link #time}
-     * @param name
-     *            the {@link #name}
-     * @param onFinished
-     *            the {@link #onFinished onFinished-handler}
-     * @param values
-     *            a {@link javafx.collections.ObservableList} of
-     *            {@link KeyValue} instances
-     * @throws NullPointerException
-     *             if {@code time} is null
-     * @throws IllegalArgumentException
-     *             if {@code time} is invalid (see {@link #time})
-     */
-    public KeyFrame(Duration time, String name,
-            EventHandler<ActionEvent> onFinished, Collection<KeyValue> values) {
-        if (time == null) {
-            throw new NullPointerException("The time has to be specified");
-        }
-        if (time.lessThan(Duration.ZERO) || time.equals(Duration.UNKNOWN)) {
-            throw new IllegalArgumentException("The time is invalid.");
-        }
-        this.time = time;
-        this.name = name;
-        if (values != null) {
-            final Set<KeyValue> set = new CopyOnWriteArraySet<KeyValue>(values);
-            set.remove(null);
-            this.values = (set.size() == 0) ? Collections.<KeyValue> emptySet()
-                    : (set.size() == 1) ? Collections.<KeyValue> singleton(set
-                            .iterator().next()) : Collections
-                            .unmodifiableSet(set);
-        } else {
-            this.values = Collections.<KeyValue> emptySet();
-        }
-        this.onFinished = onFinished;
-    }
-
-    /**
-     * Constructor of {@code KeyFrame}
-     * <p>
-     * If a passed in {@code KeyValue} is {@code null} or a duplicate, it will
-     * be ignored.
-     * 
-     * @param time
-     *            the {@link #time}
-     * @param name
-     *            the {@link #name}
-     * @param onFinished
-     *            the {@link #onFinished onFinished-handler}
-     * @param values
-     *            the {@link KeyValue} instances
-     * @throws NullPointerException
-     *             if {@code time} is null
-     * @throws IllegalArgumentException
-     *             if {@code time} is invalid (see {@link #time})
-     */
-    public KeyFrame(Duration time, String name,
-            EventHandler<ActionEvent> onFinished, KeyValue... values) {
-        if (time == null) {
-            throw new NullPointerException("The time has to be specified");
-        }
-        if (time.lessThan(Duration.ZERO) || time.equals(Duration.UNKNOWN)) {
-            throw new IllegalArgumentException("The time is invalid.");
-        }
-        this.time = time;
-        this.name = name;
-        if (values != null) {
-            final Set<KeyValue> set = new CopyOnWriteArraySet<KeyValue>();
-            for (final KeyValue keyValue : values) {
-                if (keyValue != null) {
-                    set.add(keyValue);
-                }
-            }
-            this.values = (set.size() == 0) ? Collections.<KeyValue> emptySet()
-                    : (set.size() == 1) ? Collections.<KeyValue> singleton(set
-                            .iterator().next()) : Collections
-                            .unmodifiableSet(set);
-        } else {
-            this.values = Collections.emptySet();
-        }
-        this.onFinished = onFinished;
-    }
-
-    /**
-     * Constructor of {@code KeyFrame}
-     * 
-     * @param time
-     *            the {@link #time}
-     * @param onFinished
-     *            the {@link #onFinished onFinished-handler}
-     * @param values
-     *            the {@link KeyValue} instances
-     * @throws NullPointerException
-     *             if {@code time} is null
-     * @throws IllegalArgumentException
-     *             if {@code time} is invalid (see {@link #time})
-     */
-    public KeyFrame(Duration time, EventHandler<ActionEvent> onFinished,
-            KeyValue... values) {
-        this(time, DEFAULT_NAME, onFinished, values);
-    }
-
-    /**
-     * Constructor of {@code KeyFrame}
-     * 
-     * @param time
-     *            the {@link #time}
-     * @param name
-     *            the {@link #name}
-     * @param values
-     *            the {@link KeyValue} instances
-     * @throws NullPointerException
-     *             if {@code time} is null
-     * @throws IllegalArgumentException
-     *             if {@code time} is invalid (see {@link #time})
-     */
-    public KeyFrame(Duration time, String name, KeyValue... values) {
-        this(time, name, DEFAULT_ON_FINISHED, values);
-    }
-
-    /**
-     * Constructor of {@code KeyFrame}
-     * 
-     * @param time
-     *            the {@link #time}
-     * @param values
-     *            the {@link KeyValue} instances
-     * @throws NullPointerException
-     *             if {@code time} is null
-     * @throws IllegalArgumentException
-     *             if {@code time} is invalid (see {@link #time})
-     */
-    public KeyFrame(Duration time, KeyValue... values) {
-        this(time, DEFAULT_NAME, DEFAULT_ON_FINISHED, values);
-    }
-
-    /** 
-     * Returns a string representation of this {@code KeyFrame} object. 
-     * @return a string representation of this {@code KeyFrame} object. 
-     */ 
-    @Override
-    public String toString() {
-        return "KeyFrame [time=" + time + ", values=" + values
-                + ", onFinished=" + onFinished + ", name=" + name + "]";
-    }
-
-    /** 
-     * Returns a hash code for this {@code KeyFrame} object. 
-     * @return a hash code for this {@code KeyFrame} object. 
-     */ 
-    @Override
-    public int hashCode() {
-        assert (time != null) && (values != null);
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + time.hashCode();
-        result = prime * result + ((name == null) ? 0 : name.hashCode());
-        result = prime * result
-                + ((onFinished == null) ? 0 : onFinished.hashCode());
-        result = prime * result + values.hashCode();
-        return result;
-    }
-
-    /**
-     * Indicates whether some other object is "equal to" this one. 
-     * Two {@code KeyFrames} are considered equal, if their {@link #getTime()
-     * time}, {@link #onFinished onFinished}, and {@link #getValues() values}
-     * are equal.
-     */
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj instanceof KeyFrame) {
-            final KeyFrame kf = (KeyFrame) obj;
-            assert (time != null) && (values != null) && (kf.time != null)
-                    && (kf.values != null);
-            return time.equals(kf.time)
-                    && ((name == null) ? kf.name == null : name.equals(kf.name))
-                    && ((onFinished == null) ? kf.onFinished == null
-                            : onFinished.equals(kf.onFinished))
-                    && values.equals(kf.values);
-        }
-        return false;
-    }
-
-}
--- a/modules/base/src/main/java/javafx/animation/KeyValue.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,216 +0,0 @@
-/*
- * Copyright (c) 2010, 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.animation;
-
-import javafx.beans.value.WritableBooleanValue;
-import javafx.beans.value.WritableDoubleValue;
-import javafx.beans.value.WritableFloatValue;
-import javafx.beans.value.WritableIntegerValue;
-import javafx.beans.value.WritableLongValue;
-import javafx.beans.value.WritableNumberValue;
-import javafx.beans.value.WritableValue;
-
-/**
- * Defines a key value to be interpolated for a particular interval along the
- * animation. A {@link KeyFrame}, which defines a specific point on a timeline,
- * can hold multiple {@code KeyValues}. {@code KeyValue} is an immutable class.
- * <p>
- * A {@code KeyValue} is defined by a target, which is an implementation of
- * {@link javafx.beans.value.WritableValue}, an end value and an
- * {@link Interpolator}.
- * <p>
- * Most interpolators define the interpolation between two {@code KeyFrames}.
- * (The only exception are tangent-interpolators.)
- * The {@code KeyValue} of the second {@code KeyFrame} (in forward
- * direction) specifies the interpolator to be used in the interval.
- * <p>
- * Tangent-interpolators define the interpolation to the left and to the right of
- * a {@code KeyFrame} (see {@link  Interpolator#TANGENT(javafx.util.Duration, double, javafx.util.Duration, double)
- * Interpolator.TANGENT}).
- * <p>
- * By default, {@link Interpolator#LINEAR} is used in the interval.
- * 
- * @see Timeline
- * @see KeyFrame
- * @see Interpolator
- * 
- * @since JavaFX 2.0
- */
-public final class KeyValue {
-
-    private static final Interpolator DEFAULT_INTERPOLATOR = Interpolator.LINEAR;
-
-    /**
-     * @treatAsPrivate implementation detail
-     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
-     * @since JavaFX 2.0
-     */
-    @Deprecated
-    public static enum Type {
-        BOOLEAN, DOUBLE, FLOAT, INTEGER, LONG, OBJECT
-    }
-
-    /**
-     * @treatAsPrivate implementation detail
-     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
-     */
-    @Deprecated
-    public Type getType() {
-        return type;
-    }
-
-    private final Type type;
-
-    /**
-     * Returns the target of this {@code KeyValue}
-     * 
-     * @return the target
-     */
-    public WritableValue<?> getTarget() {
-        return target;
-    }
-
-    private final WritableValue<?> target;
-
-    /**
-     * Returns the end value of this {@code KeyValue}
-     * 
-     * @return the end value
-     */
-    public Object getEndValue() {
-        return endValue;
-    }
-
-    private final Object endValue;
-
-    /**
-     * {@link Interpolator} to be used for calculating the key value along the
-     * particular interval. By default, {@link Interpolator#LINEAR} is used.
-     */
-    public Interpolator getInterpolator() {
-        return interpolator;
-    }
-
-    private final Interpolator interpolator;
-
-    /**
-     * Creates a {@code KeyValue}.
-     * 
-     * @param target
-     *            the target
-     * @param endValue
-     *            the end value
-     * @param interpolator
-     *            the {@link Interpolator}
-     * @throws NullPointerException
-     *             if {@code target} or {@code interpolator} are {@code null}
-     */
-    public <T> KeyValue(WritableValue<T> target, T endValue,
-            Interpolator interpolator) {
-        if (target == null) {
-            throw new NullPointerException("Target needs to be specified");
-        }
-        if (interpolator == null) {
-            throw new NullPointerException("Interpolator needs to be specified");
-        }
-
-        this.target = target;
-        this.endValue = endValue;
-        this.interpolator = interpolator;
-        this.type = (target instanceof WritableNumberValue) ? (target instanceof WritableDoubleValue) ? Type.DOUBLE
-                : (target instanceof WritableIntegerValue) ? Type.INTEGER
-                        : (target instanceof WritableFloatValue) ? Type.FLOAT
-                                : (target instanceof WritableLongValue) ? Type.LONG
-                                        : Type.OBJECT
-                : (target instanceof WritableBooleanValue) ? Type.BOOLEAN
-                        : Type.OBJECT;
-    }
-
-    /**
-     * Creates a {@code KeyValue} that uses {@link Interpolator#LINEAR}.
-     * 
-     * @param target
-     *            the target
-     * @param endValue
-     *            the end value
-     * @throws NullPointerException
-     *             if {@code target} or {@code interpolator} are {@code null}
-     */
-    public <T> KeyValue(WritableValue<T> target, T endValue) {
-        this(target, endValue, DEFAULT_INTERPOLATOR);
-    }
-
-    /**
-     * Returns a string representation of this {@code KeyValue} object.
-     * @return a string representation of this {@code KeyValue} object.
-     */ 
-    @Override
-    public String toString() {
-        return "KeyValue [target=" + target + ", endValue=" + endValue
-                + ", interpolator=" + interpolator + "]";
-    }
-
-    /**
-     * Returns a hash code for this {@code KeyValue} object.
-     * @return a hash code for this {@code KeyValue} object.
-     */ 
-    @Override
-    public int hashCode() {
-        assert (target != null) && (interpolator != null);
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + target.hashCode();
-        result = prime * result
-                + ((endValue == null) ? 0 : endValue.hashCode());
-        result = prime * result + interpolator.hashCode();
-        return result;
-    }
-
-    /**
-     * Indicates whether some other object is "equal to" this one.
-     * Two {@code KeyValues} are considered equal, if their {@link #getTarget()
-     * target}, {@link #getEndValue() endValue}, and {@link #getInterpolator()
-     * interpolator} are equal.
-     */
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj instanceof KeyValue) {
-            final KeyValue keyValue = (KeyValue) obj;
-            assert (target != null) && (interpolator != null)
-                    && (keyValue.target != null)
-                    && (keyValue.interpolator != null);
-            return target.equals(keyValue.target)
-                    && ((endValue == null) ? (keyValue.endValue == null)
-                            : endValue.equals(keyValue.endValue))
-                    && interpolator.equals(keyValue.interpolator);
-        }
-        return false;
-    }
-
-}
--- a/modules/base/src/main/java/javafx/animation/Timeline.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,196 +0,0 @@
-/*
- * Copyright (c) 2010, 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.animation;
-
-import javafx.collections.ListChangeListener.Change;
-import javafx.collections.ObservableList;
-import javafx.util.Duration;
-
-import com.sun.javafx.collections.TrackableObservableList;
-import com.sun.scenario.animation.AbstractMasterTimer;
-import com.sun.scenario.animation.shared.TimelineClipCore;
-
-/**
- * A {@code Timeline} can be used to define a free from animation of any
- * {@link javafx.beans.value.WritableValue}, e.g. all
- * {@link javafx.beans.property.Property JavaFX Properties}.
- * <p>
- * A {@code Timeline}, defined by one or more {@link KeyFrame}s, processes
- * individual {@code KeyFrame} sequentially, in the order specified by
- * {@code KeyFrame.time}. The animated properties, defined as key values in
- * {@code KeyFrame.values}, are interpolated 
- * to/from the targeted key values at the specified time of the {@code KeyFrame}
- * to {@code Timeline}'s initial position, depends on {@code Timeline}'s
- * direction.
- * <p>
- * {@code Timeline} processes individual {@code KeyFrame} at or after specified
- * time interval elapsed, it does not guarantee the timing when {@code KeyFrame}
- * is processed.
- * <p>
- * The {@link #cycleDurationProperty()} will be set to the largest time value
- * of Timeline's keyFrames.
- * <p>
- * If a {@code KeyFrame} is not provided for the {@code time==0s} instant, one
- * will be synthesized using the target values that are current at the time
- * {@link #play()} or {@link #playFromStart()} is called.
- * <p>
- * It is not possible to change the {@code keyFrames} of a running {@code Timeline}.
- * If the value of {@code keyFrames} is changed for a running {@code Timeline}, it 
- * has to be stopped and started again to pick up the new value.
- * 
- * @see Animation
- * @see KeyFrame
- * @see KeyValue
- * 
- * @since JavaFX 2.0
- */
-public final class Timeline extends Animation {
-    /* Package-private for testing purposes */
-    final TimelineClipCore clipCore;
-    
-    /**
-     * Returns the {@link KeyFrame KeyFrames} of this {@code Timeline}.
-     */
-    public final ObservableList<KeyFrame> getKeyFrames() {
-        return keyFrames;
-    }
-    private final ObservableList<KeyFrame> keyFrames = new TrackableObservableList<KeyFrame>() {
-        @Override
-        protected void onChanged(Change<KeyFrame> c) {
-            while (c.next()) {
-                if (!c.wasPermutated()) {
-                    for (final KeyFrame keyFrame : c.getRemoved()) {
-                        final String cuePoint = keyFrame.getName();
-                        if (cuePoint != null) {
-                            getCuePoints().remove(cuePoint);
-                        }
-                    }
-                    for (final KeyFrame keyFrame : c.getAddedSubList()) {
-                        final String cuePoint = keyFrame.getName();
-                        if (cuePoint != null) {
-                            getCuePoints().put(cuePoint, keyFrame.getTime());
-                        }
-                    }
-                    final Duration duration = clipCore.setKeyFrames(getKeyFrames());
-                    setCycleDuration(duration);
-                }
-            }
-        }
-    };
-
-    /**
-     * The constructor of {@code Timeline}.
-     * 
-     * This constructor allows to define a {@link Animation#targetFramerate}.
-     * 
-     * @param targetFramerate
-     *            The custom target frame rate for this {@code Timeline}
-     * @param keyFrames
-     *            The keyframes of this {@code Timeline}
-     */
-    public Timeline(double targetFramerate, KeyFrame... keyFrames) {
-        super(targetFramerate);
-        clipCore = new TimelineClipCore(this);
-        getKeyFrames().setAll(keyFrames);
-    }
-
-    /**
-     * The constructor of {@code Timeline}.
-     * 
-     * @param keyFrames
-     *            The keyframes of this {@code Timeline}
-     */
-    public Timeline(KeyFrame... keyFrames) {
-        super();
-        clipCore = new TimelineClipCore(this);
-        getKeyFrames().setAll(keyFrames);
-    }
-
-    /**
-     * The constructor of {@code Timeline}.
-     * 
-     * This constructor allows to define a {@link Animation#targetFramerate}.
-     * 
-     * @param targetFramerate
-     *            The custom target frame rate for this {@code Timeline}
-     */
-    public Timeline(double targetFramerate) {
-        super(targetFramerate);
-        clipCore = new TimelineClipCore(this);
-    }
-
-    /**
-     * The constructor of {@code Timeline}.
-     */
-    public Timeline() {
-        super();
-        clipCore = new TimelineClipCore(this);
-    }
-
-    // This constructor is only for testing purposes
-    Timeline(final AbstractMasterTimer timer) {
-        super(timer);
-        clipCore = new TimelineClipCore(this);
-    }
-
-    @Override
-    void impl_playTo(long currentTicks, long cycleTicks) {
-        clipCore.playTo(currentTicks);
-    }
-
-    @Override
-    void impl_jumpTo(long currentTicks, long cycleTicks, boolean forceJump) {
-        impl_sync(false);
-        impl_setCurrentTicks(currentTicks);
-        clipCore.jumpTo(currentTicks, forceJump);
-    }
-
-    @Override
-    void impl_setCurrentRate(double currentRate) {
-        super.impl_setCurrentRate(currentRate);
-        clipCore.notifyCurrentRateChanged();
-    }
-
-    @Override
-    void impl_start(boolean forceSync) {
-        super.impl_start(forceSync);
-        clipCore.start(forceSync);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void stop() {
-        if (parent != null) {
-            throw new IllegalStateException("Cannot stop when embedded in another animation");
-        }
-        if (getStatus() == Status.RUNNING) {
-            clipCore.abort();
-        }
-        super.stop();
-    }
-}
--- a/modules/base/src/test/java/com/sun/scenario/SettingsTest.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2011, 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 com.sun.scenario;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import javafx.util.Callback;
-
-import org.junit.Test;
-
-public class SettingsTest {
-
-
-    @Test
-    public void testStringValue() {
-        Settings.set("foo", "foobar");
-        assertEquals("foobar", Settings.get("foo"));
-    }
-
-    @Test
-    public void testBooleanValue() {
-        Settings.set("foo", "false");
-        assertFalse(Settings.getBoolean("foo"));
-        assertFalse(Settings.getBoolean("foo", false));
-        assertFalse(Settings.getBoolean("bar", false));
-        Settings.set("bar", "true");
-        assertTrue(Settings.getBoolean("bar", false));
-    }
-
-    @Test
-    public void testIntValue() {
-        Settings.set("foo", "128");
-        assertEquals(128, Settings.getInt("foo", 32));
-        assertEquals(32, Settings.getInt("bar", 32));
-    }
-
-    private String tmp;
-
-    @Test
-    public void testListener() {
-        final Callback<String, Void> listener = new Callback<String, Void>() {
-
-            @Override
-            public Void call(String key) {
-                tmp =  Settings.get(key);
-                return null;
-            }
-        };
-        Settings.addPropertyChangeListener(listener);
-        Settings.set("foo", "bar");
-        assertEquals(tmp, "bar");
-        Settings.removePropertyChangeListener(listener);
-    }
-
-    @Test
-    public void testSystemProperties() {
-        System.setProperty("foo", "bar");
-        Settings.set("foo", null);
-        assertEquals(Settings.get("foo"), "bar");
-
-    }
-}
--- a/modules/base/src/test/java/com/sun/scenario/StandaloneAccessor.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +0,0 @@
-/*
- * 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.scenario;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
-
-import com.sun.scenario.animation.AbstractMasterTimer;
-
-/**
- * This class is used in case Toolkit is not present. Usual use case is animaton
- * testing for openjfx-compiler.
- */
-public class StandaloneAccessor extends ToolkitAccessor {
-    private final Map<Object, Object> map = new HashMap<Object, Object>();
-    private final ScheduledExecutorService executor = Executors
-            .newSingleThreadScheduledExecutor(new ThreadFactory() {
-                private final ThreadFactory factory = Executors
-                        .defaultThreadFactory();
-
-                public Thread newThread(Runnable r) {
-                    Thread thread = factory.newThread(r);
-                    thread.setDaemon(true);
-                    return thread;
-                }
-            });
-
-    private AtomicReference<Future<?>> refFuture = new AtomicReference<Future<?>>();
-    private StandaloneMasterTimer standaloneMasterTimer = new StandaloneMasterTimer();
-
-    @Override
-    public Map<Object, Object> getContextMapImpl() {
-        return map;
-    }
-
-    @Override
-    public AbstractMasterTimer getMasterTimerImpl() {
-        return standaloneMasterTimer;
-    }
-
-    private class StandaloneMasterTimer extends AbstractMasterTimer {
-        protected StandaloneMasterTimer() {
-            super(true);
-        }
-
-        @Override
-        protected void postUpdateAnimationRunnable(
-                final DelayedRunnable animationRunnable) {
-            if (animationRunnable == null) {
-                Future<?> future = refFuture.get();
-                if (future != null) {
-                    future.cancel(false);
-                    refFuture.set(null);
-                }
-                return;
-            }
-            if (refFuture.get() != null) {
-                return;
-            }
-            Future<?> future = executor.schedule(new Runnable() {
-                public void run() {
-                    refFuture.set(null);
-                    animationRunnable.run();
-                }
-            }, animationRunnable.getDelay(), TimeUnit.MILLISECONDS);
-            refFuture.set(future);
-        }
-
-        @Override
-        protected int getPulseDuration(int precision) {
-            int retVal = precision / 60;
-            return retVal;
-        }
-    }
-}
--- a/modules/base/src/test/java/com/sun/scenario/animation/AbstractMasterTimerMock.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +0,0 @@
-/*
- * Copyright (c) 2011, 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 com.sun.scenario.animation;
-
-import java.util.HashSet;
-import java.util.Set;
-import com.sun.javafx.animation.TickCalculation;
-import com.sun.scenario.DelayedRunnable;
-import com.sun.scenario.animation.shared.PulseReceiver;
-
-public class AbstractMasterTimerMock extends AbstractMasterTimer {
-
-    private final Set<PulseReceiver> targets = new HashSet<PulseReceiver>();
-    
-    private long nanos;
-    
-    public AbstractMasterTimerMock() {
-        super(true);
-    }
-
-    public void setNanos(long nanos) {
-        this.nanos = nanos;
-    }
-    
-    @Override
-    public long nanos() {
-        return nanos;
-    }
-
-    @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));
-        }
-    }
-    
-}
--- a/modules/base/src/test/java/com/sun/scenario/animation/AbstractMasterTimerTest.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,191 +0,0 @@
-/*
- * Copyright (c) 2011, 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 com.sun.scenario.animation;
-
-import javafx.animation.AnimationTimer;
-import com.sun.scenario.DelayedRunnable;
-import com.sun.scenario.animation.shared.PulseReceiver;
-import org.junit.Before;
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-public class AbstractMasterTimerTest {
-    
-    private AbstractMasterTimerStub timer;
-    
-    
-    @Before
-    public void setUp() {
-        timer = new AbstractMasterTimerStub();
-    }
-    
-    @Test
-    public void testPauseResume() {
-        // pause timer
-        timer.setNanos(2L);
-        assertEquals(2L, timer.nanos());
-        timer.pause();
-        assertEquals(2L, timer.nanos());
-        
-        // test nanos during pause
-        timer.setNanos(5L);
-        assertEquals(2L, timer.nanos());
-        
-        // pause again
-        timer.setNanos(10L);
-        timer.pause();
-        assertEquals(2L, timer.nanos());
-        
-        // resume
-        timer.setNanos(17L);
-        timer.resume();
-        assertEquals(2L, timer.nanos());
-        timer.setNanos(28L);
-        assertEquals(13L, timer.nanos());
-        
-        // resume again
-        timer.setNanos(41L);
-        timer.resume();
-        assertEquals(26L, timer.nanos());
-        
-        // pause again
-        timer.setNanos(58L);
-        assertEquals(43L, timer.nanos());
-        timer.pause();
-        assertEquals(43L, timer.nanos());
-        
-        // test nanos during pause
-        timer.setNanos(77L);
-        assertEquals(43L, timer.nanos());
-        
-        // resume
-        timer.setNanos(100L);
-        timer.resume();
-        assertEquals(43L, timer.nanos());
-        timer.setNanos(129L);
-        assertEquals(72L, timer.nanos());
-    }
-
-    @Test
-    public void testPulseReceiver() {
-        final Flag flag = new Flag();
-        
-        final PulseReceiver pulseReceiver = new PulseReceiver() {
-            @Override
-            public void timePulse(long now) {
-                flag.flag();
-            }
-        };
-        
-        // add PulseReceiver
-        timer.addPulseReceiver(pulseReceiver);
-        timer.simulatePulse();
-        assertTrue(flag.isFlagged());
-        
-        // remove PulseReceiver
-        flag.unflag();
-        timer.removePulseReceiver(pulseReceiver);
-        timer.simulatePulse();
-        assertFalse(flag.isFlagged());
-    }
-
-    @Test
-    public void testAnimationTimers() {
-        final Flag flag = new Flag();
-        
-        final AnimationTimer animationTimer = new AnimationTimer() {
-            @Override
-            public void handle(long now) {
-                flag.flag();
-            }
-        };
-        
-        // add AnimationTimer
-        timer.addAnimationTimer(animationTimer);
-        timer.simulatePulse();
-        assertTrue(flag.isFlagged());
-        
-        // remove AnimationTimer
-        flag.unflag();
-        timer.removeAnimationTimer(animationTimer);
-        timer.simulatePulse();
-        assertFalse(flag.isFlagged());
-    }
-
-    private static class Flag {
-
-        private boolean flagged;
-
-        public void flag() {
-            flagged = true;
-        }
-
-        public void unflag() {
-            flagged = false;
-        }
-
-        public boolean isFlagged() {
-            return flagged;
-        }
-    }
-    
-    private static class AbstractMasterTimerStub extends AbstractMasterTimer {
-        
-        private long nanos;
-        private DelayedRunnable animationRunnable;
-        
-        protected AbstractMasterTimerStub() {
-            super(true);
-        }
-
-        public void setNanos(long nanos) {
-            this.nanos = nanos;
-        }
-        
-        public void simulatePulse() {
-            if (animationRunnable != null) {
-                animationRunnable.run();
-            }
-        }
-
-        @Override public long nanos() {
-            return isPaused() ? getStartPauseTime() : nanos - getTotalPausedTime();
-        }
-
-        @Override
-        protected void postUpdateAnimationRunnable(
-                DelayedRunnable animationRunnable) {
-            this.animationRunnable = animationRunnable;
-        }
-
-        @Override
-        protected int getPulseDuration(int precision) {
-            return precision / 60;
-        }
-        
-    };
-}
--- a/modules/base/src/test/java/com/sun/scenario/animation/NumberTangentInterpolatorTest.java	Mon Jul 01 12:20:05 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,180 +0,0 @@
-/*
- * Copyright (c) 2011, 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 com.sun.scenario.animation;
-
-
-import javafx.animation.Interpolator;
-import static org.junit.Assert.*;
-import static javafx.util.Duration.*;
-
-import org.junit.Before;
-import org.junit.Test;
-
-public class NumberTangentInterpolatorTest {
-	
-	private static final double EPSILON_DOUBLE = 1e-12;
-	private static final double EPSILON_FLOAT = 1e-6;
-
-	private NumberTangentInterpolator interpolator;
-	
-	@Before
-	public void setUp() throws Exception {
-		interpolator = new NumberTangentInterpolator(ZERO, 0);
-	}
-	
-	@Test
-	public void testCreate() {
-		final NumberTangentInterpolator interpolator1 = new NumberTangentInterpolator(millis(2000), Math.PI);
-		assertEquals(Math.PI, interpolator1.getInValue(), EPSILON_DOUBLE);
-		assertEquals(12000.0, interpolator1.getInTicks(), EPSILON_DOUBLE);
-		assertEquals(Math.PI, interpolator1.getOutValue(), EPSILON_DOUBLE);
-		assertEquals(12000.0, interpolator1.getOutTicks(), EPSILON_DOUBLE);
-
-		final NumberTangentInterpolator interpolator2 = new NumberTangentInterpolator(millis(500), Math.E, millis(1000), -Math.PI);
-		assertEquals(Math.E, interpolator2.getInValue(), EPSILON_DOUBLE);
-		assertEquals(3000.0, interpolator2.getInTicks(), EPSILON_DOUBLE);
-		assertEquals(-Math.PI, interpolator2.getOutValue(), EPSILON_DOUBLE);
-		assertEquals(6000.0, interpolator2.getOutTicks(), EPSILON_DOUBLE);
-	}
-	
-	@Test
-	public void testInterpolate_boolean() {
-		assertEquals(false, interpolator.interpolate(false, true, 0.0));
-		assertEquals(false, interpolator.interpolate(false, true, 0.5));
-		assertEquals(true, interpolator.interpolate(false, true, 1.0));
-	}
-
-	@Test
-	public void testInterpolate_double() {
-		assertEquals( 0.0, interpolator.interpolate(0.0, 10.0, 0.0), EPSILON_DOUBLE);
-		assertEquals( 5.0, interpolator.interpolate(0.0, 10.0, 0.5), EPSILON_DOUBLE);
-		assertEquals(10.0, interpolator.interpolate(0.0, 10.0, 1.0), EPSILON_DOUBLE);
-	}
-
-	@Test
-	public void testInterpolate_int() {
-		assertEquals( 0, interpolator.interpolate(0, 10, 0.0));
-		assertEquals( 5, interpolator.interpolate(0, 10, 0.5));
-		assertEquals(10, interpolator.interpolate(0, 10, 1.0));
-	}
-
-	@Test
-	public void testInterpolate_long() {
-		assertEquals( 0L, interpolator.interpolate(0L, 10L, 0.0));
-		assertEquals( 5L, interpolator.interpolate(0L, 10L, 0.5));
-		assertEquals(10L, interpolator.interpolate(0L, 10L, 1.0));
-	}
-
-	@Test
-	public void testInterpolate_float() {
-		assertEquals( 0.0f, interpolator.interpolate(0.0f, 10.0f, 0.0), EPSILON_FLOAT);
-		assertEquals( 5.0f, interpolator.interpolate(0.0f, 10.0f, 0.5), EPSILON_FLOAT);
-		assertEquals(10.0f, interpolator.interpolate(0.0f, 10.0f, 1.0), EPSILON_FLOAT);
-	}
-
-	@Test
-	public void testInterpolate_Object() {
-		assertEquals("Hello World", interpolator.interpolate("Hello World", "Goodbye World", 0.0));
-		assertEquals("Hello World", interpolator.interpolate("Hello World", "Goodbye World", 0.5));
-		assertEquals("Goodbye World", interpolator.interpolate("Hello World", "Goodbye World", 1.0));
-	}
-
-	@Test
-	public void testInterpolate_Number() {
-		assertEquals(Integer.valueOf( 0), interpolator.interpolate(Integer.valueOf(0), Integer.valueOf(10), 0.0));
-		assertEquals(Integer.valueOf( 5), interpolator.interpolate(Integer.valueOf(0), Integer.valueOf(10), 0.5));
-		assertEquals(Integer.valueOf(10), interpolator.interpolate(Integer.valueOf(0), Integer.valueOf(10), 1.0));
-	}
-
-        private static void testEqualsAndHashCode(Interpolator one, Interpolator another) {
-                assertTrue(one.equals(another));
-                assertTrue(another.equals(one));
-                assertEquals(one.hashCode(), another.hashCode());
-        }
-
-        private static void testNotEqualsAndHashCode(Interpolator one, Interpolator another) {
-                assertFalse(one.equals(another));
-                assertFalse(another.equals(one));
-                assertFalse(one.hashCode() == another.hashCode());
-        }