RFR: 8372761: Prevent degenerate transforms for zero-size Scene/SubScene [v2]

Ambarish Rapte arapte at openjdk.org
Fri Dec 5 06:56:12 UTC 2025


On Mon, 1 Dec 2025 22:08:27 GMT, Michael Strauß <mstrauss at openjdk.org> wrote:

>> When a `Scene` or `SubScene` has its width or height set to 0, coordinate transformations stop working because the transformation matrix contains NaNs. This is a consequence of divisions by zero in both parallel and perspective projections.
>> 
>> Even though a 0x0 scene is mathematically degenerate, it is still desirable for coordinate transformation APIs to remain numerically well-behaved and return finite results whenever possible, rather than being poisoned by NaN/Infinity.
>> 
>> Here is an application that demonstrates the failing coordinate transformations. Click on the buttons to resize the SubScene and observe the console output. After applying the patch in this PR, you should observe that `localToScreen()` no longer returns NaN.
>> 
>> 
>> public class ZeroSizeSubScene extends Application {
>> 
>>     @Override
>>     public void start(Stage stage) {
>>         var rect = new Rectangle(50, 50, Color.RED);
>>         var subScene = new SubScene(new Group(rect), 100, 100);
>>         subScene.setFill(Color.GRAY);
>> 
>>         // Also try a perspective camera:
>>         //
>>         // var camera = new PerspectiveCamera();
>>         // camera.setRotate(45);
>>         // camera.setTranslateX(-20);
>>         // camera.setRotationAxis(new Point3D(0, 1, 0));
>>         // subScene.setCamera(camera);
>> 
>>         class MyButton extends Button {
>>             public MyButton(String text, double width, double height) {
>>                 super(text);
>>                 setOnAction(_ -> {
>>                     var timeline = new Timeline(
>>                         new KeyFrame(Duration.seconds(1), new KeyValue(subScene.widthProperty(), width)),
>>                         new KeyFrame(Duration.seconds(1), new KeyValue(subScene.heightProperty(), height)));
>> 
>>                     timeline.setOnFinished(_ -> {
>>                         Point2D p0 = rect.localToScreen(0, 0);
>>                         System.out.println("rect.localToScreen(0, 0) = " + p0);
>>                     });
>> 
>>                     timeline.play();
>>                 });
>>             }
>>         }
>> 
>>         VBox.setMargin(subScene, new Insets(0, 0, 20, 0));
>> 
>>         var root = new VBox(5,
>>             subScene,
>>             new CheckBox("Rotate SubScene") {{ setOnAction(_ -> subScene.setRotate(isSelected() ? 45 : 0)); }},
>>             new MyButton("Size: 100x100", 100, 100),
>>             new MyButton("Size: 10x10", 10, 10),
>>             new MyButton("Size: 100x0", 100, 0),
>>             ne...
>
> Michael Strauß has updated the pull request incrementally with one additional commit since the last revision:
> 
>   review comments

Doc of [localToScreen()](https://openjfx.io/javadoc/24/javafx.graphics/javafx/scene/Node.html#localToScreen(double,double)): Transforms a point from the local coordinate space of this Node into the coordinate space of its Screen
When the sub scene is of size (0, 0), then the sub scene and so it's children will not be shown on screen.
Printing a valid screen coordinates with localToScreen() for nodes that are not shown on screen, seems not correct.
Rather, NaN would imply that something is not correct / the node is not shown on screen.

-------------

PR Comment: https://git.openjdk.org/jfx/pull/1992#issuecomment-3615542508


More information about the openjfx-dev mailing list