changeset 1087:b2440cb777b7

RT-520: local-to-scene transform tests and minor bug fixes.
author Pavel Safrata
date Thu, 17 May 2012 15:30:18 +0200
parents 981461c5390b
children 6e878dd047d2
files javafx-ui-common/src/javafx/scene/Node.java javafx-ui-common/src/javafx/scene/transform/Affine.java javafx-ui-common/src/javafx/scene/transform/Scale.java javafx-ui-common/test/unit/com/sun/javafx/test/TransformHelper.java javafx-ui-common/test/unit/javafx/scene/Node_LocalToParentTransform_Test.java javafx-ui-common/test/unit/javafx/scene/Node_LocalToSceneTransform_Test.java javafx-ui-common/test/unit/javafx/scene/transform/AffineTest.java javafx-ui-common/test/unit/javafx/scene/transform/RotateTest.java javafx-ui-common/test/unit/javafx/scene/transform/ScaleTest.java javafx-ui-common/test/unit/javafx/scene/transform/ShearTest.java javafx-ui-common/test/unit/javafx/scene/transform/TranslateTest.java
diffstat 11 files changed, 699 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/javafx-ui-common/src/javafx/scene/Node.java	Thu May 17 13:36:06 2012 +0200
+++ b/javafx-ui-common/src/javafx/scene/Node.java	Thu May 17 15:30:18 2012 +0200
@@ -626,6 +626,7 @@
                     }
                     updateTreeVisible();
                     oldParent = newParent;
+                    invalidateLocalToSceneTransform();
                 }
 
                 @Override
@@ -3726,14 +3727,13 @@
      */
     @Deprecated
     public final void impl_transformsChanged() {
+        if (!transformDirty) {
+            impl_markDirty(DirtyBits.NODE_TRANSFORM);
+            transformDirty = true;
+            transformedBoundsChanged();
+        }
         invalidateLocalToParentTransform();
         invalidateLocalToSceneTransform();
-        if (transformDirty) {
-            return;
-        }
-        impl_markDirty(DirtyBits.NODE_TRANSFORM);
-        transformDirty = true;
-        transformedBoundsChanged();
     }
 
     /**
@@ -4283,9 +4283,9 @@
      *
      * <p>
      * Note that when you register a listener or a binding to this property,
-     * it needs to be invalidated every time transformation changes in any
-     * of this node's parents. This means that registering a listener on this
-     * property on many nodes may seriously affect performance of
+     * it needs to listen for invalidation on all its parents to the root node.
+     * This means that registering a listener on this
+     * property on many nodes may negatively affect performance of
      * transformation changes in their common parents.
      * </p>
      */
@@ -4323,6 +4323,16 @@
                 && nodeTransformation.hasTransforms();
     }
 
+    // for tests only
+    Transform getCurrentLocalToSceneTransformState() {
+        if (nodeTransformation == null ||
+                nodeTransformation.localToSceneTransform == null) {
+            return null;
+        }
+
+        return nodeTransformation.localToSceneTransform.transform;
+    }
+
     private static final double DEFAULT_TRANSLATE_X = 0;
     private static final double DEFAULT_TRANSLATE_Y = 0;
     private static final double DEFAULT_TRANSLATE_Z = 0;
@@ -4454,6 +4464,17 @@
                     }
 
                     @Override
