Skip to content

Commit

Permalink
8260013: Snapshot does not work for nodes in a subscene
Browse files Browse the repository at this point in the history
Reviewed-by: kcr, mstrauss
  • Loading branch information
Lukasz Kostyra committed Jan 30, 2024
1 parent 876d535 commit d653a31
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ else if (lightBase instanceof NGSpotLight light) {
}

private boolean noLights(NGLightBase[] lights) {
return lights == null || lights[0] == null;
return lights == null || lights.length == 0 || lights[0] == null;
}

/**
Expand Down
4 changes: 2 additions & 2 deletions modules/javafx.graphics/src/main/java/javafx/scene/Node.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2024, 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
Expand Down Expand Up @@ -2146,7 +2146,7 @@ private WritableImage doSnapshot(SnapshotParameters params, WritableImage img) {
w = tempBounds.getWidth();
h = tempBounds.getHeight();
}
WritableImage result = Scene.doSnapshot(getScene(), x, y, w, h,
WritableImage result = Scene.doSnapshot(getScene(), getSubScene(), x, y, w, h,
this, transform, params.isDepthBufferInternal(),
params.getFill(), params.getEffectiveCamera(), img);

Expand Down
22 changes: 12 additions & 10 deletions modules/javafx.graphics/src/main/java/javafx/scene/Scene.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2024, 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
Expand Down Expand Up @@ -92,6 +92,7 @@
import java.security.PrivilegedAction;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Stream;

import com.sun.javafx.logging.PulseLogger;

Expand Down Expand Up @@ -1300,7 +1301,7 @@ void doCSSLayoutSyncForSnapshot(Node node) {

// Shared method for Scene.snapshot and Node.snapshot. It is static because
// we might be doing a Node snapshot with a null scene
static WritableImage doSnapshot(Scene scene,
static WritableImage doSnapshot(Scene scene, SubScene subScene,
double x, double y, double w, double h,
Node root, BaseTransform transform, boolean depthBuffer,
Paint fill, Camera camera, WritableImage wimg) {
Expand Down Expand Up @@ -1346,15 +1347,16 @@ static WritableImage doSnapshot(Scene scene,
context.camera = null;
}

// Grab the lights from the scene
context.lights = null;
if (scene != null && !scene.lights.isEmpty()) {
context.lights = new NGLightBase[scene.lights.size()];
for (int i = 0; i < scene.lights.size(); i++) {
context.lights[i] = scene.lights.get(i).getPeer();
}
// Grab the lights from the scene or subscene
Stream<NGLightBase> lights;
if (subScene != null) {
lights = Optional.of(subScene).stream().flatMap(s -> s.getLights().stream()).map(LightBase::getPeer);
} else {
lights = Optional.ofNullable(scene).stream().flatMap(s -> s.lights.stream()).map(LightBase::getPeer);
}

context.lights = lights.toArray(NGLightBase[]::new);

Toolkit.WritableImageAccessor accessor = Toolkit.getWritableImageAccessor();
context.platformImage = accessor.getTkImageLoader(wimg);
setAllowPGAccess(false);
Expand Down Expand Up @@ -1394,7 +1396,7 @@ private WritableImage doSnapshot(WritableImage img) {
double h = getHeight();
BaseTransform transform = BaseTransform.IDENTITY_TRANSFORM;

return doSnapshot(this, 0, 0, w, h,
return doSnapshot(this, null, 0, 0, w, h,
getRoot(), transform, isDepthBufferInternal(),
getFill(), getEffectiveCamera(), img);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2024, 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
Expand Down Expand Up @@ -930,4 +930,7 @@ private boolean syncLights() {
return lightOwnerChanged;
}

List<LightBase> getLights() {
return lights;
}
}
161 changes: 161 additions & 0 deletions tests/system/src/test/java/test/javafx/scene/SnapshotLightsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/*
* Copyright (c) 2024, 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 test.javafx.scene;

import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.PointLight;
import javafx.scene.Scene;
import javafx.scene.SubScene;
import javafx.scene.image.PixelReader;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.PhongMaterial;
import javafx.scene.shape.Box;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import test.util.Util;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertNotNull;

public class SnapshotLightsTest extends SnapshotCommon {

static final int BOX_DIM = 50;

@BeforeAll
public static void setupOnce() {
doSetupOnce();
}

@AfterAll
public static void teardownOnce() {
doTeardownOnce();
}

@BeforeEach
public void setupEach() {
assertNotNull(myApp);
assertNotNull(myApp.primaryStage);
assertTrue(myApp.primaryStage.isShowing());
}

@AfterEach
public void teardownEach() {
}

private Scene buildScene(boolean inSubScene) {
Box boxNode = new Box(BOX_DIM, BOX_DIM, BOX_DIM - 10);
boxNode.setMaterial(new PhongMaterial(Color.WHITE));

StackPane pane = new StackPane(boxNode);
pane.setAlignment(Pos.CENTER);

PointLight light = new PointLight(Color.BLUE);
light.setTranslateZ(-150);
pane.getChildren().add(light);

if (inSubScene) {
SubScene ss = new SubScene(pane, BOX_DIM, BOX_DIM);
StackPane subSceneRoot = new StackPane(ss);
subSceneRoot.setAlignment(Pos.CENTER);
return new Scene(subSceneRoot, BOX_DIM, BOX_DIM);
} else {
return new Scene(pane, BOX_DIM, BOX_DIM);
}
}

private void compareSnapshots(WritableImage base, WritableImage comp) {
assertEquals(base.getWidth(), comp.getWidth(), 0.1);
assertEquals(base.getHeight(), comp.getHeight(), 0.1);

PixelReader baseReader = base.getPixelReader();
PixelReader compReader = comp.getPixelReader();

assertEquals(baseReader.getArgb(BOX_DIM / 2, BOX_DIM / 2), compReader.getArgb(BOX_DIM / 2, BOX_DIM / 2));
}

public SnapshotLightsTest() {
}

@Test
public void testSceneNodeSnapshotLighting() throws Exception {
Util.runAndWait(() -> {
Scene scene = buildScene(false);
WritableImage baseSnapshot = scene.snapshot(null);

Node boxNode = scene.getRoot().getChildrenUnmodifiable().get(0);
WritableImage nodeSnapshot = boxNode.snapshot(null, null);

compareSnapshots(baseSnapshot, nodeSnapshot);
});
}

@Test
public void testSubSceneNodeSnapshotLighting() throws Exception {
Util.runAndWait(() -> {
Scene scene = buildScene(true);
WritableImage baseSnapshot = scene.snapshot(null);

SubScene ss = (SubScene)scene.getRoot().getChildrenUnmodifiable().get(0);
Node boxNode = ss.getRoot().getChildrenUnmodifiable().get(0);
WritableImage nodeSnapshot = boxNode.snapshot(null, null);

compareSnapshots(baseSnapshot, nodeSnapshot);
});
}

@Test
public void testSubSceneSnapshotWithSceneLights() throws Exception {
Util.runAndWait(() -> {
Scene scene = buildScene(true);

// SubScene is "separated" from Scene, so Scene's lights should not be included
// Add an extra red light to make sure it is actually not included
PointLight light = new PointLight(Color.RED);
light.setTranslateZ(-150);
StackPane sceneRootPane = (StackPane)scene.getRoot();
sceneRootPane.getChildren().add(light);

WritableImage baseSnapshot = scene.snapshot(null);

SubScene ss = (SubScene)scene.getRoot().getChildrenUnmodifiable().get(0);
WritableImage subSceneSnapshot = ss.snapshot(null, null);

Node boxNode = ss.getRoot().getChildrenUnmodifiable().get(0);
WritableImage nodeSnapshot = boxNode.snapshot(null, null);

compareSnapshots(baseSnapshot, subSceneSnapshot);
compareSnapshots(baseSnapshot, nodeSnapshot);
});
}
}

1 comment on commit d653a31

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.