# HG changeset patch # User kshefov # Date 1383642580 -14400 # Node ID bda654c6d59ced41ad68c42e3f132afb29ab1f8c # Parent b0d4ef6fb2db3acc1dece6feb7faac2a4c6be6d5 8027708: NASHORN TEST: Create Nashorn test that draws image step-by-step using JavaFX canvas. Reviewed-by: jlaskey, lagergren diff -r b0d4ef6fb2db -r bda654c6d59c make/build.xml --- a/make/build.xml Tue Nov 05 09:13:41 2013 +0530 +++ b/make/build.xml Tue Nov 05 13:09:40 2013 +0400 @@ -372,6 +372,12 @@ + + + + + + @@ -380,6 +386,7 @@ + diff -r b0d4ef6fb2db -r bda654c6d59c make/project.properties --- a/make/project.properties Tue Nov 05 09:13:41 2013 +0530 +++ b/make/project.properties Tue Nov 05 13:09:40 2013 +0400 @@ -230,7 +230,7 @@ ${file.reference.jemmyawtinput.jar}${path.separator}\ ${file.reference.testng.jar}${path.separator}\ ${nashorn.internal.tests.jar}${path.separator}\ - ${nashorn.api.tests.jar} + ${nashorn.api.tests.jar} # testjfx VM options for script tests with @fork option testjfx-test-sys-prop.test.fork.jvm.options=${run.test.jvmargs.main} -Xmx${run.test.xmx} -cp ${testjfx.run.test.classpath} diff -r b0d4ef6fb2db -r bda654c6d59c test/script/jfx.js --- a/test/script/jfx.js Tue Nov 05 09:13:41 2013 +0530 +++ b/test/script/jfx.js Tue Nov 05 13:09:40 2013 +0400 @@ -37,13 +37,24 @@ var Scene = Java.type("javafx.scene.Scene"); var Stage = Java.type("javafx.stage.Stage"); var File = Java.type("java.io.File"); -var Timer = Java.type("java.util.Timer"); -var TimerTask = Java.type("java.util.TimerTask"); var OSInfo = Java.type("sun.awt.OSInfo"); var OSType = Java.type("sun.awt.OSInfo.OSType"); var StringBuffer = Java.type("java.lang.StringBuffer"); +var Paint = Java.type("javafx.scene.paint.Paint"); +var Color = Java.type("javafx.scene.paint.Color"); +var Image = Java.type("javafx.scene.image.Image"); +var Canvas = Java.type("javafx.scene.canvas.Canvas"); +var BorderPane = Java.type("javafx.scene.layout.BorderPane"); +var StackPane = Java.type("javafx.scene.layout.StackPane"); +var StrokeLineCap = Java.type("javafx.scene.shape.StrokeLineCap"); +var Platform = Java.type("javafx.application.Platform"); +var Runnable = Java.type("java.lang.Runnable"); +var RunnableExtend = Java.extend(Runnable); +var AnimationTimer = Java.type("javafx.animation.AnimationTimer"); +var AnimationTimerExtend = Java.extend(AnimationTimer); +var Timer = Java.type("java.util.Timer"); +var TimerTask = Java.type("java.util.TimerTask"); -var WAIT = 2000; var TESTNAME = "test"; var fsep = System.getProperty("file.separator"); @@ -53,14 +64,16 @@ run: function run() { var tmpdir = System.getProperty("java.io.tmpdir"); var timenow = (new Date()).getTime(); - makeScreenShot(tmpdir + fsep + "screenshot" + timenow +".png"); - var dupImg = isDuplicateImages(tmpdir + fsep + "screenshot" + timenow +".png", __DIR__ + "jfx" + fsep + TESTNAME + fsep + "golden"); - (new File(mpdir + fsep + "screenshot" + timenow +".png")).delete(); - if (!dupImg) System.err.println("ERROR: screenshot does not match golden image"); + var scrShotTmp = tmpdir + fsep + "screenshot" + timenow +".png"; + var goldenImageDir = __DIR__ + "jfx" + fsep + TESTNAME + fsep + "golden"; + makeScreenShot(scrShotTmp); + var dupImg = isDuplicateImages(scrShotTmp, goldenImageDir); + (new File(scrShotTmp)).delete(); + if (!dupImg) System.err.println("ERROR: screenshot does not match the golden image"); exit(0); } }; - raceTimer.schedule(timerTask, WAIT); + raceTimer.schedule(timerTask, 100); } function makeScreenShot(shootToImg) { @@ -70,10 +83,10 @@ imageJemmy.save(shootToImg); } -function isDuplicateImages(file1, file2) { - var f1 = new File(file1); +function isDuplicateImages(screenShot, goldenDir) { + var f1 = new File(screenShot); var f2; - var sb = new StringBuffer(file2); + var sb = new StringBuffer(goldenDir); if (OSInfo.getOSType() == OSType.WINDOWS) { f2 = new File(sb.append(fsep + "windows.png").toString()); } else if (OSInfo.getOSType() == OSType.LINUX) { @@ -81,8 +94,6 @@ } else if (OSInfo.getOSType() == OSType.MACOSX) { f2 = new File(sb.append(fsep + "macosx.png").toString()); } - print(f1.getAbsolutePath()); - print(f2.getAbsolutePath()); if (f1.exists() && f2.exists()) { var image1 = new AWTImage(PNGDecoder.decode(f1.getAbsolutePath())); var image2 = new AWTImage(PNGDecoder.decode(f2.getAbsolutePath())); diff -r b0d4ef6fb2db -r bda654c6d59c test/script/jfx/flyingimage.js --- a/test/script/jfx/flyingimage.js Tue Nov 05 09:13:41 2013 +0530 +++ b/test/script/jfx/flyingimage.js Tue Nov 05 13:09:40 2013 +0400 @@ -31,15 +31,6 @@ TESTNAME = "flyingimage"; -var Image = Java.type("javafx.scene.image.Image"); -var Color = Java.type("javafx.scene.paint.Color"); -var Canvas = Java.type("javafx.scene.canvas.Canvas"); -var BorderPane = Java.type("javafx.scene.layout.BorderPane"); -var StackPane = Java.type("javafx.scene.layout.StackPane"); -var Font = Java.type("javafx.scene.text.Font"); -var FontSmoothingType = Java.type("javafx.scene.text.FontSmoothingType"); -var Text = Java.type("javafx.scene.text.Text"); - var WIDTH = 800; var HEIGHT = 600; var canvas = new Canvas(WIDTH, HEIGHT); @@ -48,10 +39,9 @@ } var imageUrl = fileToURL(__DIR__ + "flyingimage/flyingimage.png"); var img = new Image(imageUrl); -var font = new Font("Arial", 16); -var t = 0; var isFrameRendered = false; function renderFrame() { + var t = frame; var gc = canvas.graphicsContext2D; gc.setFill(Color.web("#cccccc")); gc.fillRect(0, 0, WIDTH, HEIGHT); @@ -61,7 +51,7 @@ var c = 200; var msc= 0.5 * HEIGHT / img.height; var sp0 = 0.003; - for (var h = 0; h < c; h++, t++) { + for (var h = 0; h < c; h++) { gc.setTransform(1, 0, 0, 1, 0, 0); var yh = h / (c - 1); gc.translate((0.5 + Math.sin(t * sp0 + h * 0.1) / 3) * WIDTH, 25 + (HEIGHT * 3 / 4 - 40) * (yh * yh)); @@ -69,15 +59,26 @@ gc.rotate(90 * Math.sin(t * sp0 + h * 0.1 + Math.PI)); gc.scale(sc, sc); gc.drawImage(img, -img.width / 2, -img.height / 2); - } + } gc.setTransform(1, 0, 0, 1, 0, 0); isFrameRendered = true; } var stack = new StackPane(); var pane = new BorderPane(); - pane.setCenter(canvas); stack.getChildren().add(pane); $STAGE.scene = new Scene(stack); -renderFrame(); -checkImageAndExit(); +var frame = 0; +var timer = new AnimationTimerExtend() { + handle: function handle(now) { + if (frame < 200) { + renderFrame(); + frame++; + } else { + checkImageAndExit(); + timer.stop(); + } + } +}; +timer.start(); + diff -r b0d4ef6fb2db -r bda654c6d59c test/script/jfx/flyingimage/flyingimage.png Binary file test/script/jfx/flyingimage/flyingimage.png has changed diff -r b0d4ef6fb2db -r bda654c6d59c test/script/jfx/flyingimage/golden/linux.png Binary file test/script/jfx/flyingimage/golden/linux.png has changed diff -r b0d4ef6fb2db -r bda654c6d59c test/script/jfx/flyingimage/golden/macosx.png Binary file test/script/jfx/flyingimage/golden/macosx.png has changed diff -r b0d4ef6fb2db -r bda654c6d59c test/script/jfx/flyingimage/golden/windows.png Binary file test/script/jfx/flyingimage/golden/windows.png has changed diff -r b0d4ef6fb2db -r bda654c6d59c test/script/jfx/kaleidoscope.js --- a/test/script/jfx/kaleidoscope.js Tue Nov 05 09:13:41 2013 +0530 +++ b/test/script/jfx/kaleidoscope.js Tue Nov 05 13:09:40 2013 +0400 @@ -30,13 +30,6 @@ */ TESTNAME = "kaleidoscope"; -WAIT = 4000; - -var Paint = Java.type("javafx.scene.paint.Paint"); -var Canvas = Java.type("javafx.scene.canvas.Canvas"); -var BorderPane = Java.type("javafx.scene.layout.BorderPane"); -var StackPane = Java.type("javafx.scene.layout.StackPane"); -var StrokeLineCap = Java.type("javafx.scene.shape.StrokeLineCap"); var WIDTH = 800; var HEIGHT = 600; @@ -56,26 +49,28 @@ var r,e; var fade; var prv_x,prv_y,prv_x2,prv_y2; +var isFrameRendered = false; function renderFrame() { - a=0.2*angle; - b=0.7*angle; - r=0; - fade=32; - for(var i=0;i<6;i++) - { - c[i]=1.0/(i+1)/2; - d[i]=1.0/(i+1)/2; - } - radius=Math.round((WIDTH+HEIGHT)/8); - e=radius*0.2; - p_x=Math.round(WIDTH/2); - p_y=Math.round(HEIGHT/2); - x=(radius*c[0])*Math.cos(a*d[1])+(radius*c[2])*Math.sin(a*d[3])+(radius*c[4])*Math.sin(a*d[5]); - y=(radius*c[5])*Math.sin(a*d[4])+(radius*c[3])*Math.cos(a*d[2])+(radius*c[1])*Math.cos(a*d[0]); - for (i = 0; i < 800; i++) { - anim(); + if (!isFrameRendered) { + a=0.2*angle; + b=0.7*angle; + r=0; + fade=32; + for(var i=0;i<6;i++) + { + c[i]=1.0/(i+1)/2; + d[i]=1.0/(i+1)/2; + } + radius=Math.round((WIDTH+HEIGHT)/8); + e=radius*0.2; + p_x=Math.round(WIDTH/2); + p_y=Math.round(HEIGHT/2); + x=(radius*c[0])*Math.cos(a*d[1])+(radius*c[2])*Math.sin(a*d[3])+(radius*c[4])*Math.sin(a*d[5]); + y=(radius*c[5])*Math.sin(a*d[4])+(radius*c[3])*Math.cos(a*d[2])+(radius*c[1])*Math.cos(a*d[0]); + isFrameRendered = true; } + anim(); } function anim() { @@ -154,9 +149,19 @@ var stack = new StackPane(); var pane = new BorderPane(); - pane.setCenter(canvas); stack.getChildren().add(pane); $STAGE.scene = new Scene(stack); -renderFrame(); -checkImageAndExit(); \ No newline at end of file +var frame = 0; +var timer = new AnimationTimerExtend() { + handle: function handle(now) { + if (frame < 800) { + renderFrame(); + frame++; + } else { + checkImageAndExit(); + timer.stop(); + } + } +}; +timer.start(); diff -r b0d4ef6fb2db -r bda654c6d59c test/script/jfx/kaleidoscope/golden/linux.png Binary file test/script/jfx/kaleidoscope/golden/linux.png has changed diff -r b0d4ef6fb2db -r bda654c6d59c test/script/jfx/kaleidoscope/golden/macosx.png Binary file test/script/jfx/kaleidoscope/golden/macosx.png has changed diff -r b0d4ef6fb2db -r bda654c6d59c test/script/jfx/kaleidoscope/golden/windows.png Binary file test/script/jfx/kaleidoscope/golden/windows.png has changed diff -r b0d4ef6fb2db -r bda654c6d59c test/script/jfx/spread.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/script/jfx/spread.js Tue Nov 05 13:09:40 2013 +0400 @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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. + */ + +/** + * Testing JavaFX canvas run by Nashorn. + * + * @test/nocompare + * @run + * @fork + */ + +TESTNAME = "spread"; + +var WIDTH = 800; +var HEIGHT = 600; +var canvas = new Canvas(WIDTH, HEIGHT); +var context = canvas.graphicsContext2D; + +/* "Spread" tech demo of canvas by Tom Theisen + * + * This will animate a sequence of branch structures in a canvas element. + * Each frame, a new direction is calculated, similar to the last frame. + */ + +var start_width = 20; // starting width of each branch +var frame_time = 30; // milliseconds per frame +var straighten_factor = 0.95; // value from 0 to 1, factor applied to direction_offset every frame +var curviness = 0.2; // amount of random direction change each frame + +var color_speed = 0.03; // speed at which colors change when cycling is enabled +var branch_shrink = 0.95; // factor by which branches shrink every frame +var min_width = 1; // minimum WIDTH for branch, after which they are discontinued +var branch_opacity = 0.4; // opacity of lines drawn +var branch_count = 3; // branch count per tree +var branch_bud_size = 0.5; // ratio of original branch size at which branch will split +var branch_bud_angle = 1; // angle offset for split branch; + +var paper; // reference to graphics context +var branches = Object(); // linked list of active branches +var color_styles = []; // pre-computed list of colors as styles. format: (r,g,b,a) +var direction_offset = 0; // current direction offset in radians. this is applied to all branches. +var frame = 0; // frame counter +var timespent = 0; // total time spent so far, used to calculate average frame render duration +var frameratespan; // html span element for updating performance number + +// preferences object, contains an attribute for each user setting +var prefs = { + wrap: true, // causes branches reaching edge of viewable area to appear on opposite side + fade: false, // fade existing graphics on each frame + cycle: true, // gradually change colors each frame + new_branch_frames: 20 // number of frames elapsed between each auto-generated tree +}; + +// create tree at the specified position with number of branches +function create_tree(branches, start_width, position, branch_count) { + var angle_offset = Math.PI * 2 / branch_count; + for (var i = 0; i < branch_count; ++i) { + branch_add(branches, new Branch(position, angle_offset * i, start_width)); + } +} + +// add branch to collection +function branch_add(branches, branch) { + branch.next = branches.next; + branches.next = branch; +} + +// get the coordinates for the position of a new tree +// use the center of the canvas +function get_new_tree_center(width, height) { + return { + x: 0.5 * width, + y: 0.5 * height + }; +} + +// Branch constructor +// position has x and y properties +// direction is in radians +function Branch(position, direction, width) { + this.x = position.x; + this.y = position.y; + this.width = width; + this.original_width = width; + this.direction = direction; +} + +// update position, direction and width of a particular branch +function branch_update(branches, branch, paper) { + paper.beginPath(); + paper.lineWidth = branch.width; + paper.moveTo(branch.x, branch.y); + + branch.width *= branch_shrink; + branch.direction += direction_offset; + branch.x += Math.cos(branch.direction) * branch.width; + branch.y += Math.sin(branch.direction) * branch.width; + + paper.lineTo(branch.x, branch.y); + paper.stroke(); + + if (prefs.wrap) wrap_branch(branch, WIDTH, HEIGHT); + + if (branch.width < branch.original_width * branch_bud_size) { + branch.original_width *= branch_bud_size; + branch_add(branches, new Branch(branch, branch.direction + 1, branch.original_width)); + } +} + +function draw_frame() { + if (prefs.fade) { + paper.fillRect(0, 0, WIDTH, HEIGHT); + } + + if (prefs.cycle) { + paper.setStroke(Paint.valueOf(color_styles[frame % color_styles.length])); + } + + if (frame++ % prefs.new_branch_frames == 0) { + create_tree(branches, start_width, get_new_tree_center(WIDTH, HEIGHT), branch_count); + } + + direction_offset += (0.35 + (frame % 200) * 0.0015) * curviness - curviness / 2; + direction_offset *= straighten_factor; + + var branch = branches; + var prev_branch = branches; + while (branch = branch.next) { + branch_update(branches, branch, paper); + + if (branch.width < min_width) { + // remove branch from list + prev_branch.next = branch.next; + } + + prev_branch = branch; + } +} + +// constrain branch position to visible area by "wrapping" from edge to edge +function wrap_branch(branch, WIDTH, HEIGHT) { + branch.x = positive_mod(branch.x, WIDTH); + branch.y = positive_mod(branch.y, HEIGHT); +} + +// for a < 0, b > 0, javascript returns a negative number for a % b +// this is a variant of the % operator that adds b to the result in this case +function positive_mod(a, b) { + // ECMA 262 11.5.3: Applying the % Operator + // remainder operator does not convert operands to integers, + // although negative results are possible + + return ((a % b) + b) % b; +} + +// pre-compute color styles that will be used for color cycling +function populate_colors(color_speed, color_styles, branch_opacity) { + // used in calculation of RGB values + var two_thirds_pi = Math.PI * 2 / 3; + var four_thirds_pi = Math.PI * 4 / 3; + var two_pi = Math.PI * 2; + + // hue does represent hue, but not in the conventional HSL scheme + for(var hue = 0; hue < two_pi; hue += color_speed) { + var r = Math.floor(Math.sin(hue) * 128 + 128); + var g = Math.floor(Math.sin(hue + two_thirds_pi) * 128 + 128); + var b = Math.floor(Math.sin(hue + four_thirds_pi) * 128 + 128); + color = "rgba(" + [r, g, b, branch_opacity].join() + ")"; + + color_styles.push(color); + } +} + +// apply initial settings to canvas object +function setup_canvas() { + paper = canvas.graphicsContext2D; + paper.setFill(Paint.valueOf('rgb(0, 0, 0)')); + paper.fillRect(0, 0, WIDTH, HEIGHT); + paper.setFill(Paint.valueOf("rgba(0, 0, 0, 0.005)")); + paper.setStroke(Paint.valueOf("rgba(128, 128, 64, " + String(branch_opacity) + ")")); +} + +populate_colors(color_speed, color_styles, branch_opacity); +setup_canvas(); + +var stack = new StackPane(); +var pane = new BorderPane(); +pane.setCenter(canvas); +stack.getChildren().add(pane); +$STAGE.scene = new Scene(stack); +var timer = new AnimationTimerExtend() { + handle: function handle(now) { + if (frame < 200) { + draw_frame(); + } else { + checkImageAndExit(); + timer.stop(); + } + } +}; +timer.start(); + diff -r b0d4ef6fb2db -r bda654c6d59c test/script/jfx/spread/golden/linux.png Binary file test/script/jfx/spread/golden/linux.png has changed diff -r b0d4ef6fb2db -r bda654c6d59c test/script/jfx/spread/golden/macosx.png Binary file test/script/jfx/spread/golden/macosx.png has changed diff -r b0d4ef6fb2db -r bda654c6d59c test/script/jfx/spread/golden/windows.png Binary file test/script/jfx/spread/golden/windows.png has changed