+                    public Transform get() {
+                        Transform t = super.get();
+                        if (listenerReasons == 0) {
+                            // we don't get invalidation notifications
+                            // so we must expect it to be always invalid
+                            invalidate();
+                        }
+                        return t;
+                    }
+
+                    @Override
                     public void addListener(InvalidationListener listener) {
                         incListenerReasons();
                         if (localToSceneListeners == null) {
--- a/javafx-ui-common/src/javafx/scene/transform/Affine.java	Thu May 17 13:36:06 2012 +0200
+++ b/javafx-ui-common/src/javafx/scene/transform/Affine.java	Thu May 17 15:30:18 2012 +0200
@@ -66,9 +66,9 @@
     }
 
     // to be published
-    Affine(Double mxx, Double mxy, Double mxz, Double tx,
-            Double myx, Double myy, Double myz, Double ty,
-            Double mzx, Double mzy, Double mzz, Double tz) {
+    Affine(double mxx, double mxy, double mxz, double tx,
+            double myx, double myy, double myz, double ty,
+            double mzx, double mzy, double mzz, double tz) {
         if (mxx != 1.0) this.mxxProperty().set(mxx);
         if (mxy != 0.0) this.mxyProperty().set(mxy);
         if (mxz != 0.0) this.mxzProperty().set(mxz);
--- a/javafx-ui-common/src/javafx/scene/transform/Scale.java	Thu May 17 13:36:06 2012 +0200
+++ b/javafx-ui-common/src/javafx/scene/transform/Scale.java	Thu May 17 15:30:18 2012 +0200
@@ -35,9 +35,9 @@
  * by the specified factors. The matrix representing the scaling transformation
  * is as follows:
  * <pre>
- *              [ x    0   0   0 ]
- *              [ 0    y   0   0 ]
- *              [ 0    0   z   0 ]
+ *              [ x   0   0   (1-x)*pivotX ]
+ *              [ 0   y   0   (1-y)*pivotY ]
+ *              [ 0   0   z   (1-z)*pivotZ ]
  * </pre>
  */
 public class Scale extends Transform {
@@ -336,6 +336,23 @@
         return getZ();
     }
 
+    @Override
+    public double getTx() {
+        return (1-getX()) * getPivotX();
+    }
+
+    @Override
+    public double getTy() {
+        return (1-getY()) * getPivotY();
+    }
+
+    @Override
+    public double getTz() {
+        return (1-getZ()) * getPivotZ();
+    }
+
+
+
     /**
      * @treatAsPrivate implementation detail
      * @deprecated This is an internal API that is not intended for use and will be removed in the next version
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-ui-common/test/unit/com/sun/javafx/test/TransformHelper.java	Thu May 17 15:30:18 2012 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.sun.javafx.test;
+
+import javafx.scene.transform.Transform;
+import static org.junit.Assert.assertEquals;
+
+public class TransformHelper {
+    public static void assertMatrix(Transform matrix,
+            double mxx, double mxy, double mxz, double tx,
+            double myx, double myy, double myz, double ty,
+            double mzx, double mzy, double mzz, double tz) {
+        assertEquals(mxx, matrix.getMxx(), 0.00001);
+        assertEquals(mxy, matrix.getMxy(), 0.00001);
+        assertEquals(mxz, matrix.getMxz(), 0.00001);
+        assertEquals(tx, matrix.getTx(), 0.00001);
+        assertEquals(myx, matrix.getMyx(), 0.00001);
+        assertEquals(myy, matrix.getMyy(), 0.00001);
+        assertEquals(myz, matrix.getMyz(), 0.00001);
+        assertEquals(ty, matrix.getTy(), 0.00001);
+        assertEquals(mzx, matrix.getMzx(), 0.00001);
+        assertEquals(mzy, matrix.getMzy(), 0.00001);
+        assertEquals(mzz, matrix.getMzz(), 0.00001);
+        assertEquals(tz, matrix.getTz(), 0.00001);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-ui-common/test/unit/javafx/scene/Node_LocalToParentTransform_Test.java	Thu May 17 15:30:18 2012 +0200
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package javafx.scene;
+
+import com.sun.javafx.test.TransformHelper;
+import javafx.scene.transform.Translate;
+import javafx.scene.shape.Rectangle;
+import javafx.beans.Observable;
+import javafx.beans.InvalidationListener;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class Node_LocalToParentTransform_Test {
+    private boolean notified;
+
+    @Test
+    public void notTransformedNodeShouldReturnIdentity() {
+        Node n = new Rectangle(20, 20);
+        TransformHelper.assertMatrix(n.getLocalToParentTransform(),
+                1, 0, 0, 0,
+                0, 1, 0, 0,
+                0, 0, 1, 0);
+    }
+
+    @Test
+    public void shouldConsiderBothTransformListAndConvenientTransforms() {
+        Node n = new Rectangle(20, 20);
+
+        n.setTranslateX(10);
+        n.setScaleY(10);
+        n.getTransforms().add(new Translate(5, 6));
+
+        TransformHelper.assertMatrix(n.getLocalToParentTransform(),
+                1,  0, 0,  15,
+                0, 10, 0, -30,
+                0,  0, 1,   0);
+    }
+
+    @Test
+    public void shouldBeUpToDate() {
+        Node n = new Rectangle(20, 20);
+
+        n.setTranslateX(10);
+
+        TransformHelper.assertMatrix(n.getLocalToParentTransform(),
+                1, 0, 0, 10,
+                0, 1, 0, 0,
+                0, 0, 1, 0);
+
+        n.setTranslateX(20);
+
+        TransformHelper.assertMatrix(n.getLocalToParentTransform(),
+                1, 0, 0, 20,
+                0, 1, 0,  0,
+                0, 0, 1,  0);
+    }
+
+    @Test
+    public void shouldBeNotifiedWhenNodeTransforms() {
+        final Node n = new Rectangle(20, 20);
+        n.localToParentTransformProperty().addListener(new InvalidationListener() {
+            public void invalidated(Observable o) {
+                if (!notified) {
+                    notified = true;
+                    TransformHelper.assertMatrix(n.getLocalToParentTransform(),
+                        1, 0, 0, 10,
+                        0, 1, 0, 20,
+                        0, 0, 1,  0);
+                }
+            }
+        });
+
+        notified = false;
+        n.getTransforms().add(new Translate(10, 20));
+        assertTrue(notified);
+
+        n.getTransforms().clear();
+        n.getTransforms().add(new Translate(10, 0));
+        n.getLocalToParentTransform();
+
+        notified = false;
+        n.setTranslateY(20);
+        assertTrue(notified);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javafx-ui-common/test/unit/javafx/scene/Node_LocalToSceneTransform_Test.java	Thu May 17 15:30:18 2012 +0200
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package javafx.scene;
+
+import com.sun.javafx.test.TransformHelper;
+import javafx.scene.transform.Translate;
+import javafx.scene.shape.Rectangle;
+import javafx.beans.Observable;
+import java.lang.reflect.Method;
+import javafx.beans.InvalidationListener;
+import javafx.beans.property.ReadOnlyObjectProperty;
+import javafx.scene.transform.Transform;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class Node_LocalToSceneTransform_Test {
+    private boolean notified;
+
+    @Test
+    public void notTransformedNodeShouldReturnIdentity() {
+        Node n = new Rectangle(20, 20);
+        TransformHelper.assertMatrix(n.getLocalToSceneTransform(),
+                1, 0, 0, 0,
+                0, 1, 0, 0,
+                0, 0, 1, 0);
+    }
+
+    @Test
+    public void noListenersShouldBeAddedByDefault() throws Exception {
+        Node r = new Rectangle(20, 20);
+        Group n = new Group(r);
+        Group p = new Group(n);
+
+        p.getLocalToSceneTransform();
+        n.getLocalToSceneTransform();
+        r.getLocalToSceneTransform();
+
+        p.setTranslateX(10);
+        p.setRotate(80);
+
+        // n didn't react on its parent's transformation
+        TransformHelper.assertMatrix(n.getCurrentLocalToSceneTransformState(),
+                1, 0, 0, 0,
+                0, 1, 0, 0,
+                0, 0, 1, 0);
+    }
+
+    @Test
+    public void shouldConsiderAllParents() {
+        Node n = new Rectangle(20, 20);
+        Group p1 = new Group(n);
+        Group p2 = new Group(p1);
+
+        n.setTranslateX(10);
+        p1.setTranslateY(20);
+        p2.getTransforms().add(new Translate(5, 6));
+
+        TransformHelper.assertMatrix(n.getLocalToSceneTransform(),
+                1, 0, 0, 15,
+                0, 1, 0, 26,
+                0, 0, 1, 0);
+    }
+
+    @Test
+    public void shouldBeUpToDate() {
+        Node n = new Rectangle(20, 20);
+        Group p1 = new Group(n);
+        Group p2 = new Group(p1);
+
+        n.setTranslateX(10);
+        p1.setTranslateY(20);
+        p2.getTransforms().add(new Translate(5, 6));
+
+        TransformHelper.assertMatrix(n.getLocalToSceneTransform(),
+                1, 0, 0, 15,
+                0, 1, 0, 26,
+                0, 0, 1, 0);
+
+        n.setTranslateX(0);
+        p1.setTranslateY(0);
+        p2.getTransforms().clear();
+        p2.setScaleY(10);
+
+        TransformHelper.assertMatrix(n.getLocalToSceneTransform(),
+                1,  0, 0,   0,
+                0, 10, 0, -90,
+                0,  0, 1,   0);
+    }
+
+    @Test
+    public void shouldBeNotifiedWhenThisTransforms() {
+        final Node n = new Rectangle(20, 20);
+        n.localToSceneTransformProperty().addListener(new InvalidationListener() {
+            public void invalidated(Observable o) {
+                notified = true;
+                TransformHelper.assertMatrix(n.getLocalToSceneTransform(),
+                    1, 0, 0, 10,
+                    0, 1, 0, 20,
+                    0, 0, 1,  0);
+            }
+        });
+
+        notified = false;
+        n.getTransforms().add(new Translate(10, 20));
+        assertTrue(notified);
+    }
+    
+    @Test
+    public void shouldBeNotifiedWhenParentTransforms() {
+        final Node n = new Rectangle(20, 20);
+        final Group g = new Group(n);
+        n.localToSceneTransformProperty().addListener(new InvalidationListener() {
+            public void invalidated(Observable o) {
+                notified = true;
+                TransformHelper.assertMatrix(n.getLocalToSceneTransform(),
+                    1, 0, 0, 10,
+                    0, 1, 0, 20,
+                    0, 0, 1,  0);
+            }
+        });
+
+        notified = false;
+        g.getTransforms().add(new Translate(10, 20));
+        assertTrue(notified);
+    }
+
+    @Test
+    public void shouldBeNotifiedOnReparent() {
+        final Node n = new Rectangle(20, 20);
+        final Group g = new Group(n);
+        final Group g2 = new Group();
+        g2.setTranslateX(100);
+
+        n.localToSceneTransformProperty().addListener(new InvalidationListener() {
+            public void invalidated(Observable o) {
+                if (n.getParent() != null) {
+                    notified = true;
+                    TransformHelper.assertMatrix(n.getLocalToSceneTransform(),
+                        1, 0, 0, 100,
+                        0, 1, 0,   0,
+                        0, 0, 1,   0);
+                } else {
+                    TransformHelper.assertMatrix(n.getLocalToSceneTransform(),
+                        1, 0, 0, 0,
+                        0, 1, 0, 0,
+                        0, 0, 1, 0);
+                }
+            }
+        });
+
+        notified = false;
+        g2.getChildren().add(n);
+        assertTrue(notified);
+    }
+
+    @Test
+    public void shouldBeNotifiedWhenParentTransformsAfterReparent() {
+        final Node n = new Rectangle(20, 20);
+        final Group g = new Group(n);
+        final Group g2 = new Group();
+        g.setTranslateX(50);
+        g2.setTranslateX(100);
+
+        n.localToSceneTransformProperty().addListener(new InvalidationListener() {
+            public void invalidated(Observable o) {
+                if (!notified) {
+                    notified = true;
+                    TransformHelper.assertMatrix(n.getLocalToSceneTransform(),
+                        1, 0, 0, 60,
+                        0, 1, 0,  0,
+                        0, 0, 1,  0);
+                } else {
+                    // enable next invalidation
+                    n.getLocalToSceneTransform();
+                }
+            }
+        });
+
+        // disable listener
+        notified = true;
+        g2.getChildren().add(n);
+        // enable listener
+        notified = false;
+        g2.setTranslateX(60);
+        assertTrue(notified);
+    }
+
+    @Test
+    public void shouldUnregisterListenersWhenNotNeeded() {
+        final Node n = new Rectangle(20, 20);
+        final Group p1 = new Group(n);
+        final Group p2 = new Group(p1);
+
+        InvalidationListener lstnr = new InvalidationListener() {
+            public void invalidated(Observable o) {
+                n.getLocalToSceneTransform();
+            }
+        };
+
+        n.localToSceneTransformProperty().addListener(lstnr);
+
+        // with listener on leave, parents update
+        p2.setTranslateX(30);
+        TransformHelper.assertMatrix(p1.getCurrentLocalToSceneTransformState(),
+                1, 0, 0, 30,
+                0, 1, 0,  0,
+                0, 0, 1,  0);
+
+        // without listener on leave, parents don't update
+        n.localToSceneTransformProperty().removeListener(lstnr);
+        p2.setTranslateX(60);
+        TransformHelper.assertMatrix(p1.getCurrentLocalToSceneTransformState(),
+                1, 0, 0, 30,
+                0, 1, 0,  0,
+                0, 0, 1,  0);
+
+        // with listener on leave again, parents update again
+        n.localToSceneTransformProperty().addListener(lstnr);
+        p2.setTranslateX(90);
+        TransformHelper.assertMatrix(p1.getCurrentLocalToSceneTransformState(),
+                1, 0, 0, 90,
+                0, 1, 0,  0,
+                0, 0, 1,  0);
+    }
+
+    @Test
+    public void shouldUnregisterListenersWhenReparent() {
+        final Node n = new Rectangle(20, 20);
+        final Group p1 = new Group(n);
+        final Group p2 = new Group(p1);
+        final Group g = new Group();
+
+        InvalidationListener lstnr = new InvalidationListener() {
+            public void invalidated(Observable o) {
+                n.getLocalToSceneTransform();
+            }
+        };
+
+        n.localToSceneTransformProperty().addListener(lstnr);
+
+        // with listener on leave, parents update
+        p2.setTranslateX(30);
+        TransformHelper.assertMatrix(p1.getCurrentLocalToSceneTransformState(),
+                1, 0, 0, 30,
+                0, 1, 0,  0,
+                0, 0, 1,  0);
+
+        // child with listener is moved away, parents stop updating
+        g.getChildren().add(n);
+        p2.setTranslateX(60);
+        TransformHelper.assertMatrix(p1.getCurrentLocalToSceneTransformState(),
+                1, 0, 0, 30,
+                0, 1, 0,  0,
+                0, 0, 1,  0);
+
+        // leaf with listener moved back, parents update again
+        p1.getChildren().add(n);
+        p2.setTranslateX(90);
+        TransformHelper.assertMatrix(p1.getCurrentLocalToSceneTransformState(),
+                1, 0, 0, 90,
+                0, 1, 0,  0,
+                0, 0, 1,  0);
+    }
+
+    @Test
+    public void shouldNotUnregisterListenerIfThereIsOtherReason() {
+        final Node n = new Rectangle(20, 20);
+        final Group p1 = new Group(n);
+        final Group p2 = new Group(p1);
+        final Group g = new Group();
+
+        InvalidationListener nlstnr = new InvalidationListener() {
+            public void invalidated(Observable o) {
+                n.getLocalToSceneTransform();
+            }
+        };
+        InvalidationListener plstnr = new InvalidationListener() {
+            public void invalidated(Observable o) {
+                p1.getLocalToSceneTransform();
+            }
+        };
+
+        n.localToSceneTransformProperty().addListener(nlstnr);
+        p1.localToSceneTransformProperty().addListener(plstnr);
+
+        // with listeners, parents update
+        p2.setTranslateX(30);
+        TransformHelper.assertMatrix(p1.getCurrentLocalToSceneTransformState(),
+                1, 0, 0, 30,
+                0, 1, 0,  0,
+                0, 0, 1,  0);
+
+        // child moved away, but there is still listener on parent
+        g.getChildren().add(n);
+        p2.setTranslateX(60);
+        TransformHelper.assertMatrix(p1.getCurrentLocalToSceneTransformState(),
+                1, 0, 0, 60,
+                0, 1, 0,  0,
+                0, 0, 1,  0);
+
+        // removed even the listener on parent, now we can stop updating
+        p1.localToSceneTransformProperty().removeListener(plstnr);
+        p2.setTranslateX(90);
+        TransformHelper.assertMatrix(p1.getCurrentLocalToSceneTransformState(),
+                1, 0, 0, 60,
+                0, 1, 0,  0,
+                0, 0, 1,  0);
+
+        // return both listener and child
+        p1.localToSceneTransformProperty().addListener(plstnr);
+        p1.getChildren().add(n);
+
+        // remove the listener, must still update because of the child
+        p1.localToSceneTransformProperty().removeListener(plstnr);
+        p2.setTranslateX(45);
+        TransformHelper.assertMatrix(p1.getCurrentLocalToSceneTransformState(),
+                1, 0, 0, 45,
+                0, 1, 0,  0,
+                0, 0, 1,  0);
+
+        // remove the child as well, now we can stop updating
+        g.getChildren().add(n);
+        p2.setTranslateX(25);
+        TransformHelper.assertMatrix(p1.getCurrentLocalToSceneTransformState(),
+                1, 0, 0, 45,
+                0, 1, 0,  0,
+                0, 0, 1,  0);
+    }
+}
--- a/javafx-ui-common/test/unit/javafx/scene/transform/AffineTest.java	Thu May 17 13:36:06 2012 +0200
+++ b/javafx-ui-common/test/unit/javafx/scene/transform/AffineTest.java	Thu May 17 15:30:18 2012 +0200
@@ -30,6 +30,7 @@
 import org.junit.Assert;
 import org.junit.Test;
 
+import com.sun.javafx.test.TransformHelper;
 import com.sun.javafx.geom.transform.Affine2D;
 import com.sun.javafx.geom.transform.Affine3D;
 
@@ -75,6 +76,35 @@
         assertTx(n, new Affine2D(10, 21, 32, 43, 54, 65));
     }
 
+    @Test public void testGetters() {
+        final Affine trans = new Affine(
+                1,  2,  3,  4,
+                5,  6,  7,  8,
+                9, 10, 11, 12);
+        TransformHelper.assertMatrix(trans,
+                1,  2,  3,  4,
+                5,  6,  7,  8,
+                9, 10, 11, 12);
+
+        trans.setMxx(12);
+        trans.setMxy(11);
+        trans.setMxz(10);
+        trans.setTx(9);
+        trans.setMyx(8);
+        trans.setMyy(7);
+        trans.setMyz(6);
+        trans.setTy(5);
+        trans.setMzx(4);
+        trans.setMzy(3);
+        trans.setMzz(2);
+        trans.setTz(1);
+
+        TransformHelper.assertMatrix(trans,
+                12, 11, 10, 9,
+                 8,  7,  6, 5,
+                 4,  3,  2, 1);
+    }
+
     @Test public void testBoundPropertySynced() throws Exception {
 
         TransformTest.checkDoublePropertySynced(createTransform(), "mxx" , 2.0);
--- a/javafx-ui-common/test/unit/javafx/scene/transform/RotateTest.java	Thu May 17 13:36:06 2012 +0200
+++ b/javafx-ui-common/test/unit/javafx/scene/transform/RotateTest.java	Thu May 17 15:30:18 2012 +0200
@@ -28,6 +28,7 @@
 
 import java.lang.reflect.Method;
 
+import com.sun.javafx.test.TransformHelper;
 import javafx.beans.property.ObjectProperty;
 import javafx.beans.property.SimpleObjectProperty;
 import javafx.geometry.Point3D;
@@ -55,6 +56,10 @@
         Affine2D expTx1 = new Affine2D();
         expTx1.quadrantRotate(1);
         assertTx(n, expTx1);
+        TransformHelper.assertMatrix(trans,
+                Math.cos(Math.PI / 2.0), -Math.sin(Math.PI / 2.0), 0, 0,
+                Math.sin(Math.PI / 2.0),  Math.cos(Math.PI / 2.0), 0, 0,
+                         0,                          0,            1, 0);
 
         trans.setAngle(180);
         Affine2D expTx2 = new Affine2D();
@@ -70,6 +75,41 @@
         Affine2D expTx4 = new Affine2D();
         expTx4.setToRotation(Math.toRadians(trans.getAngle()), trans.getPivotX(), trans.getPivotY());
         assertTx(n, expTx4);
+
+        trans.setAngle(45);
+        trans.setPivotZ(88);
+        trans.setAxis(new Point3D(20, 30, 40));
+
+        final Point3D a = new Point3D(20.0 / Math.sqrt(2900.0),
+                                30.0 / Math.sqrt(2900.0),
+                                40.0 / Math.sqrt(2900.0));
+        double sin = Math.sin(Math.PI / 4);
+        double cos = Math.cos(Math.PI / 4);
+
+        TransformHelper.assertMatrix(trans,
+                cos + a.getX() * a.getX() * (1 - cos), //mxx
+                a.getX() * a.getY() * (1 - cos) - a.getZ() * sin, //mxy
+                a.getX() * a.getZ() * (1 - cos) + a.getY() * sin, //mxz
+                66
+                    - 66 * (cos + a.getX() * a.getX() * (1 - cos))
+                    - 77 * (a.getX() * a.getY() * (1 - cos) - a.getZ() * sin)
+                    - 88 * (a.getX() * a.getZ() * (1 - cos) + a.getY() * sin), //tx
+                a.getY() * a.getX() * (1 - cos) + a.getZ() * sin, //myx
+                cos + a.getY() * a.getY() * (1 - cos), //myy
+                a.getY() * a.getZ() * (1 - cos) - a.getX() * sin, //myz
+                77
+                    - 66 * (a.getY() * a.getX() * (1 - cos) + a.getZ() * sin)
+                    - 77 * (cos + a.getY() * a.getY() * (1 - cos))
+                    - 88 * (a.getY() * a.getZ() * (1 - cos) - a.getX() * sin), //ty
+                a.getZ() * a.getX() * (1 - cos) - a.getY() * sin, //mzx
+                a.getZ() * a.getY() * (1 - cos) + a.getX() * sin, //mzy
+                cos + a.getZ() * a.getZ() * (1 - cos), //mzz
+                88
+                    - 66 * (a.getZ() * a.getX() * (1 - cos) - a.getY() * sin)
+                    - 77 * (a.getZ() * a.getY() * (1 - cos) + a.getX() * sin)
+                    - 88 * (cos + a.getZ() * a.getZ() * (1 - cos)) //tz
+
+                );
     }
 
     @Test public void testRotateAxisCtor() {
--- a/javafx-ui-common/test/unit/javafx/scene/transform/ScaleTest.java	Thu May 17 13:36:06 2012 +0200
+++ b/javafx-ui-common/test/unit/javafx/scene/transform/ScaleTest.java	Thu May 17 15:30:18 2012 +0200
@@ -30,6 +30,7 @@
 import org.junit.Assert;
 import org.junit.Test;
 
+import com.sun.javafx.test.TransformHelper;
 import com.sun.javafx.geom.transform.Affine2D;
 import com.sun.javafx.geom.transform.Affine3D;
 import com.sun.javafx.geom.transform.BaseTransform;
@@ -46,15 +47,27 @@
         n.getTransforms().add(trans);
 
         assertTx(n, BaseTransform.getScaleInstance(25, 52));
+        TransformHelper.assertMatrix(trans,
+                25,  0, 0, 0,
+                 0, 52, 0, 0,
+                 0,  0, 1, 0);
 
 
         trans.setX(34);
         Assert.assertEquals(34, trans.getX(), 1e-100);
         assertTx(n, BaseTransform.getScaleInstance(34, 52));
+        TransformHelper.assertMatrix(trans,
+                34,  0, 0, 0,
+                 0, 52, 0, 0,
+                 0,  0, 1, 0);
 
 
         trans.setY(67);
         assertTx(n, BaseTransform.getScaleInstance(34, 67));
+        TransformHelper.assertMatrix(trans,
+                34,  0, 0, 0,
+                 0, 67, 0, 0,
+                 0,  0, 1, 0);
 
 
         trans.setPivotX(66);
@@ -64,6 +77,10 @@
         expTx.scale(trans.getX(), trans.getY());
         expTx.translate(-trans.getPivotX(), -trans.getPivotY());
         assertTx(n, expTx);
+        TransformHelper.assertMatrix(trans,
+                34,  0, 0, -2178,
+                 0, 67, 0,     0,
+                 0,  0, 1,     0);
 
 
         trans.setPivotY(77);
@@ -72,6 +89,17 @@
         expTx.scale(trans.getX(), trans.getY());
         expTx.translate(-trans.getPivotX(), -trans.getPivotY());
         assertTx(n, expTx);
+        TransformHelper.assertMatrix(trans,
+                34,  0, 0, -2178,
+                 0, 67, 0, -5082,
+                 0,  0, 1,     0);
+
+        trans.setZ(10);
+        trans.setPivotZ(5);
+        TransformHelper.assertMatrix(trans,
+                34,  0,  0, -2178,
+                 0, 67,  0, -5082,
+                 0,  0, 10,   -45);
     }
     
     @Test public void testScalePivotCtor() {
--- a/javafx-ui-common/test/unit/javafx/scene/transform/ShearTest.java	Thu May 17 13:36:06 2012 +0200
+++ b/javafx-ui-common/test/unit/javafx/scene/transform/ShearTest.java	Thu May 17 15:30:18 2012 +0200
@@ -29,6 +29,7 @@
 
 import org.junit.Test;
 
+import com.sun.javafx.test.TransformHelper;
 import com.sun.javafx.geom.transform.Affine2D;
 
 public class ShearTest {
@@ -49,6 +50,11 @@
         final Rectangle n = new Rectangle();
         n.getTransforms().add(trans);
 
+        TransformHelper.assertMatrix(trans,
+                 1, 25, 0, 0,
+                52,  1, 0, 0,
+                 0,  0, 1, 0);
+
         Affine2D expTx1 = new Affine2D();
         expTx1.setToShear(25, 52);
         assertTx(n, expTx1);
@@ -57,11 +63,19 @@
         Affine2D expTx2 = new Affine2D();
         expTx2.setToShear(34, 52);
         assertTx(n, expTx2);
+        TransformHelper.assertMatrix(trans,
+                 1, 34, 0, 0,
+                52,  1, 0, 0,
+                 0,  0, 1, 0);
 
         trans.setY(67);
         Affine2D expTx3 = new Affine2D();
         expTx3.setToShear(34, 67);
         assertTx(n, expTx3);
+        TransformHelper.assertMatrix(trans,
+                 1, 34, 0, 0,
+                67,  1, 0, 0,
+                 0,  0, 1, 0);
 
         trans.setPivotX(66);
 
@@ -70,6 +84,10 @@
         expTx.shear(trans.getX(), trans.getY());
         expTx.translate(-trans.getPivotX(), -trans.getPivotY());
         assertTx(n, expTx);
+        TransformHelper.assertMatrix(trans,
+                 1, 34, 0,      0,
+                67,  1, 0, -67*66,
+                 0,  0, 1,      0);
 
 
         trans.setPivotY(77);
@@ -78,6 +96,10 @@
         expTx.shear(trans.getX(), trans.getY());
         expTx.translate(-trans.getPivotX(), -trans.getPivotY());
         assertTx(n, expTx);
+        TransformHelper.assertMatrix(trans,
+                 1, 34, 0, -34*77,
+                67,  1, 0, -67*66,
+                 0,  0, 1,      0);
     }
 
     @Test public void testBoundPropertySynced_X() throws Exception {
--- a/javafx-ui-common/test/unit/javafx/scene/transform/TranslateTest.java	Thu May 17 13:36:06 2012 +0200
+++ b/javafx-ui-common/test/unit/javafx/scene/transform/TranslateTest.java	Thu May 17 15:30:18 2012 +0200
@@ -30,6 +30,7 @@
 import org.junit.Assert;
 import org.junit.Test;
 
+import com.sun.javafx.test.TransformHelper;
 import com.sun.javafx.geom.transform.BaseTransform;
 
 
@@ -45,15 +46,32 @@
         n.getTransforms().add(trans);
 
         assertTx(n, BaseTransform.getTranslateInstance(25, 52));
-
+        TransformHelper.assertMatrix(trans,
+                1, 0, 0, 25,
+                0, 1, 0, 52,
+                0, 0, 1,  0);
 
         trans.setX(34);
         Assert.assertEquals(34, trans.getX(), 1e-100);
         assertTx(n, BaseTransform.getTranslateInstance(34, 52));
+        TransformHelper.assertMatrix(trans,
+                1, 0, 0, 34,
+                0, 1, 0, 52,
+                0, 0, 1,  0);
 
 
         trans.setY(67);
         assertTx(n, BaseTransform.getTranslateInstance(34, 67));
+        TransformHelper.assertMatrix(trans,
+                1, 0, 0, 34,
+                0, 1, 0, 67,
+                0, 0, 1,  0);
+
+        trans.setZ(33);
+        TransformHelper.assertMatrix(trans,
+                1, 0, 0, 34,
+                0, 1, 0, 67,
+                0, 0, 1, 33);
     }
 
     @Test public void testBoundPropertySynced_X() throws Exception {