1 /* 2 * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package test.javafx.scene; 27 28 import test.javafx.scene.shape.TestUtils; 29 import test.javafx.scene.shape.CircleTest; 30 import com.sun.javafx.geom.PickRay; 31 import com.sun.javafx.geom.transform.Affine2D; 32 import com.sun.javafx.geom.transform.Affine3D; 33 import com.sun.javafx.geom.transform.BaseTransform; 34 import com.sun.javafx.geom.transform.Translate2D; 35 import test.com.sun.javafx.pgstub.StubToolkit; 36 import com.sun.javafx.scene.DirtyBits; 37 import com.sun.javafx.scene.NodeHelper; 38 import com.sun.javafx.scene.input.PickResultChooser; 39 import com.sun.javafx.scene.shape.RectangleHelper; 40 import com.sun.javafx.sg.prism.NGGroup; 41 import com.sun.javafx.sg.prism.NGNode; 42 import com.sun.javafx.sg.prism.NGRectangle; 43 import test.com.sun.javafx.test.objects.TestScene; 44 import test.com.sun.javafx.test.objects.TestStage; 45 import com.sun.javafx.tk.Toolkit; 46 import com.sun.javafx.util.Utils; 47 import javafx.beans.property.*; 48 import javafx.geometry.BoundingBox; 49 import javafx.geometry.Bounds; 50 import javafx.geometry.NodeOrientation; 51 import javafx.geometry.Point2D; 52 import javafx.geometry.Point3D; 53 import javafx.scene.effect.DropShadow; 54 import javafx.scene.effect.Effect; 55 import javafx.scene.shape.*; 56 import javafx.scene.transform.Rotate; 57 import javafx.scene.transform.Transform; 58 import org.junit.Rule; 59 import org.junit.Test; 60 import org.junit.rules.ExpectedException; 61 62 import java.lang.reflect.Method; 63 import java.util.Comparator; 64 import javafx.scene.Group; 65 import javafx.scene.GroupShim; 66 import javafx.scene.Node; 67 import javafx.scene.NodeShim; 68 import javafx.scene.ParallelCamera; 69 import javafx.scene.ParentShim; 70 import javafx.scene.PerspectiveCamera; 71 import javafx.scene.Scene; 72 import javafx.scene.SceneShim; 73 import javafx.scene.SubScene; 74 import javafx.scene.layout.AnchorPane; 75 import javafx.scene.transform.Affine; 76 import javafx.scene.transform.Scale; 77 import javafx.scene.transform.Shear; 78 import javafx.scene.transform.Translate; 79 import javafx.stage.Stage; 80 81 import static org.junit.Assert.*; 82 /** 83 * Tests various aspects of Node. 84 * 85 */ 86 public class NodeTest { 87 @Rule 88 public ExpectedException thrown = ExpectedException.none(); 89 90 // Things to test: 91 // When parent is changed, should cursor on toolkit change as well if 92 // the current node has the mouse over it and didn't explicitly set a 93 // cursor?? 94 95 // Test CSS integration 96 97 // Events: 98 // Events should *not* be delivered to invisible nodes as per the 99 // specification for visible 100 101 // A Node must lose focus when it is no longer visible 102 103 // A node made invisible must cause the cursor to be updated 104 105 // Setting the cursor should override the parent cursor when hover 106 // (test that this happens both when the node already has hover set and 107 // when hover is changed to true) 108 109 // Setting the cursor to null should revert to parent cursor when hover 110 // (test that this happens both when the node already has hover set and 111 // when hover is changed to true) 112 113 // Clip: 114 // Test setting/clearing the clip affects the bounds 115 // Test changing bounds / smooth / etc on clip updates bounds of clipped Node 116 117 // Effect: 118 // Test setting/clearing the effect affects the bounds 119 // Test changing state on Effect updates bounds of Node 120 121 // Test that a disabled Group affects the disabled property of child nodes 122 123 // Test contains, intersects methods 124 // Test parentToLocal/localToStage/etc 125 126 // Test computeCompleteBounds 127 // (other bounds test situtations explicitly tested in BoundsTest) 128 129 // Test transforms end up setting the correct matrix on the peer 130 // In particular, test that pivots are taken correctly into account 131 132 // Test hover is updated when mouse enters 133 // Test hover is updated when mouse exists 134 // Test hover is updated when mouse was over but a higher node then 135 // turns on blocks mouse 136 // Test hover is updated when node moves out from under the cursor 137 // TODO most of these cases cannot be handled until/unless we update 138 // the list of nodes under the cursor on pulse events 139 140 // Test pressed is updated when mouse is pressed 141 // Test pressed is updated when mouse is released 142 // TODO shoudl pressed obey the semantics of a button that is armed & pressed? 143 // Or should "armed" be put on Node? What to do here? 144 145 // Test various onMouseXXX event handlers 146 147 // Test onKeyXXX handlers 148 149 // Test focused is updated? 150 // Test nodes which are not focusable are not focused! 151 // Test focus... (SHOULD NOT DEPEND ON KEY LISTENERS BEING INSTALLED!!) 152 153 // Test that clip is taken into account for both "contains" and 154 // "intersects". See http://javafx-jira.kenai.com/browse/RT-646 155 156 157 158 /*************************************************************************** 159 * * 160 * Basic Node Tests * 161 * * 162 **************************************************************************/ 163 164 @Test 165 public void testGetPseudoClassStatesShouldReturnSameSet() { 166 Rectangle node = new Rectangle(); 167 assertSame("getPseudoClassStates() should always return the same instance", 168 node.getPseudoClassStates(), node.getPseudoClassStates()); 169 } 170 171 // TODO disable this because it depends on TestNode 172 // @Test public void testPeerNotifiedOfVisibilityChanges() { 173 // Rectangle rect = new Rectangle(); 174 // Node peer = rect.impl_getPGNode(); 175 // assertEquals(peer.visible, rect.visible); 176 // 177 // rect.visible = false; 178 // assertEquals(peer.visible, rect.visible); 179 // 180 // rect.visible = true; 181 // assertEquals(peer.visible, rect.visible); 182 // } 183 184 /*************************************************************************** 185 * * 186 * Testing Node Bounds * 187 * * 188 **************************************************************************/ 189 190 // TODO disable this because it depends on TestNode 191 // public function testContainsCallsPeer():Void { 192 // var rect = Rectangle { }; 193 // var peer = rect.impl_getPGNode() as TestNode; 194 // peer.numTimesContainsCalled = 0; 195 // 196 // rect.contains(0, 0); 197 // assertEquals(1, peer.numTimesContainsCalled); 198 // 199 // rect.contains(Point2D { x:10, y:10 }); 200 // assertEquals(2, peer.numTimesContainsCalled); 201 // } 202 203 // TODO disable this because it depends on TestNode 204 // public function testIntersectsCallsPeer():Void { 205 // var rect = Rectangle { }; 206 // var peer = rect.impl_getPGNode() as TestNode; 207 // peer.numTimesIntersectsCalled = 0; 208 // 209 // rect.intersects(0, 0, 10, 10); 210 // assertEquals(1, peer.numTimesIntersectsCalled); 211 // 212 // rect.intersects(BoundingBox { minX:10, minY:10, width:100, height:100 }); 213 // assertEquals(2, peer.numTimesIntersectsCalled); 214 // } 215 216 /*************************************************************************** 217 * * 218 * Testing Node transforms * 219 * * 220 **************************************************************************/ 221 222 /** 223 * Tests that the function which converts a com.sun.javafx.geom.Point2D 224 * in parent coords to local coords works properly. 225 */ 226 @Test public void testParentToLocalGeomPoint() { 227 Rectangle rect = new Rectangle(); 228 rect.setTranslateX(10); 229 rect.setTranslateY(10); 230 rect.setWidth(100); 231 rect.setHeight(100); 232 rect.getTransforms().clear(); 233 rect.getTransforms().addAll(Transform.scale(2, 2), Transform.translate(30, 30)); 234 235 Point2D pt = new Point2D(0, 0); 236 pt = rect.parentToLocal(pt); 237 assertEquals(new Point2D(-35, -35), pt); 238 } 239 240 // TODO need to test with some observableArrayList of transforms which cannot be 241 // cleanly inverted so that we can test that code path 242 243 @Test public void testLocalToParentGeomPoint() { 244 Rectangle rect = new Rectangle(); 245 rect.setTranslateX(10); 246 rect.setTranslateY(10); 247 rect.setWidth(100); 248 rect.setHeight(100); 249 rect.getTransforms().clear(); 250 rect.getTransforms().addAll(Transform.scale(2, 2), Transform.translate(30, 30)); 251 252 Point2D pt = new Point2D(0, 0); 253 pt = rect.localToParent(pt); 254 assertEquals(new Point2D(70, 70), pt); 255 } 256 257 @Test public void testPickingNodeDirectlyNoTransforms() { 258 Rectangle rect = new Rectangle(); 259 rect.setX(10); 260 rect.setY(10); 261 rect.setWidth(100); 262 rect.setHeight(100); 263 264 // needed since picking doesn't work unless rooted in a scene and visible 265 Scene scene = new Scene(new Group()); 266 ParentShim.getChildren(scene.getRoot()).add(rect); 267 268 PickResultChooser res = new PickResultChooser(); 269 NodeHelper.pickNode(rect, new PickRay(50, 50, 1, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY), res); 270 assertSame(rect, res.getIntersectedNode()); 271 res = new PickResultChooser(); 272 NodeHelper.pickNode(rect, new PickRay(0, 0, 1, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY), res); 273 assertNull(res.getIntersectedNode()); 274 } 275 276 @Test public void testPickingNodeDirectlyWithTransforms() { 277 Rectangle rect = new Rectangle(); 278 rect.setTranslateX(10); 279 rect.setTranslateY(10); 280 rect.setWidth(100); 281 rect.setHeight(100); 282 283 // needed since picking doesn't work unless rooted in a scene and visible 284 Scene scene = new Scene(new Group()); 285 ParentShim.getChildren(scene.getRoot()).add(rect); 286 287 PickResultChooser res = new PickResultChooser(); 288 NodeHelper.pickNode(rect, new PickRay(50, 50, 1, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY), res); 289 assertSame(rect, res.getIntersectedNode()); 290 res = new PickResultChooser(); 291 NodeHelper.pickNode(rect, new PickRay(0, 0, 1, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY), res); 292 assertNull(res.getIntersectedNode()); 293 } 294 295 @Test public void testEffectSharedOnNodes() { 296 Effect effect = new DropShadow(); 297 Rectangle node = new Rectangle(); 298 node.setEffect(effect); 299 300 Rectangle node2 = new Rectangle(); 301 node2.setEffect(effect); 302 303 assertEquals(effect, node.getEffect()); 304 assertEquals(effect, node2.getEffect()); 305 } 306 307 public static void testBooleanPropertyPropagation( 308 final Node node, 309 final String propertyName, 310 final boolean initialValue, 311 final boolean newValue) throws Exception { 312 313 final StringBuilder propertyNameBuilder = new StringBuilder(propertyName); 314 propertyNameBuilder.setCharAt(0, Character.toUpperCase(propertyName.charAt(0))); 315 final String setterName = new StringBuilder("set").append(propertyNameBuilder).toString(); 316 final String getterName = new StringBuilder("is").append(propertyNameBuilder).toString(); 317 318 final Class<? extends Node> nodeClass = node.getClass(); 319 final Method setter = nodeClass.getMethod(setterName, boolean.class); 320 final Method getter = nodeClass.getMethod(getterName); 321 322 final NGNode peer = NodeHelper.getPeer(node); 323 final Class<? extends NGNode> impl_class = peer.getClass(); 324 final Method impl_getter = impl_class.getMethod(getterName); 325 326 327 // 1. Create test scene 328 final Scene scene = new Scene(new Group()); 329 ParentShim.getChildren(scene.getRoot()).add(node); 330 331 // 2. Initial setup 332 setter.invoke(node, initialValue); 333 NodeHelper.syncPeer(node); 334 assertEquals(initialValue, getter.invoke(node)); 335 assertEquals(initialValue, impl_getter.invoke(peer)); 336 337 // 3. Change value of the property 338 setter.invoke(node, newValue); 339 340 // 4. Check that the property value has changed but has not propagated to PGNode 341 assertEquals(newValue, getter.invoke(node)); 342 assertEquals(initialValue, impl_getter.invoke(peer)); 343 344 // 5. Propagate the property value to PGNode 345 NodeHelper.syncPeer(node); 346 347 // 6. Check that the value has been propagated to PGNode 348 assertEquals(newValue, impl_getter.invoke(peer)); 349 } 350 351 352 public static void testFloatPropertyPropagation( 353 final Node node, 354 final String propertyName, 355 final float initialValue, 356 final float newValue) throws Exception { 357 358 testFloatPropertyPropagation(node, propertyName, propertyName, initialValue, newValue); 359 } 360 361 public static void syncNode(Node node) { 362 NodeShim.updateBounds(node); 363 NodeHelper.syncPeer(node); 364 } 365 366 public static void assertBooleanPropertySynced( 367 final Node node, 368 final String propertyName, 369 final String pgPropertyName, 370 final boolean value) throws Exception { 371 372 final Scene scene = new Scene(new Group(), 500, 500); 373 374 final StringBuilder propertyNameBuilder = new StringBuilder(propertyName); 375 propertyNameBuilder.setCharAt(0, Character.toUpperCase(propertyName.charAt(0))); 376 final String getterName = new StringBuilder("is").append(propertyNameBuilder).toString(); 377 Method getterMethod = node.getClass().getMethod(getterName, new Class[]{}); 378 Boolean defaultValue = (Boolean)getterMethod.invoke(node); 379 BooleanProperty v = new SimpleBooleanProperty(defaultValue); 380 381 Method modelMethod = node.getClass().getMethod( 382 propertyName + "Property", 383 new Class[]{}); 384 BooleanProperty model = (BooleanProperty)modelMethod.invoke(node); 385 model.bind(v); 386 387 ParentShim.getChildren(scene.getRoot()).add(node); 388 389 NodeTest.syncNode(node); 390 assertEquals(defaultValue, TestUtils.getBooleanValue(node, pgPropertyName)); 391 392 v.set(value); 393 NodeTest.syncNode(node); 394 assertEquals(value, TestUtils.getBooleanValue(node, pgPropertyName)); 395 } 396 397 public static void assertIntPropertySynced( 398 final Node node, 399 final String propertyName, 400 final String pgPropertyName, 401 final int value) throws Exception { 402 403 final Scene scene = new Scene(new Group(), 500, 500); 404 405 final StringBuilder propertyNameBuilder = new StringBuilder(propertyName); 406 propertyNameBuilder.setCharAt(0, Character.toUpperCase(propertyName.charAt(0))); 407 final String getterName = new StringBuilder("get").append(propertyNameBuilder).toString(); 408 Method getterMethod = node.getClass().getMethod(getterName, new Class[]{}); 409 Integer defaultValue = (Integer)getterMethod.invoke(node); 410 IntegerProperty v = new SimpleIntegerProperty(defaultValue); 411 412 Method modelMethod = node.getClass().getMethod( 413 propertyName + "Property", 414 new Class[]{}); 415 IntegerProperty model = (IntegerProperty)modelMethod.invoke(node); 416 model.bind(v); 417 418 ParentShim.getChildren(scene.getRoot()).add(node); 419 420 NodeTest.syncNode(node); 421 assertTrue(numbersEquals(defaultValue, 422 (Number)TestUtils.getObjectValue(node, pgPropertyName))); 423 424 v.set(value); 425 NodeTest.syncNode(node); 426 assertTrue(numbersEquals(new Integer(value), 427 (Number)TestUtils.getObjectValue(node, pgPropertyName))); 428 } 429 430 public static boolean numbersEquals(Number expected, Number value) { 431 return numbersEquals(expected, value, 0.001); 432 } 433 434 public static boolean numbersEquals(Number expected, Number value, double delta) { 435 boolean res = (Math.abs(expected.doubleValue() - value.doubleValue()) < delta); 436 if (!res) { 437 System.err.println("expected=" + expected + ", value=" + value); 438 } 439 return res; 440 } 441 442 public static void assertDoublePropertySynced( 443 final Node node, 444 final String propertyName, 445 final String pgPropertyName, 446 final double value) throws Exception { 447 448 final Scene scene = new Scene(new Group(), 500, 500); 449 450 final StringBuilder propertyNameBuilder = new StringBuilder(propertyName); 451 propertyNameBuilder.setCharAt(0, Character.toUpperCase(propertyName.charAt(0))); 452 final String getterName = new StringBuilder("get").append(propertyNameBuilder).toString(); 453 Method getterMethod = node.getClass().getMethod(getterName, new Class[]{}); 454 Double defaultValue = (Double)getterMethod.invoke(node); 455 DoubleProperty v = new SimpleDoubleProperty(defaultValue); 456 457 Method modelMethod = node.getClass().getMethod( 458 propertyName + "Property", 459 new Class[]{}); 460 DoubleProperty model = (DoubleProperty)modelMethod.invoke(node); 461 model.bind(v); 462 463 ParentShim.getChildren(scene.getRoot()).add(node); 464 465 NodeTest.syncNode(node); 466 assertTrue(numbersEquals(defaultValue, 467 (Number)TestUtils.getObjectValue(node, pgPropertyName))); 468 469 v.set(value); 470 NodeTest.syncNode(node); 471 assertTrue(numbersEquals(new Double(value), 472 (Number)TestUtils.getObjectValue(node, pgPropertyName))); 473 } 474 475 476 public static void assertObjectPropertySynced( 477 final Node node, 478 final String propertyName, 479 final String pgPropertyName, 480 final Object value) throws Exception { 481 482 final Scene scene = new Scene(new Group(), 500, 500); 483 484 final StringBuilder propertyNameBuilder = new StringBuilder(propertyName); 485 propertyNameBuilder.setCharAt(0, Character.toUpperCase(propertyName.charAt(0))); 486 final String getterName = new StringBuilder("get").append(propertyNameBuilder).toString(); 487 Method getterMethod = node.getClass().getMethod(getterName, new Class[]{}); 488 Object defaultValue = getterMethod.invoke(node); 489 ObjectProperty v = new SimpleObjectProperty(defaultValue); 490 491 Method modelMethod = node.getClass().getMethod( 492 propertyName + "Property", 493 new Class[]{}); 494 ObjectProperty model = (ObjectProperty)modelMethod.invoke(node); 495 model.bind(v); 496 497 ParentShim.getChildren(scene.getRoot()).add(node); 498 499 NodeTest.syncNode(node); 500 // sometimes enum is used on node but int on PGNode 501 Object result1 = TestUtils.getObjectValue(node, pgPropertyName); 502 if (result1 instanceof Integer) { 503 assertTrue(((Enum)defaultValue).ordinal() == ((Integer)result1).intValue()); 504 } else { 505 assertEquals(defaultValue, TestUtils.getObjectValue(node, pgPropertyName)); 506 } 507 508 v.set(value); 509 NodeTest.syncNode(node); 510 511 Object result2 = TestUtils.getObjectValue(node, pgPropertyName); 512 if (result2 instanceof Integer) { 513 assertTrue(((Enum)value).ordinal() == ((Integer)result2).intValue()); 514 } else { 515 assertEquals(value, TestUtils.getObjectValue(node, pgPropertyName)); 516 } 517 } 518 519 520 521 public static void assertObjectProperty_AsStringSynced( 522 final Node node, 523 final String propertyName, 524 final String pgPropertyName, 525 final Object value) throws Exception { 526 527 final Scene scene = new Scene(new Group(), 500, 500); 528 529 final StringBuilder propertyNameBuilder = new StringBuilder(propertyName); 530 propertyNameBuilder.setCharAt(0, Character.toUpperCase(propertyName.charAt(0))); 531 final String getterName = new StringBuilder("get").append(propertyNameBuilder).toString(); 532 Method getterMethod = node.getClass().getMethod(getterName, new Class[]{}); 533 Object defaultValue = getterMethod.invoke(node); 534 ObjectProperty v = new SimpleObjectProperty(defaultValue); 535 536 Method modelMethod = node.getClass().getMethod( 537 propertyName + "Property", 538 new Class[]{}); 539 ObjectProperty model = (ObjectProperty)modelMethod.invoke(node); 540 model.bind(v); 541 542 ParentShim.getChildren(scene.getRoot()).add(node); 543 544 NodeTest.syncNode(node); 545 assertEquals( 546 defaultValue.toString(), 547 TestUtils.getObjectValue(node, pgPropertyName).toString()); 548 549 v.set(value); 550 NodeTest.syncNode(node); 551 552 assertEquals( 553 value.toString(), 554 TestUtils.getObjectValue(node, pgPropertyName).toString()); 555 } 556 557 public static void assertStringPropertySynced( 558 final Node node, 559 final String propertyName, 560 final String pgPropertyName, 561 final String value) throws Exception { 562 563 final Scene scene = new Scene(new Group(), 500, 500); 564 565 final StringBuilder propertyNameBuilder = new StringBuilder(propertyName); 566 propertyNameBuilder.setCharAt(0, Character.toUpperCase(propertyName.charAt(0))); 567 final String getterName = new StringBuilder("get").append(propertyNameBuilder).toString(); 568 Method getterMethod = node.getClass().getMethod(getterName, new Class[]{}); 569 String defaultValue = (String)getterMethod.invoke(node); 570 StringProperty v = new SimpleStringProperty(defaultValue); 571 572 Method modelMethod = node.getClass().getMethod( 573 propertyName + "Property", 574 new Class[]{}); 575 StringProperty model = (StringProperty)modelMethod.invoke(node); 576 model.bind(v); 577 578 ParentShim.getChildren(scene.getRoot()).add(node); 579 580 NodeTest.syncNode(node); 581 assertEquals( 582 defaultValue, 583 TestUtils.getStringValue(node, pgPropertyName)); 584 585 v.set(value); 586 NodeTest.syncNode(node); 587 588 assertEquals( 589 value, 590 TestUtils.getStringValue(node, pgPropertyName)); 591 } 592 593 public static void testFloatPropertyPropagation( 594 final Node node, 595 final String propertyName, 596 final String pgPropertyName, 597 final float initialValue, 598 final float newValue) throws Exception { 599 600 final StringBuilder propertyNameBuilder = new StringBuilder(propertyName); 601 propertyNameBuilder.setCharAt(0, Character.toUpperCase(propertyName.charAt(0))); 602 603 final StringBuilder pgPropertyNameBuilder = new StringBuilder(pgPropertyName); 604 pgPropertyNameBuilder.setCharAt(0, Character.toUpperCase(pgPropertyName.charAt(0))); 605 606 final String setterName = new StringBuilder("set").append(propertyNameBuilder).toString(); 607 final String getterName = new StringBuilder("get").append(propertyNameBuilder).toString(); 608 final String pgGetterName = new StringBuilder("get").append(pgPropertyNameBuilder).toString(); 609 610 final Class<? extends Node> nodeClass = node.getClass(); 611 final Method setter = nodeClass.getMethod(setterName, float.class); 612 final Method getter = nodeClass.getMethod(getterName); 613 614 final NGNode peer = NodeHelper.getPeer(node); 615 final Class<? extends NGNode> impl_class = peer.getClass(); 616 final Method impl_getter = impl_class.getMethod(pgGetterName); 617 618 619 // 1. Create test scene 620 final Scene scene = new Scene(new Group()); 621 ParentShim.getChildren(scene.getRoot()).add(node); 622 623 // 2. Initial setup 624 setter.invoke(node, initialValue); 625 NodeHelper.syncPeer(node); 626 assertEquals(initialValue, (Float) getter.invoke(node), 1e-100); 627 assertEquals(initialValue, (Float) impl_getter.invoke(peer), 1e-100); 628 629 // 3. Change value of the property 630 setter.invoke(node, newValue); 631 632 // 4. Check that the property value has changed but has not propagated to PGNode 633 assertEquals(newValue, (Float) getter.invoke(node), 1e-100); 634 assertEquals(initialValue, (Float) impl_getter.invoke(peer), 1e-100); 635 636 // 5. Propagate the property value to PGNode 637 NodeHelper.syncPeer(node); 638 639 // 6. Check that the value has been propagated to PGNode 640 assertEquals(newValue, (Float) impl_getter.invoke(peer), 1e-100); 641 } 642 643 public static void testDoublePropertyPropagation( 644 final Node node, 645 final String propertyName, 646 final double initialValue, 647 final double newValue) throws Exception { 648 649 testDoublePropertyPropagation(node, propertyName, propertyName, initialValue, newValue); 650 } 651 652 653 public static void testDoublePropertyPropagation( 654 final Node node, 655 final String propertyName, 656 final String pgPropertyName, 657 final double initialValue, 658 final double newValue) throws Exception { 659 660 final StringBuilder propertyNameBuilder = new StringBuilder(propertyName); 661 propertyNameBuilder.setCharAt(0, Character.toUpperCase(propertyName.charAt(0))); 662 663 final StringBuilder pgPropertyNameBuilder = new StringBuilder(pgPropertyName); 664 pgPropertyNameBuilder.setCharAt(0, Character.toUpperCase(pgPropertyName.charAt(0))); 665 666 final String setterName = new StringBuilder("set").append(propertyNameBuilder).toString(); 667 final String getterName = new StringBuilder("get").append(propertyNameBuilder).toString(); 668 final String pgGetterName = new StringBuilder("get").append(pgPropertyNameBuilder).toString(); 669 670 final Class<? extends Node> nodeClass = node.getClass(); 671 final Method setter = nodeClass.getMethod(setterName, double.class); 672 final Method getter = nodeClass.getMethod(getterName); 673 674 final NGNode peer = NodeHelper.getPeer(node); 675 final Class<? extends NGNode> impl_class = peer.getClass(); 676 final Method impl_getter = impl_class.getMethod(pgGetterName); 677 678 679 // 1. Create test scene 680 final Scene scene = new Scene(new Group()); 681 ParentShim.getChildren(scene.getRoot()).add(node); 682 683 // 2. Initial setup 684 setter.invoke(node, initialValue); 685 NodeHelper.syncPeer(node); 686 assertEquals(initialValue, (Double) getter.invoke(node), 1e-100); 687 assertEquals((float) initialValue, (Float) impl_getter.invoke(peer), 1e-100); 688 689 // 3. Change value of the property 690 setter.invoke(node, newValue); 691 692 // 4. Check that the property value has changed but has not propagated to PGNode 693 assertEquals(newValue, (Double) getter.invoke(node), 1e-100); 694 assertEquals((float) initialValue, (Float) impl_getter.invoke(peer), 1e-100); 695 696 // 5. Propagate the property value to PGNode 697 NodeHelper.syncPeer(node); 698 699 // 6. Check that the value has been propagated to PGNode 700 assertEquals((float) newValue, (Float) impl_getter.invoke(peer), 1e-100); 701 } 702 703 public interface ObjectValueConvertor { 704 Object toSg(Object pgValue); 705 } 706 707 public static final Comparator DEFAULT_OBJ_COMPARATOR = 708 (sgValue, pgValue) -> { 709 assertEquals(sgValue, pgValue); 710 return 0; 711 }; 712 713 public static void testObjectPropertyPropagation( 714 final Node node, 715 final String propertyName, 716 final Object initialValue, 717 final Object newValue) throws Exception { 718 719 testObjectPropertyPropagation(node, propertyName, propertyName, initialValue, newValue); 720 } 721 722 public static void testObjectPropertyPropagation( 723 final Node node, 724 final String propertyName, 725 final String pgPropertyName, 726 final Object initialValue, 727 final Object newValue) throws Exception { 728 testObjectPropertyPropagation(node, propertyName, pgPropertyName, 729 initialValue, newValue, DEFAULT_OBJ_COMPARATOR); 730 } 731 732 public static void testObjectPropertyPropagation( 733 final Node node, 734 final String propertyName, 735 final String pgPropertyName, 736 final Object initialValue, 737 final Object newValue, 738 final ObjectValueConvertor convertor) throws Exception { 739 testObjectPropertyPropagation( 740 node, propertyName, pgPropertyName, 741 initialValue, newValue, 742 (sgValue, pgValue) -> { 743 assertEquals(sgValue, convertor.toSg(pgValue)); 744 return 0; 745 } 746 ); 747 } 748 749 public static void testObjectPropertyPropagation( 750 final Node node, 751 final String propertyName, 752 final String pgPropertyName, 753 final Object initialValue, 754 final Object newValue, 755 final Comparator comparator) throws Exception { 756 final StringBuilder propertyNameBuilder = new StringBuilder(propertyName); 757 propertyNameBuilder.setCharAt(0, Character.toUpperCase(propertyName.charAt(0))); 758 759 final StringBuilder pgPropertyNameBuilder = new StringBuilder(pgPropertyName); 760 pgPropertyNameBuilder.setCharAt(0, Character.toUpperCase(pgPropertyName.charAt(0))); 761 762 final String setterName = new StringBuilder("set").append(propertyNameBuilder).toString(); 763 final String getterName = new StringBuilder("get").append(propertyNameBuilder).toString(); 764 final String pgGetterName = new StringBuilder("get").append(pgPropertyNameBuilder).toString(); 765 766 final Class<? extends Node> nodeClass = node.getClass(); 767 final Method getter = nodeClass.getMethod(getterName); 768 final Method setter = nodeClass.getMethod(setterName, getter.getReturnType()); 769 770 final NGNode peer = NodeHelper.getPeer(node); 771 final Class<? extends NGNode> impl_class = peer.getClass(); 772 final Method impl_getter = impl_class.getMethod(pgGetterName); 773 774 775 // 1. Create test scene 776 final Scene scene = new Scene(new Group()); 777 ParentShim.getChildren(scene.getRoot()).add(node); 778 779 // 2. Initial setup 780 setter.invoke(node, initialValue); 781 NodeHelper.syncPeer(node); 782 assertEquals(initialValue, getter.invoke(node)); 783 assertEquals(0, comparator.compare(initialValue, 784 impl_getter.invoke(peer))); 785 786 // 3. Change value of the property 787 setter.invoke(node, newValue); 788 789 // 4. Check that the property value has changed but has not propagated to PGNode 790 assertEquals(newValue, getter.invoke(node)); 791 assertEquals(0, comparator.compare(initialValue, 792 impl_getter.invoke(peer))); 793 794 // 5. Propagate the property value to PGNode 795 NodeHelper.syncPeer(node); 796 797 // 6. Check that the value has been propagated to PGNode 798 assertEquals(0, comparator.compare(newValue, 799 impl_getter.invoke(peer))); 800 } 801 802 803 public static void testIntPropertyPropagation( 804 final Node node, 805 final String propertyName, 806 final int initialValue, 807 final int newValue) throws Exception { 808 809 testIntPropertyPropagation(node, propertyName, propertyName, initialValue, newValue); 810 } 811 812 813 public static void testIntPropertyPropagation( 814 final Node node, 815 final String propertyName, 816 final String pgPropertyName, 817 final int initialValue, 818 final int newValue) throws Exception { 819 820 final StringBuilder propertyNameBuilder = new StringBuilder(propertyName); 821 propertyNameBuilder.setCharAt(0, Character.toUpperCase(propertyName.charAt(0))); 822 823 final StringBuilder pgPropertyNameBuilder = new StringBuilder(pgPropertyName); 824 pgPropertyNameBuilder.setCharAt(0, Character.toUpperCase(pgPropertyName.charAt(0))); 825 826 final String setterName = new StringBuilder("set").append(propertyNameBuilder).toString(); 827 final String getterName = new StringBuilder("get").append(propertyNameBuilder).toString(); 828 final String pgGetterName = new StringBuilder("get").append(pgPropertyNameBuilder).toString(); 829 830 final Class<? extends Node> nodeClass = node.getClass(); 831 final Method getter = nodeClass.getMethod(getterName); 832 final Method setter = nodeClass.getMethod(setterName, getter.getReturnType()); 833 834 final NGNode peer = NodeHelper.getPeer(node); 835 final Class<? extends NGNode> impl_class = peer.getClass(); 836 final Method impl_getter = impl_class.getMethod(pgGetterName); 837 838 839 // 1. Create test scene 840 final Scene scene = new Scene(new Group()); 841 ParentShim.getChildren(scene.getRoot()).add(node); 842 843 // 2. Initial setup 844 setter.invoke(node, initialValue); 845 assertEquals(initialValue, getter.invoke(node)); 846 NodeHelper.syncPeer(node); 847 assertEquals(initialValue, ((Number) impl_getter.invoke(peer)).intValue()); 848 849 // 3. Change value of the property 850 setter.invoke(node, newValue); 851 852 // 4. Check that the property value has changed but has not propagated to PGNode 853 assertEquals(newValue, getter.invoke(node)); 854 assertEquals(initialValue, ((Number) impl_getter.invoke(peer)).intValue()); 855 856 // 5. Propagate the property value to PGNode 857 NodeHelper.syncPeer(node); 858 859 // 6. Check that the value has been propagated to PGNode 860 assertEquals(newValue, ((Number) impl_getter.invoke(peer)).intValue()); 861 } 862 863 public static void callSyncPGNode(final Node node) { 864 NodeHelper.syncPeer(node); 865 } 866 867 @Test 868 public void testToFront() { 869 Rectangle rect1 = new Rectangle(); 870 Rectangle rect2 = new Rectangle(); 871 Group g = new Group(); 872 873 Scene scene = new Scene(g); 874 ParentShim.getChildren(g).add(rect1); 875 ParentShim.getChildren(g).add(rect2); 876 877 rect1.toFront(); 878 rect2.toFront(); 879 880 // toFront should not remove rectangle from scene 881 assertEquals(scene, rect2.getScene()); 882 assertEquals(scene, rect1.getScene()); 883 // test corect order of scene content 884 assertEquals(rect2, ParentShim.getChildren(g).get(1)); 885 assertEquals(rect1, ParentShim.getChildren(g).get(0)); 886 887 rect1.toFront(); 888 assertEquals(scene, rect2.getScene()); 889 assertEquals(scene, rect1.getScene()); 890 assertEquals(rect1, ParentShim.getChildren(g).get(1)); 891 assertEquals(rect2, ParentShim.getChildren(g).get(0)); 892 } 893 894 @Test 895 public void testClip() { 896 Rectangle rect1 = new Rectangle(); 897 Rectangle rect2 = new Rectangle(); 898 rect1.setClip(rect2); 899 900 Scene scene = new Scene(new Group()); 901 ParentShim.getChildren(scene.getRoot()).add(rect1); 902 assertEquals(rect2, rect1.getClip()); 903 assertEquals(scene, rect2.getScene()); 904 905 } 906 907 @Test 908 public void testInvalidClip() { 909 Rectangle rectA = new Rectangle(300, 300); 910 Rectangle clip1 = new Rectangle(10, 10); 911 Rectangle clip2 = new Rectangle(100, 100); 912 clip2.setClip(rectA); 913 rectA.setClip(clip1); 914 assertEquals(rectA.getClip(), clip1); 915 thrown.expect(IllegalArgumentException.class); 916 try { 917 rectA.setClip(clip2); 918 } catch (final IllegalArgumentException e) { 919 assertNotSame(rectA.getClip(), clip2); 920 throw e; 921 } 922 } 923 924 @Test public void testProperties() { 925 Rectangle node = new Rectangle(); 926 javafx.collections.ObservableMap<Object, Object> properties = node.getProperties(); 927 928 /* If we ask for it, we should get it. 929 */ 930 assertNotNull(properties); 931 932 /* What we put in, we should get out. 933 */ 934 properties.put("MyKey", "MyValue"); 935 assertEquals("MyValue", properties.get("MyKey")); 936 937 /* If we ask for it again, we should get the same thing. 938 */ 939 javafx.collections.ObservableMap<Object, Object> properties2 = node.getProperties(); 940 assertEquals(properties2, properties); 941 942 /* What we put in to the other one, we should get out of this one because 943 * they should be the same thing. 944 */ 945 assertEquals("MyValue", properties2.get("MyKey")); 946 } 947 948 public static boolean isDirty(Node node, DirtyBits[] dbs) { 949 for(DirtyBits db:dbs) { 950 if (!NodeShim.isDirty(node, db)) { 951 System.out.printf("@NodeTest:check dirty: %s [%d]\n",db,db.ordinal()); 952 return false; 953 } 954 } 955 return true; 956 } 957 958 @Test 959 public void testDefaultValueForViewOrderIsZeroWhenReadFromGetter() { 960 final Node node = new Rectangle(); 961 assertEquals(0, node.getViewOrder(), .005); 962 } 963 964 @Test 965 public void testDefaultValueForViewOrderIsZeroWhenReadFromProperty() { 966 final Node node = new Rectangle(); 967 assertEquals(0, node.viewOrderProperty().get(), .005); 968 } 969 970 @Test 971 public void settingViewOrderThroughSetterShouldAffectBothGetterAndProperty() { 972 final Node node = new Rectangle(); 973 node.setViewOrder(.5); 974 assertEquals(.5, node.getViewOrder(), .005); 975 assertEquals(.5, node.viewOrderProperty().get(), .005); 976 } 977 978 @Test 979 public void settingViewOrderThroughPropertyShouldAffectBothGetterAndProperty() { 980 final Node node = new Rectangle(); 981 node.viewOrderProperty().set(.5); 982 assertEquals(.5, node.getViewOrder(), .005); 983 assertEquals(.5, node.viewOrderProperty().get(), .005); 984 } 985 986 @Test 987 public void testDefaultValueForOpacityIsOneWhenReadFromGetter() { 988 final Node node = new Rectangle(); 989 assertEquals(1, node.getOpacity(), .005); 990 } 991 992 @Test 993 public void testDefaultValueForOpacityIsOneWhenReadFromProperty() { 994 final Node node = new Rectangle(); 995 assertEquals(1, node.opacityProperty().get(), .005); 996 } 997 998 @Test 999 public void settingOpacityThroughSetterShouldAffectBothGetterAndProperty() { 1000 final Node node = new Rectangle(); 1001 node.setOpacity(.5); 1002 assertEquals(.5, node.getOpacity(), .005); 1003 assertEquals(.5, node.opacityProperty().get(), .005); 1004 } 1005 1006 @Test 1007 public void settingOpacityThroughPropertyShouldAffectBothGetterAndProperty() { 1008 final Node node = new Rectangle(); 1009 node.opacityProperty().set(.5); 1010 assertEquals(.5, node.getOpacity(), .005); 1011 assertEquals(.5, node.opacityProperty().get(), .005); 1012 } 1013 1014 @Test 1015 public void testDefaultValueForVisibleIsTrueWhenReadFromGetter() { 1016 final Node node = new Rectangle(); 1017 assertTrue(node.isVisible()); 1018 } 1019 1020 @Test 1021 public void testDefaultValueForVisibleIsTrueWhenReadFromProperty() { 1022 final Node node = new Rectangle(); 1023 assertTrue(node.visibleProperty().get()); 1024 } 1025 1026 @Test 1027 public void settingVisibleThroughSetterShouldAffectBothGetterAndProperty() { 1028 final Node node = new Rectangle(); 1029 node.setVisible(false); 1030 assertFalse(node.isVisible()); 1031 assertFalse(node.visibleProperty().get()); 1032 } 1033 1034 @Test 1035 public void settingVisibleThroughPropertyShouldAffectBothGetterAndProperty() { 1036 final Node node = new Rectangle(); 1037 node.visibleProperty().set(false); 1038 assertFalse(node.isVisible()); 1039 assertFalse(node.visibleProperty().get()); 1040 } 1041 1042 @Test 1043 public void testDefaultStyleIsEmptyString() { 1044 final Node node = new Rectangle(); 1045 assertEquals("", node.getStyle()); 1046 assertEquals("", node.styleProperty().get()); 1047 node.setStyle(null); 1048 assertEquals("", node.styleProperty().get()); 1049 assertEquals("", node.getStyle()); 1050 } 1051 1052 @Test 1053 public void testSynchronizationOfInvisibleNodes() { 1054 final Group g = new Group(); 1055 final Circle c = new CircleTest.StubCircle(50); 1056 final NGGroup sg = NodeHelper.getPeer(g); 1057 final CircleTest.StubNGCircle sc = NodeHelper.getPeer(c); 1058 ParentShim.getChildren(g).add(c); 1059 1060 syncNode(g); 1061 syncNode(c); 1062 assertFalse(sg.getChildren().isEmpty()); 1063 assertEquals(50.0, sc.getRadius(), 0.01); 1064 1065 g.setVisible(false); 1066 1067 syncNode(g); 1068 syncNode(c); 1069 assertFalse(sg.isVisible()); 1070 1071 final Rectangle r = new Rectangle(); 1072 ParentShim.getChildren(g).add(r); 1073 c.setRadius(100); 1074 1075 syncNode(g); 1076 syncNode(c); 1077 // Group with change in children will always be synced even if it is invisible 1078 assertEquals(2, sg.getChildren().size()); 1079 assertEquals(50.0, sc.getRadius(), 0.01); 1080 1081 g.setVisible(true); 1082 1083 syncNode(g); 1084 syncNode(c); 1085 assertEquals(2, sg.getChildren().size()); 1086 assertEquals(100.0, sc.getRadius(), 0.01); 1087 1088 } 1089 1090 @Test 1091 public void testIsTreeVisible() { 1092 final Group g = new Group(); 1093 final Circle c = new CircleTest.StubCircle(50); 1094 1095 ParentShim.getChildren(g).add(c); 1096 1097 Scene s = new Scene(g); 1098 Stage st = new Stage(); 1099 1100 assertTrue(NodeHelper.isTreeVisible(g)); 1101 assertTrue(NodeHelper.isTreeVisible(c)); 1102 assertFalse(NodeHelper.isTreeShowing(g)); 1103 assertFalse(NodeHelper.isTreeShowing(c)); 1104 1105 st.show(); 1106 st.setScene(s); 1107 1108 assertTrue(NodeHelper.isTreeVisible(g)); 1109 assertTrue(NodeHelper.isTreeVisible(c)); 1110 assertTrue(NodeHelper.isTreeShowing(g)); 1111 assertTrue(NodeHelper.isTreeShowing(c)); 1112 1113 SceneShim.scenePulseListener_pulse(s); 1114 1115 assertTrue(NodeHelper.isTreeVisible(g)); 1116 assertTrue(NodeHelper.isTreeVisible(c)); 1117 assertTrue(NodeHelper.isTreeShowing(g)); 1118 assertTrue(NodeHelper.isTreeShowing(c)); 1119 1120 g.setVisible(false); 1121 SceneShim.scenePulseListener_pulse(s); 1122 1123 assertFalse(NodeHelper.isTreeVisible(g)); 1124 assertFalse(NodeHelper.isTreeVisible(c)); 1125 assertFalse(NodeHelper.isTreeShowing(g)); 1126 assertFalse(NodeHelper.isTreeShowing(c)); 1127 1128 g.setVisible(true); 1129 SceneShim.scenePulseListener_pulse(s); 1130 1131 assertTrue(NodeHelper.isTreeVisible(g)); 1132 assertTrue(NodeHelper.isTreeVisible(c)); 1133 assertTrue(NodeHelper.isTreeShowing(g)); 1134 assertTrue(NodeHelper.isTreeShowing(c)); 1135 1136 c.setVisible(false); 1137 SceneShim.scenePulseListener_pulse(s); 1138 1139 assertTrue(NodeHelper.isTreeVisible(g)); 1140 assertFalse(NodeHelper.isTreeVisible(c)); 1141 assertTrue(NodeHelper.isTreeShowing(g)); 1142 assertFalse(NodeHelper.isTreeShowing(c)); 1143 1144 c.setVisible(true); 1145 SceneShim.scenePulseListener_pulse(s); 1146 1147 assertTrue(NodeHelper.isTreeVisible(g)); 1148 assertTrue(NodeHelper.isTreeVisible(c)); 1149 assertTrue(NodeHelper.isTreeShowing(g)); 1150 assertTrue(NodeHelper.isTreeShowing(c)); 1151 1152 s.setRoot(new Group()); 1153 SceneShim.scenePulseListener_pulse(s); 1154 1155 assertTrue(NodeHelper.isTreeVisible(g)); 1156 assertTrue(NodeHelper.isTreeVisible(c)); 1157 assertFalse(NodeHelper.isTreeShowing(g)); 1158 assertFalse(NodeHelper.isTreeShowing(c)); 1159 1160 s.setRoot(g); 1161 SceneShim.scenePulseListener_pulse(s); 1162 1163 assertTrue(NodeHelper.isTreeVisible(g)); 1164 assertTrue(NodeHelper.isTreeVisible(c)); 1165 assertTrue(NodeHelper.isTreeShowing(g)); 1166 assertTrue(NodeHelper.isTreeShowing(c)); 1167 1168 st.hide(); 1169 SceneShim.scenePulseListener_pulse(s); 1170 1171 assertTrue(NodeHelper.isTreeVisible(g)); 1172 assertTrue(NodeHelper.isTreeVisible(c)); 1173 assertFalse(NodeHelper.isTreeShowing(g)); 1174 assertFalse(NodeHelper.isTreeShowing(c)); 1175 1176 } 1177 1178 @Test 1179 public void testSynchronizationOfInvisibleNodes_2() { 1180 final Group g = new Group(); 1181 final Circle c = new CircleTest.StubCircle(50); 1182 1183 Scene s = new Scene(g); 1184 Stage st = new Stage(); 1185 st.show(); 1186 st.setScene(s); 1187 1188 final NGGroup sg = NodeHelper.getPeer(g); 1189 final CircleTest.StubNGCircle sc = NodeHelper.getPeer(c); 1190 1191 ParentShim.getChildren(g).add(c); 1192 1193 SceneShim.scenePulseListener_pulse(s); 1194 1195 g.setVisible(false); 1196 1197 SceneShim.scenePulseListener_pulse(s); 1198 1199 assertFalse(sg.isVisible()); 1200 assertTrue(sc.isVisible()); 1201 1202 c.setCenterX(10); // Make the circle dirty. It won't be synchronized as it is practically invisible (through the parent) 1203 1204 SceneShim.scenePulseListener_pulse(s); 1205 1206 c.setVisible(false); // As circle is invisible and dirty, this won't trigger a synchronization 1207 1208 SceneShim.scenePulseListener_pulse(s); 1209 1210 assertFalse(sg.isVisible()); 1211 assertTrue(sc.isVisible()); // This has not been synchronized, as it's not necessary 1212 // The rendering will stop at the Group, which is invisible 1213 1214 g.setVisible(true); 1215 1216 SceneShim.scenePulseListener_pulse(s); 1217 1218 assertTrue(sg.isVisible()); 1219 assertFalse(sc.isVisible()); // Now the group is visible again, we need to synchronize also 1220 // the Circle 1221 } 1222 1223 @Test 1224 public void testSynchronizationOfInvisibleNodes_2_withClip() { 1225 final Group g = new Group(); 1226 final Circle c = new CircleTest.StubCircle(50); 1227 1228 Scene s = new Scene(g); 1229 Stage st = new Stage(); 1230 st.show(); 1231 st.setScene(s); 1232 1233 final NGGroup sg = NodeHelper.getPeer(g); 1234 final CircleTest.StubNGCircle sc = NodeHelper.getPeer(c); 1235 1236 g.setClip(c); 1237 1238 SceneShim.scenePulseListener_pulse(s); 1239 1240 g.setVisible(false); 1241 1242 SceneShim.scenePulseListener_pulse(s); 1243 1244 assertFalse(sg.isVisible()); 1245 assertTrue(sc.isVisible()); 1246 1247 c.setCenterX(10); // Make the circle dirty. It won't be synchronized as it is practically invisible (through the parent) 1248 1249 SceneShim.scenePulseListener_pulse(s); 1250 1251 c.setVisible(false); // As circle is invisible and dirty, this won't trigger a synchronization 1252 1253 SceneShim.scenePulseListener_pulse(s); 1254 1255 assertFalse(sg.isVisible()); 1256 assertTrue(sc.isVisible()); // This has not been synchronized, as it's not necessary 1257 // The rendering will stop at the Group, which is invisible 1258 1259 g.setVisible(true); 1260 1261 SceneShim.scenePulseListener_pulse(s); 1262 1263 assertTrue(sg.isVisible()); 1264 assertFalse(sc.isVisible()); // Now the group is visible again, we need to synchronize also 1265 // the Circle 1266 } 1267 1268 @Test 1269 public void testLocalToScreen() { 1270 Rectangle rect = new Rectangle(); 1271 1272 rect.setTranslateX(10); 1273 rect.setTranslateY(20); 1274 1275 TestScene scene = new TestScene(new Group(rect)); 1276 final TestStage testStage = new TestStage(""); 1277 testStage.setX(100); 1278 testStage.setY(200); 1279 scene.set_window(testStage); 1280 Point2D p = rect.localToScreen(new Point2D(1, 2)); 1281 assertEquals(111.0, p.getX(), 0.0001); 1282 assertEquals(222.0, p.getY(), 0.0001); 1283 Bounds b = rect.localToScreen(new BoundingBox(1, 2, 3, 4)); 1284 assertEquals(111.0, b.getMinX(), 0.0001); 1285 assertEquals(222.0, b.getMinY(), 0.0001); 1286 assertEquals(3.0, b.getWidth(), 0.0001); 1287 assertEquals(4.0, b.getHeight(), 0.0001); 1288 } 1289 1290 @Test 1291 public void testLocalToScreen3D() { 1292 Box box = new Box(10, 10, 10); 1293 1294 box.setTranslateX(10); 1295 box.setTranslateY(20); 1296 1297 TestScene scene = new TestScene(new Group(box)); 1298 scene.setCamera(new PerspectiveCamera()); 1299 final TestStage testStage = new TestStage(""); 1300 testStage.setX(100); 1301 testStage.setY(200); 1302 scene.set_window(testStage); 1303 1304 Point2D p = box.localToScreen(new Point3D(1, 2, -5)); 1305 assertEquals(111.42, p.getX(), 0.1); 1306 assertEquals(223.14, p.getY(), 0.1); 1307 Bounds b = box.localToScreen(new BoundingBox(1, 2, -5, 1, 2, 10)); 1308 assertEquals(110.66, b.getMinX(), 0.1); 1309 assertEquals(221.08, b.getMinY(), 0.1); 1310 assertEquals(1.88, b.getWidth(), 0.1); 1311 assertEquals(4.3, b.getHeight(), 0.1); 1312 assertEquals(0.0, b.getDepth(), 0.0001); 1313 } 1314 1315 @Test 1316 public void testScreenToLocal() { 1317 Rectangle rect = new Rectangle(); 1318 1319 rect.setTranslateX(10); 1320 rect.setTranslateY(20); 1321 1322 TestScene scene = new TestScene(new Group(rect)); 1323 final TestStage testStage = new TestStage(""); 1324 testStage.setX(100); 1325 testStage.setY(200); 1326 scene.set_window(testStage); 1327 1328 assertEquals(new Point2D(1, 2), rect.screenToLocal(new Point2D(111, 222))); 1329 assertEquals(new BoundingBox(1, 2, 3, 4), rect.screenToLocal(new BoundingBox(111, 222, 3, 4))); 1330 } 1331 1332 @Test 1333 public void testLocalToScreenWithTranslatedCamera() { 1334 Rectangle rect = new Rectangle(); 1335 1336 rect.setTranslateX(10); 1337 rect.setTranslateY(20); 1338 1339 ParallelCamera cam = new ParallelCamera(); 1340 TestScene scene = new TestScene(new Group(rect, cam)); 1341 scene.setCamera(cam); 1342 final TestStage testStage = new TestStage(""); 1343 testStage.setX(100); 1344 testStage.setY(200); 1345 cam.setTranslateX(30); 1346 cam.setTranslateY(20); 1347 scene.set_window(testStage); 1348 1349 Point2D p = rect.localToScreen(new Point2D(1, 2)); 1350 assertEquals(81.0, p.getX(), 0.0001); 1351 assertEquals(202.0, p.getY(), 0.0001); 1352 Bounds b = rect.localToScreen(new BoundingBox(1, 2, 3, 4)); 1353 assertEquals(81.0, b.getMinX(), 0.0001); 1354 assertEquals(202.0, b.getMinY(), 0.0001); 1355 assertEquals(3.0, b.getWidth(), 0.0001); 1356 assertEquals(4.0, b.getHeight(), 0.0001); 1357 } 1358 1359 @Test 1360 public void testScreenToLocalWithTranslatedCamera() { 1361 Rectangle rect = new Rectangle(); 1362 1363 rect.setTranslateX(10); 1364 rect.setTranslateY(20); 1365 1366 ParallelCamera cam = new ParallelCamera(); 1367 TestScene scene = new TestScene(new Group(rect, cam)); 1368 scene.setCamera(cam); 1369 final TestStage testStage = new TestStage(""); 1370 testStage.setX(100); 1371 testStage.setY(200); 1372 cam.setTranslateX(30); 1373 cam.setTranslateY(20); 1374 scene.set_window(testStage); 1375 1376 assertEquals(new Point2D(31, 22), rect.screenToLocal(new Point2D(111, 222))); 1377 assertEquals(new BoundingBox(31, 22, 3, 4), rect.screenToLocal(new BoundingBox(111, 222, 3, 4))); 1378 } 1379 1380 @Test 1381 public void testLocalToScreenInsideSubScene() { 1382 Rectangle rect = new Rectangle(); 1383 rect.setTranslateX(4); 1384 rect.setTranslateY(9); 1385 SubScene subScene = new SubScene(new Group(rect), 100, 100); 1386 subScene.setTranslateX(6); 1387 subScene.setTranslateY(11); 1388 1389 TestScene scene = new TestScene(new Group(subScene)); 1390 final TestStage testStage = new TestStage(""); 1391 testStage.setX(100); 1392 testStage.setY(200); 1393 scene.set_window(testStage); 1394 1395 Point2D p = rect.localToScreen(new Point2D(1, 2)); 1396 assertEquals(111.0, p.getX(), 0.0001); 1397 assertEquals(222.0, p.getY(), 0.0001); 1398 Bounds b = rect.localToScreen(new BoundingBox(1, 2, 3, 4)); 1399 assertEquals(111.0, b.getMinX(), 0.0001); 1400 assertEquals(222.0, b.getMinY(), 0.0001); 1401 assertEquals(3.0, b.getWidth(), 0.0001); 1402 assertEquals(4.0, b.getHeight(), 0.0001); 1403 } 1404 1405 @Test 1406 public void testScreenToLocalInsideSubScene() { 1407 Rectangle rect = new Rectangle(); 1408 rect.setTranslateX(4); 1409 rect.setTranslateY(9); 1410 SubScene subScene = new SubScene(new Group(rect), 100, 100); 1411 subScene.setTranslateX(6); 1412 subScene.setTranslateY(11); 1413 1414 TestScene scene = new TestScene(new Group(subScene)); 1415 final TestStage testStage = new TestStage(""); 1416 testStage.setX(100); 1417 testStage.setY(200); 1418 scene.set_window(testStage); 1419 1420 assertEquals(new Point2D(1, 2), rect.screenToLocal(new Point2D(111, 222))); 1421 assertEquals(new BoundingBox(1, 2, 3, 4), rect.screenToLocal(new BoundingBox(111, 222, 3, 4))); 1422 } 1423 1424 @Test 1425 public void test2DLocalToScreenOn3DRotatedSubScene() { 1426 Rectangle rect = new Rectangle(); 1427 rect.setTranslateX(5); 1428 rect.setTranslateY(10); 1429 SubScene subScene = new SubScene(new Group(rect), 100, 100); 1430 subScene.setTranslateX(5); 1431 subScene.setTranslateY(10); 1432 subScene.setRotationAxis(Rotate.Y_AXIS); 1433 subScene.setRotate(40); 1434 1435 TestScene scene = new TestScene(new Group(subScene)); 1436 scene.setCamera(new PerspectiveCamera()); 1437 final TestStage testStage = new TestStage(""); 1438 testStage.setX(100); 1439 testStage.setY(200); 1440 scene.set_window(testStage); 1441 1442 Point2D p = rect.localToScreen(new Point2D(1, 2)); 1443 assertEquals(124.36, p.getX(), 0.1); 1444 assertEquals(226.0, p.getY(), 0.1); 1445 Bounds b = rect.localToScreen(new BoundingBox(1, 2, 3, 4)); 1446 assertEquals(124.36, b.getMinX(), 0.1); 1447 assertEquals(225.75, b.getMinY(), 0.1); 1448 assertEquals(1.85, b.getWidth(), 0.1); 1449 assertEquals(3.76, b.getHeight(), 0.1); 1450 } 1451 1452 @Test 1453 public void test2DScreenToLocalTo3DRotatedSubScene() { 1454 Rectangle rect = new Rectangle(); 1455 rect.setTranslateX(5); 1456 rect.setTranslateY(10); 1457 SubScene subScene = new SubScene(new Group(rect), 100, 100); 1458 subScene.setTranslateX(5); 1459 subScene.setTranslateY(10); 1460 subScene.setRotationAxis(Rotate.Y_AXIS); 1461 subScene.setRotate(40); 1462 1463 TestScene scene = new TestScene(new Group(subScene)); 1464 scene.setCamera(new PerspectiveCamera()); 1465 final TestStage testStage = new TestStage(""); 1466 testStage.setX(100); 1467 testStage.setY(200); 1468 scene.set_window(testStage); 1469 1470 Point2D p = rect.screenToLocal(new Point2D(124.36, 226.0)); 1471 assertEquals(1, p.getX(), 0.1); 1472 assertEquals(2, p.getY(), 0.1); 1473 Bounds b = rect.screenToLocal(new BoundingBox(124.36, 225.75, 1.85, 3.76)); 1474 assertEquals(1, b.getMinX(), 0.1); 1475 assertEquals(1.72, b.getMinY(), 0.1); 1476 assertEquals(3, b.getWidth(), 0.1); 1477 assertEquals(4.52, b.getHeight(), 0.1); 1478 } 1479 1480 @Test 1481 public void testScreenToLocalWithNonInvertibleTransform() { 1482 Rectangle rect = new Rectangle(); 1483 1484 rect.setScaleX(0.0); 1485 1486 TestScene scene = new TestScene(new Group(rect)); 1487 final TestStage testStage = new TestStage(""); 1488 testStage.setX(100); 1489 testStage.setY(200); 1490 scene.set_window(testStage); 1491 1492 assertNull(rect.screenToLocal(new Point2D(111, 222))); 1493 assertNull(rect.screenToLocal(new BoundingBox(111, 222, 3, 4))); 1494 } 1495 1496 @Test 1497 public void testScreenToLocalInsideNonInvertibleSubScene() { 1498 Rectangle rect = new Rectangle(); 1499 rect.setTranslateX(4); 1500 rect.setTranslateY(9); 1501 SubScene subScene = new SubScene(new Group(rect), 100, 100); 1502 subScene.setScaleX(0.0); 1503 1504 TestScene scene = new TestScene(new Group(subScene)); 1505 final TestStage testStage = new TestStage(""); 1506 testStage.setX(100); 1507 testStage.setY(200); 1508 scene.set_window(testStage); 1509 1510 assertNull(rect.screenToLocal(new Point2D(111, 222))); 1511 assertNull(rect.screenToLocal(new BoundingBox(111, 222, 3, 4))); 1512 } 1513 1514 @Test 1515 public void testRootMirroringWithTranslate() { 1516 final Group rootGroup = new Group(); 1517 rootGroup.setTranslateX(20); 1518 rootGroup.setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT); 1519 final Scene scene = new Scene(rootGroup, 200, 200); 1520 1521 final Point2D trPoint = scene.getRoot().localToScene(0, 0); 1522 assertEquals(180, trPoint.getX(), 0.1); 1523 } 1524 1525 1526 @Test 1527 public void testLayoutXYTriggersParentSizeChange() { 1528 final Group rootGroup = new Group(); 1529 final Group subGroup = new Group(); 1530 ParentShim.getChildren(rootGroup).add(subGroup); 1531 1532 Rectangle r = new Rectangle(50,50); 1533 r.setManaged(false); 1534 Rectangle staticR = new Rectangle(1,1); 1535 ParentShim.getChildren(subGroup).addAll(r, staticR); 1536 1537 assertEquals(50,subGroup.getLayoutBounds().getWidth(), 1e-10); 1538 assertEquals(50,subGroup.getLayoutBounds().getHeight(), 1e-10); 1539 1540 r.setLayoutX(50); 1541 1542 rootGroup.layout(); 1543 1544 assertEquals(100,subGroup.getLayoutBounds().getWidth(), 1e-10); 1545 assertEquals(50,subGroup.getLayoutBounds().getHeight(), 1e-10); 1546 1547 } 1548 1549 @Test 1550 public void testLayoutXYWontBreakLayout() { 1551 final Group rootGroup = new Group(); 1552 final AnchorPane pane = new AnchorPane(); 1553 ParentShim.getChildren(rootGroup).add(pane); 1554 1555 Rectangle r = new Rectangle(50,50); 1556 ParentShim.getChildren(pane).add(r); 1557 1558 AnchorPane.setLeftAnchor(r, 10d); 1559 AnchorPane.setTopAnchor(r, 10d); 1560 1561 rootGroup.layout(); 1562 1563 assertEquals(10, r.getLayoutX(), 1e-10); 1564 assertEquals(10, r.getLayoutY(), 1e-10); 1565 1566 r.setLayoutX(50); 1567 1568 assertEquals(50, r.getLayoutX(), 1e-10); 1569 assertEquals(10, r.getLayoutY(), 1e-10); 1570 1571 rootGroup.layout(); 1572 1573 assertEquals(10, r.getLayoutX(), 1e-10); 1574 assertEquals(10, r.getLayoutY(), 1e-10); 1575 1576 } 1577 1578 @Test 1579 public void clipShouldUpdateAfterParentVisibilityChange() { 1580 1581 final Group root = new Group(); 1582 Scene scene = new Scene(root, 300, 300); 1583 1584 final Group parent = new Group(); 1585 parent.setVisible(false); 1586 1587 final Circle circle = new Circle(100, 100, 100); 1588 ParentShim.getChildren(parent).add(circle); 1589 1590 final Rectangle clip = new StubRect(100, 100); 1591 circle.setClip(clip); 1592 1593 ParentShim.getChildren(root).add(parent); 1594 parent.setVisible(true); 1595 1596 Stage stage = new Stage(); 1597 stage.setScene(scene); 1598 stage.show(); 1599 1600 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1601 1602 clip.setWidth(300); 1603 1604 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1605 1606 assertEquals(300, ((MockNGRect) NodeHelper.getPeer(clip)).w, 1e-10); 1607 } 1608 1609 @Test 1610 public void untransformedNodeShouldSyncIdentityTransform() { 1611 final Node node = createTestRect(); 1612 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1613 assertSame(BaseTransform.IDENTITY_TRANSFORM, 1614 ((MockNGRect) NodeHelper.getPeer(node)).t); 1615 } 1616 1617 @Test 1618 public void nodeTransfomedByIdentitiesShouldSyncIdentityTransform() { 1619 final Node node = createTestRect(); 1620 node.setRotationAxis(Rotate.X_AXIS); 1621 node.getTransforms().add(new Translate()); 1622 node.getTransforms().add(new Scale()); 1623 node.getTransforms().add(new Affine()); 1624 node.getTransforms().add(new Rotate(0, Rotate.Y_AXIS)); 1625 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1626 assertSame(BaseTransform.IDENTITY_TRANSFORM, 1627 ((MockNGRect) NodeHelper.getPeer(node)).t); 1628 } 1629 1630 @Test 1631 public void translatedNodeShouldSyncTranslateTransform1() { 1632 final Node node = createTestRect(); 1633 node.setTranslateX(30); 1634 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1635 assertSame(Translate2D.class, 1636 ((MockNGRect) NodeHelper.getPeer(node)).t.getClass()); 1637 } 1638 1639 @Test 1640 public void translatedNodeShouldSyncTranslateTransform2() { 1641 final Node node = createTestRect(); 1642 node.getTransforms().add(new Translate(20, 10)); 1643 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1644 assertSame(Translate2D.class, 1645 ((MockNGRect) NodeHelper.getPeer(node)).t.getClass()); 1646 } 1647 1648 @Test 1649 public void multitranslatedNodeShouldSyncTranslateTransform() { 1650 final Node node = createTestRect(); 1651 node.setTranslateX(30); 1652 node.getTransforms().add(new Translate(20, 10)); 1653 node.getTransforms().add(new Translate(10, 20)); 1654 node.getTransforms().add(new Translate(5, 5, 0)); 1655 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1656 assertSame(Translate2D.class, 1657 ((MockNGRect) NodeHelper.getPeer(node)).t.getClass()); 1658 } 1659 1660 @Test 1661 public void mirroringShouldSyncAffine2DTransform() { 1662 final Node node = createTestRect(); 1663 node.setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT); 1664 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1665 assertSame(Affine2D.class, 1666 ((MockNGRect) NodeHelper.getPeer(node)).t.getClass()); 1667 } 1668 1669 @Test 1670 public void rotatedNodeShouldSyncAffine2DTransform1() { 1671 final Node node = createTestRect(); 1672 node.setRotate(20); 1673 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1674 assertSame(Affine2D.class, 1675 ((MockNGRect) NodeHelper.getPeer(node)).t.getClass()); 1676 } 1677 1678 @Test 1679 public void rotatedNodeShouldSyncAffine2DTransform2() { 1680 final Node node = createTestRect(); 1681 node.getTransforms().add(new Rotate(20)); 1682 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1683 assertSame(Affine2D.class, 1684 ((MockNGRect) NodeHelper.getPeer(node)).t.getClass()); 1685 } 1686 1687 @Test 1688 public void multiRotatedNodeShouldSyncAffine2DTransform() { 1689 final Node node = createTestRect(); 1690 node.setRotate(20); 1691 node.getTransforms().add(new Rotate(20)); 1692 node.getTransforms().add(new Rotate(0, Rotate.X_AXIS)); 1693 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1694 assertSame(Affine2D.class, 1695 ((MockNGRect) NodeHelper.getPeer(node)).t.getClass()); 1696 } 1697 1698 @Test 1699 public void scaledNodeShouldSyncAffine2DTransform1() { 1700 final Node node = createTestRect(); 1701 node.setScaleX(2); 1702 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1703 assertSame(Affine2D.class, 1704 ((MockNGRect) NodeHelper.getPeer(node)).t.getClass()); 1705 } 1706 1707 @Test 1708 public void scaledNodeShouldSyncAffine2DTransform2() { 1709 final Node node = createTestRect(); 1710 node.getTransforms().add(new Scale(2, 1)); 1711 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1712 assertSame(Affine2D.class, 1713 ((MockNGRect) NodeHelper.getPeer(node)).t.getClass()); 1714 } 1715 1716 @Test 1717 public void multiScaledNodeShouldSyncAffine2DTransform() { 1718 final Node node = createTestRect(); 1719 node.setScaleX(20); 1720 node.getTransforms().add(new Scale(2, 1)); 1721 node.getTransforms().add(new Scale(0.5, 2, 1)); 1722 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1723 assertSame(Affine2D.class, 1724 ((MockNGRect) NodeHelper.getPeer(node)).t.getClass()); 1725 } 1726 1727 @Test 1728 public void shearedNodeShouldSyncAffine2DTransform() { 1729 final Node node = createTestRect(); 1730 node.getTransforms().add(new Shear(2, 1)); 1731 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1732 assertSame(Affine2D.class, 1733 ((MockNGRect) NodeHelper.getPeer(node)).t.getClass()); 1734 } 1735 1736 @Test 1737 public void ztranslatedNodeShouldSyncAffine3DTransform1() { 1738 final Node node = createTestRect(); 1739 node.setTranslateZ(30); 1740 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1741 assertSame(Affine3D.class, 1742 ((MockNGRect) NodeHelper.getPeer(node)).t.getClass()); 1743 } 1744 1745 @Test 1746 public void ztranslatedNodeShouldSyncAffine3DTransform2() { 1747 final Node node = createTestRect(); 1748 node.getTransforms().add(new Translate(0, 0, 10)); 1749 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1750 assertSame(Affine3D.class, 1751 ((MockNGRect) NodeHelper.getPeer(node)).t.getClass()); 1752 } 1753 1754 @Test 1755 public void zscaledNodeShouldSyncAffine3DTransform1() { 1756 final Node node = createTestRect(); 1757 node.setScaleZ(0.5); 1758 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1759 assertSame(Affine3D.class, 1760 ((MockNGRect) NodeHelper.getPeer(node)).t.getClass()); 1761 } 1762 1763 @Test 1764 public void zscaledNodeShouldSyncAffine3DTransform2() { 1765 final Node node = createTestRect(); 1766 node.getTransforms().add(new Scale(1, 1, 2)); 1767 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1768 assertSame(Affine3D.class, 1769 ((MockNGRect) NodeHelper.getPeer(node)).t.getClass()); 1770 } 1771 1772 @Test 1773 public void nonZRotatedNodeShouldSyncAffine3DTransform1() { 1774 final Node node = createTestRect(); 1775 node.setRotationAxis(Rotate.Y_AXIS); 1776 node.setRotate(10); 1777 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1778 assertSame(Affine3D.class, 1779 ((MockNGRect) NodeHelper.getPeer(node)).t.getClass()); 1780 } 1781 1782 @Test 1783 public void nonZRotatedNodeShouldSyncAffine3DTransform2() { 1784 final Node node = createTestRect(); 1785 node.getTransforms().add(new Rotate(10, Rotate.X_AXIS)); 1786 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1787 assertSame(Affine3D.class, 1788 ((MockNGRect) NodeHelper.getPeer(node)).t.getClass()); 1789 } 1790 1791 @Test 1792 public void translateTransformShouldBeReusedWhenPossible() { 1793 final Node node = createTestRect(); 1794 node.setTranslateX(10); 1795 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1796 1797 BaseTransform t = ((MockNGRect) NodeHelper.getPeer(node)).t; 1798 1799 ((MockNGRect) NodeHelper.getPeer(node)).t = null; 1800 node.setTranslateX(20); 1801 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1802 1803 assertSame(t, ((MockNGRect) NodeHelper.getPeer(node)).t); 1804 } 1805 1806 @Test 1807 public void affine2DTransformShouldBeReusedWhenPossible() { 1808 final Node node = createTestRect(); 1809 node.setScaleX(10); 1810 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1811 1812 BaseTransform t = ((MockNGRect) NodeHelper.getPeer(node)).t; 1813 1814 ((MockNGRect) NodeHelper.getPeer(node)).t = null; 1815 node.setRotate(20); 1816 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1817 1818 assertSame(t, ((MockNGRect) NodeHelper.getPeer(node)).t); 1819 } 1820 1821 @Test 1822 public void affine3DTransformShouldBeReusedWhenPossible() { 1823 final Node node = createTestRect(); 1824 node.setScaleZ(10); 1825 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1826 1827 BaseTransform t = ((MockNGRect) NodeHelper.getPeer(node)).t; 1828 1829 ((MockNGRect) NodeHelper.getPeer(node)).t = null; 1830 node.setRotate(20); 1831 ((StubToolkit) Toolkit.getToolkit()).firePulse(); 1832 1833 assertSame(t, ((MockNGRect) NodeHelper.getPeer(node)).t); 1834 } 1835 1836 @Test 1837 public void rtlSceneSizeShouldBeComputedCorrectly() { 1838 Scene scene = new Scene(new Group(new Rectangle(100, 100))); 1839 scene.setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT); 1840 Stage stage = new Stage(); 1841 stage.setScene(scene); 1842 stage.show(); 1843 assertEquals(100.0, scene.getWidth(), 0.00001); 1844 } 1845 1846 private Node createTestRect() { 1847 final Rectangle rect = new StubRect(); 1848 Scene scene = new Scene(new Group(rect)); 1849 Stage stage = new Stage(); 1850 stage.setScene(scene); 1851 stage.show(); 1852 return rect; 1853 } 1854 1855 private static class MockNGRect extends NGRectangle { 1856 double w = 0; 1857 BaseTransform t = null; 1858 1859 @Override public void updateRectangle(float x, float y, float width, 1860 float height, float arcWidth, float arcHeight) { 1861 w = width; 1862 } 1863 1864 @Override 1865 public void setTransformMatrix(BaseTransform tx) { 1866 t = tx; 1867 } 1868 } 1869 1870 static class StubRect extends Rectangle { 1871 static { 1872 StubRectHelper.setStubRectAccessor(new StubRectHelper.StubRectAccessor() { 1873 @Override 1874 public NGNode doCreatePeer(Node node) { 1875 return ((StubRect) node).doCreatePeer(); 1876 } 1877 }); 1878 } 1879 1880 StubRect() { 1881 super(); 1882 StubRectHelper.initHelper(this); 1883 } 1884 1885 StubRect(double width, double height) { 1886 super(width, height); 1887 StubRectHelper.initHelper(this); 1888 } 1889 1890 private NGNode doCreatePeer() { 1891 return new MockNGRect(); 1892 } 1893 } 1894 1895 public static class StubRectHelper extends RectangleHelper { 1896 1897 private static final StubRectHelper theInstance; 1898 private static StubRectAccessor stubRectAccessor; 1899 1900 static { 1901 theInstance = new StubRectHelper(); 1902 Utils.forceInit(StubRect.class); 1903 } 1904 1905 private static StubRectHelper getInstance() { 1906 return theInstance; 1907 } 1908 1909 public static void initHelper(StubRect stubRect) { 1910 setHelper(stubRect, getInstance()); 1911 } 1912 1913 public static void setStubRectAccessor(final StubRectAccessor newAccessor) { 1914 if (stubRectAccessor != null) { 1915 throw new IllegalStateException(); 1916 } 1917 1918 stubRectAccessor = newAccessor; 1919 } 1920 1921 @Override 1922 protected NGNode createPeerImpl(Node node) { 1923 return stubRectAccessor.doCreatePeer(node); 1924 } 1925 1926 public interface StubRectAccessor { 1927 NGNode doCreatePeer(Node node); 1928 } 1929 1930 } 1931 }