changeset 4835:b92a762b41da

Automated merge with ssh://jfxsrc.us.oracle.com//javafx/8.0/MASTER/jfx/rt
author jgodinez
date Tue, 27 Aug 2013 09:36:40 -0700
parents 4612c8fd2a83 8587043be240
children 903908477a58
files modules/graphics/src/test/java/com/sun/javafx/sg/prism/NodeTestUtils.java modules/graphics/src/test/java/com/sun/javafx/sg/prism/TestNGNode.java modules/web/src/main/java/com/sun/webkit/network/about/AboutURLConnection.java modules/web/src/main/java/com/sun/webkit/network/about/Handler.java tools/gltrace/opengl.h tools/gltrace/trace.c
diffstat 184 files changed, 10850 insertions(+), 5000 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.idea/GraphicsPerformance.iml	Tue Aug 27 09:36:40 2013 -0700
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$/apps/performance/GraphicsPerformance">
+      <sourceFolder url="file://$MODULE_DIR$/apps/performance/GraphicsPerformance/src/main/java" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/apps/performance/GraphicsPerformance/src/main/resources" isTestSource="false" />
+    </content>
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="module" module-name="base" />
+    <orderEntry type="module" module-name="controls" />
+    <orderEntry type="module" module-name="fxml" />
+    <orderEntry type="module" module-name="fxpackager" />
+    <orderEntry type="module" module-name="graphics" />
+    <orderEntry type="module" module-name="rt" />
+    <orderEntry type="inheritedJdk" />
+  </component>
+</module>
+
--- a/.idea/modules.xml	Tue Aug 27 09:59:24 2013 -0400
+++ b/.idea/modules.xml	Tue Aug 27 09:36:40 2013 -0700
@@ -4,6 +4,7 @@
     <modules>
       <module fileurl="file://$PROJECT_DIR$/.idea/3DViewer.iml" filepath="$PROJECT_DIR$/.idea/3DViewer.iml" />
       <module fileurl="file://$PROJECT_DIR$/.idea/Ensemble8.iml" filepath="$PROJECT_DIR$/.idea/Ensemble8.iml" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/GraphicsPerformance.iml" filepath="$PROJECT_DIR$/.idea/GraphicsPerformance.iml" />
       <module fileurl="file://$PROJECT_DIR$/.idea/Hello.iml" filepath="$PROJECT_DIR$/.idea/Hello.iml" />
       <module fileurl="file://$PROJECT_DIR$/.idea/Modena.iml" filepath="$PROJECT_DIR$/.idea/Modena.iml" />
       <module fileurl="file://$PROJECT_DIR$/.idea/RegionTests.iml" filepath="$PROJECT_DIR$/.idea/RegionTests.iml" />
--- a/.idea/vcs.xml	Tue Aug 27 09:59:24 2013 -0400
+++ b/.idea/vcs.xml	Tue Aug 27 09:36:40 2013 -0700
@@ -2,8 +2,8 @@
 <project version="4">
   <component name="VcsDirectoryMappings">
     <mapping directory="" vcs="" />
+    <mapping directory="$PROJECT_DIR$/../../deploy" vcs="hg4idea" />
     <mapping directory="$PROJECT_DIR$" vcs="hg4idea" />
-    <mapping directory="$PROJECT_DIR$/../../deploy" vcs="hg4idea" />
     <mapping directory="$PROJECT_DIR$/../../rt-closed" vcs="hg4idea" />
   </component>
 </project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/performance/GraphicsPerformance/build.gradle	Tue Aug 27 09:36:40 2013 -0700
@@ -0,0 +1,1 @@
+apply plugin: "java"
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/performance/GraphicsPerformance/src/main/java/nodecount/BenchBase.java	Tue Aug 27 09:36:40 2013 -0700
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates.
+ * All rights reserved. Use is subject to license terms.
+ *
+ * This file is available and licensed under the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the distribution.
+ *  - Neither the name of Oracle Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package nodecount;
+
+import javafx.animation.Animation;
+import javafx.animation.AnimationTimer;
+import javafx.application.Application;
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
+import javafx.scene.Group;
+import javafx.scene.Node;
+import javafx.scene.Scene;
+import javafx.stage.Stage;
+import com.sun.javafx.perf.PerformanceTracker;
+
+/**
+ */
+public abstract class BenchBase<T extends Node> extends Application {
+    protected Animation driver;
+    private BenchTest currentTest;
+
+    @Override
+    public void start(Stage stage) throws Exception {
+
+        Scene scene = new Scene(new Group(), 640, 480);
+        stage.setScene(scene);
+        stage.show();
+
+        final PerformanceTracker tracker = PerformanceTracker.getSceneTracker(scene);
+        AnimationTimer fpsTimer = new AnimationTimer() {
+            long lastReset;
+            @Override
+            public void handle(long now) {
+                if (now - lastReset > 5000 * 1000000) {
+                    float fps = tracker.getAverageFPS();
+                    if (currentTest != null) {
+                        currentTest.maxFPS = Math.max(currentTest.maxFPS, fps);
+                    }
+                    tracker.resetAverageFPS();
+                    lastReset = now;
+                }
+            }
+        };
+        fpsTimer.start();
+
+        BenchTest[] tests = createTests();
+        runTest(scene, tests, 0);
+    }
+
+    protected BenchTest[] createTests() {
+        int[][] sizes = new int[][] {
+                {8, 8},
+                {10, 10},
+                {14, 14},
+                {20, 20},
+                {40, 40},
+                {60, 60},
+        };
+        BenchTest[] tests = new BenchTest[3 * 6];
+        int sizeIndex = 0;
+        for (int i=0; i<tests.length; i+=3) {
+            int rows = sizes[sizeIndex][0];
+            int cols = sizes[sizeIndex][1];
+            tests[i] = new SimpleGrid(this, rows, cols);
+            tests[i+1] = new PixelGrid(this, rows, cols);
+            tests[i+2] = new RotatingGrid(this, rows, cols);
+            sizeIndex++;
+        }
+        return tests;
+    }
+
+    protected void printResults(BenchTest[] tests) {
+        for (int i=0; i<tests.length; i+=3) {
+            // There are 3 types of tests involved, all at different pixel sizes
+            int nodeCount = tests[i].getNodeCount();
+            assert nodeCount == tests[i+1].getNodeCount() && nodeCount == tests[i+2].getNodeCount();
+            System.out.print(nodeCount + "\t");
+            System.out.print(tests[i].getMaxFPS() + "\t");
+            System.out.print(tests[i+1].getMaxFPS() + "\t");
+            System.out.println(tests[i+2].getMaxFPS() + "\t");
+        }
+    }
+
+    protected abstract void resizeAndRelocate(T node, double x, double y, double width, double height);
+
+    protected abstract T createNode();
+
+    private void runTest(Scene scene, BenchTest[] tests, int index) {
+        if (index >= tests.length) {
+            printResults(tests);
+            return; // we're done.
+        }
+
+        if (currentTest != null) {
+            currentTest.tearDown();
+        }
+
+        currentTest = tests[index];
+        tests[index].setup(scene);
+        driver = tests[index].createBenchmarkDriver(scene);
+        driver.play();
+        driver.setOnFinished(new EventHandler<ActionEvent>() {
+            @Override
+            public void handle(ActionEvent event) {
+                runTest(scene, tests, index+1);
+            }
+        });
+    }
+
+    /**
+     * Java main for when running without JavaFX launcher
+     */
+    public static void main(String[] args) {
+        launch(args);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/performance/GraphicsPerformance/src/main/java/nodecount/BenchTest.java	Tue Aug 27 09:36:40 2013 -0700
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates.
+ * All rights reserved. Use is subject to license terms.
+ *
+ * This file is available and licensed under the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the distribution.
+ *  - Neither the name of Oracle Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package nodecount;
+
+import javafx.animation.Animation;
+import javafx.animation.FillTransition;
+import javafx.scene.Node;
+import javafx.scene.Scene;
+import javafx.scene.layout.Pane;
+import javafx.scene.paint.Color;
+import javafx.scene.shape.Rectangle;
+import javafx.util.Duration;
+
+/**
+ */
+public abstract class BenchTest {
+    public static final int GAP = 6;
+
+    double maxFPS;
+    private final BenchBase benchmark;
+    private final int rows, cols;
+    private final boolean pixelSnap;
+    
+    public BenchTest(BenchBase benchmark, int rows, int cols, boolean pixelSnap) {
+        this.benchmark = benchmark;
+        this.rows = rows;
+        this.cols = cols;
+        this.pixelSnap = pixelSnap;
+    }
+
+    public double getMaxFPS() { return maxFPS; }
+
+    public int getNodeCount() {
+        return rows * cols;
+    }
+
+    public int getCols() { return cols; }
+    public int getRows() { return rows; }
+    
+    protected Animation createBenchmarkDriver(Scene scene) {
+        Rectangle background = (Rectangle) scene.getRoot().getChildrenUnmodifiable().get(0);
+        FillTransition t = new FillTransition(Duration.seconds(5), background, Color.WHITE, Color.BLACK);
+        t.setAutoReverse(true);
+        t.setCycleCount(2);
+        return t;
+    }
+
+    public void setup(Scene scene) {
+        final Rectangle background = new Rectangle();
+        final Node[][] nodes = new Node[rows][cols];
+        final Pane root = new Pane() {
+            @Override protected void layoutChildren() {
+                background.setWidth(getWidth());
+                background.setHeight(getHeight());
+                double rectWidth = (getWidth() - ((cols-1) * GAP)) / cols;
+                double rectHeight = (getHeight() - ((rows-1) * GAP)) / rows;
+                for (int r=0; r<rows; r++) {
+                    for (int c=0; c<cols; c++) {
+                        double x = c * (GAP + rectWidth);
+                        double y = r * (GAP + rectHeight);
+                        Node n = nodes[r][c];
+                        benchmark.resizeAndRelocate(n,
+                                pixelSnap ? (int) x : x,
+                                pixelSnap ? (int) y : y,
+                                pixelSnap ? (int) rectWidth : rectWidth,
+                                pixelSnap ? (int) rectHeight : rectHeight);
+                    }
+                }
+            }
+        };
+        root.getChildren().add(background);
+
+        for (int r=0; r<rows; r++) {
+            for (int c=0; c<cols; c++) {
+                Node node = benchmark.createNode();
+                nodes[r][c] = node;
+                root.getChildren().add(node);
+            }
+        }
+
+        scene.setRoot(root);
+    }
+
+    public void tearDown() { }
+
+    @Override public String toString() {
+        return getClass().getSimpleName() + " " + rows + "x" + cols + ": " + maxFPS;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/performance/GraphicsPerformance/src/main/java/nodecount/ButtonBench.java	Tue Aug 27 09:36:40 2013 -0700
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates.
+ * All rights reserved. Use is subject to license terms.
+ *
+ * This file is available and licensed under the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the distribution.
+ *  - Neither the name of Oracle Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package nodecount;
+
+import javafx.scene.control.Button;
+
+/**
+ */
+public class ButtonBench extends BenchBase<Button> {
+
+    @Override
+    protected void resizeAndRelocate(Button button, double x, double y, double width, double height) {
+        button.resizeRelocate(x, y, width, height);
+    }
+
+    @Override
+    protected Button createNode() {
+        return new Button();
+    }
+
+    /**
+     * Java main for when running without JavaFX launcher
+     */
+    public static void main(String[] args) {
+        launch(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/performance/GraphicsPerformance/src/main/java/nodecount/FlatButtonBench.java	Tue Aug 27 09:36:40 2013 -0700
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates.
+ * All rights reserved. Use is subject to license terms.
+ *
+ * This file is available and licensed under the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the distribution.
+ *  - Neither the name of Oracle Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package nodecount;
+
+import javafx.scene.control.Button;
+
+/**
+ * Buttons rendered with a flat fill
+ */
+public class FlatButtonBench extends ButtonBench {
+/*
+    -fx-background-color: -fx-shadow-highlight-color, -fx-outer-border, -fx-inner-border, -fx-body-color;
+    -fx-background-insets: 0 0 -1 0, 0, 1, 2;
+    -fx-background-radius: 3px, 3px, 2px, 1px;
+    -fx-padding: 0.333333em 0.666667em 0.333333em 0.666667em;
+    -fx-text-fill: -fx-text-base-color;
+    -fx-alignment: CENTER;
+    -fx-content-display: LEFT;
+
+ */
+
+
+    @Override
+    protected Button createNode() {
+        Button button = super.createNode();
+        button.setStyle(
+                "-fx-background-color: BLACK, DARKGRAY, LIGHTGRAY, CORNFLOWERBLUE;" +
+                "-fx-background-insets: 0 0 -1 0, 0, 1, 2;" +
+                "-fx-background-radius: 3px, 3px, 2px, 1px;" +
+                "-fx-padding: 0.33333em 0.666667em 0.333333em 0.6666667em;" +
+                "-fx-text-fill: white;" +
+                "-fx-alignment: CENTER;" +
+                "-fx-content-display: LEFT;");
+        return button;
+    }
+
+    /**
+     * Java main for when running without JavaFX launcher
+     */
+    public static void main(String[] args) {
+        launch(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/performance/GraphicsPerformance/src/main/java/nodecount/ImageBench.java	Tue Aug 27 09:36:40 2013 -0700
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates.
+ * All rights reserved. Use is subject to license terms.
+ *
+ * This file is available and licensed under the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the distribution.
+ *  - Neither the name of Oracle Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package nodecount;
+
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+
+/**
+ */
+public class ImageBench extends BenchBase<ImageView> {
+    Image image = new Image(ImageBench.class.getResource("Duke_Wave_Opaque.png").toExternalForm());
+
+    @Override protected void resizeAndRelocate(ImageView i, double x, double y, double width, double height) {
+        i.setX(x);
+        i.setY(y);
+        i.setFitWidth(width);
+        i.setFitHeight(height);
+    }
+
+    @Override protected ImageView createNode() {
+        ImageView i = new ImageView();
+        i.setImage(image);
+        return i;
+    }
+
+    /**
+     * Java main for when running without JavaFX launcher
+     */
+    public static void main(String[] args) {
+        launch(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/performance/GraphicsPerformance/src/main/java/nodecount/PixelGrid.java	Tue Aug 27 09:36:40 2013 -0700
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates.
+ * All rights reserved. Use is subject to license terms.
+ *
+ * This file is available and licensed under the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the distribution.
+ *  - Neither the name of Oracle Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package nodecount;
+
+/**
+ */
+public class PixelGrid extends BenchTest {
+    public PixelGrid(BenchBase benchmark, int rows, int cols) {
+        super(benchmark, rows, cols, true);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/performance/GraphicsPerformance/src/main/java/nodecount/RectBench.java	Tue Aug 27 09:36:40 2013 -0700
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates.
+ * All rights reserved. Use is subject to license terms.
+ *
+ * This file is available and licensed under the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the distribution.
+ *  - Neither the name of Oracle Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package nodecount;
+
+import javafx.scene.paint.Color;
+import javafx.scene.shape.Rectangle;
+
+/**
+ */
+public class RectBench extends BenchBase<Rectangle> {
+
+    @Override protected void resizeAndRelocate(Rectangle rect, double x, double y, double width, double height) {
+        rect.setX(x);
+        rect.setY(y);
+        rect.setWidth(width);
+        rect.setHeight(height);
+    }
+
+    @Override protected Rectangle createNode() {
+        Rectangle rect = new Rectangle();
+        rect.setFill(new Color(Math.random(), Math.random(), Math.random(), 1));
+        return rect;
+    }
+
+    /**
+     * Java main for when running without JavaFX launcher
+     */
+    public static void main(String[] args) {
+        launch(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/performance/GraphicsPerformance/src/main/java/nodecount/RotatingGrid.java	Tue Aug 27 09:36:40 2013 -0700
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates.
+ * All rights reserved. Use is subject to license terms.
+ *
+ * This file is available and licensed under the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the distribution.
+ *  - Neither the name of Oracle Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package nodecount;
+
+import javafx.animation.ParallelTransition;
+import javafx.animation.RotateTransition;
+import javafx.scene.Node;
+import javafx.scene.Scene;
+import javafx.util.Duration;
+import java.util.List;
+
+/**
+ */
+public class RotatingGrid extends BenchTest {
+    private ParallelTransition tx;
+
+    public RotatingGrid(BenchBase benchmark, int rows, int cols) {
+        super(benchmark, rows, cols, false);
+    }
+
+    @Override public void setup(Scene scene) {
+        super.setup(scene);
+        List<Node> children = scene.getRoot().getChildrenUnmodifiable();
+        tx = new ParallelTransition();
+        for (int i=1; i<children.size(); i++) {
+            Node n = children.get(i);
+            RotateTransition rot = new RotateTransition(Duration.seconds(5), n);
+            rot.setToAngle(360);
+            tx.getChildren().add(rot);
+        }
+        tx.setCycleCount(ParallelTransition.INDEFINITE);
+        tx.play();
+    }
+
+    @Override public void tearDown() {
+        tx.stop();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/performance/GraphicsPerformance/src/main/java/nodecount/SimpleGrid.java	Tue Aug 27 09:36:40 2013 -0700
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates.
+ * All rights reserved. Use is subject to license terms.
+ *
+ * This file is available and licensed under the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the distribution.
+ *  - Neither the name of Oracle Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package nodecount;
+
+/**
+ */
+public class SimpleGrid extends BenchTest {
+    public SimpleGrid(BenchBase benchmark, int rows, int cols) {
+        super(benchmark, rows, cols, false);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/performance/GraphicsPerformance/src/main/java/preloader/PreloaderApp.java	Tue Aug 27 09:36:40 2013 -0700
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates.
+ * All rights reserved. Use is subject to license terms.
+ *
+ * This file is available and licensed under the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the distribution.
+ *  - Neither the name of Oracle Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package preloader;
+
+import javafx.application.Preloader;
+import javafx.geometry.Pos;
+import javafx.scene.Scene;
+import javafx.scene.control.Label;
+import javafx.scene.control.ProgressBar;
+import javafx.scene.layout.VBox;
+import javafx.scene.paint.Color;
+import javafx.stage.Stage;
+
+/**
+ *
+ */
+public class PreloaderApp extends Preloader {
+    private ProgressBar progressBar;
+    private Label label;
+    private Stage stage;
+    private VBox root;
+
+    @Override
+    public void init() throws Exception {
+        System.out.println("Preloader init: " + Thread.currentThread());
+        progressBar = new ProgressBar();
+        label = new Label();
+
+        root = new VBox(progressBar, label);
+        root.setAlignment(Pos.CENTER);
+        root.setSpacing(7);
+        root.setBackground(null);
+    }
+
+    @Override
+    public void start(Stage stage) throws Exception {
+        Scene scene = new Scene(root, Color.BLACK);
+        stage.setScene(scene);
+        stage.show();
+        this.stage = stage;
+        System.out.println("Preloader start: " + Thread.currentThread());
+    }
+
+    /**
+     * Indicates progress.
+     *
+     * <p>
+     * The implementation of this method provided by the Preloader class
+     * does nothing.
+     * </p>
+     *
+     * @param info the progress notification
+     */
+    public void handleProgressNotification(ProgressNotification info) {
+//        progressBar.setProgress(info.getProgress());
+    }
+
+    /**
+     * Indicates a change in application state.
+     *
+     * <p>
+     * The implementation of this method provided by the Preloader class
+     * does nothing.
+     * </p>
+     *
+     * @param info the state change notification
+     */
+    public void handleStateChangeNotification(StateChangeNotification info) {
+        switch(info.getType()) {
+            case BEFORE_INIT:
+                break;
+            case BEFORE_LOAD:
+                break;
+            case BEFORE_START:
+                ((SlowStartingApp)info.getApplication()).preloaderApp = stage;
+                break;
+        }
+    }
+
+    /**
+     * Indicates an application-generated notification.
+     * Application should not call this method directly, but should use
+     * notifyCurrentPreloader() instead to avoid mixed code dialog issues.
+     *
+     * <p>
+     * The implementation of this method provided by the Preloader class
+     * does nothing.
+     * </p>
+     *
+     * @param info the application-generated notification
+     */
+    public void handleApplicationNotification(PreloaderNotification info) {
+        label.setText(info.toString());
+    }
+
+    /**
+     * Java main for when running without JavaFX launcher
+     */
+    public static void main(String[] args) {
+        launch(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/performance/GraphicsPerformance/src/main/java/preloader/SlowStartingApp.java	Tue Aug 27 09:36:40 2013 -0700
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2008, 2013 Oracle and/or its affiliates.
+ * All rights reserved. Use is subject to license terms.
+ *
+ * This file is available and licensed under the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the distribution.
+ *  - Neither the name of Oracle Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package preloader;
+
+import javafx.application.Application;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.scene.Scene;
+import javafx.scene.control.ListCell;
+import javafx.scene.control.ListView;
+import javafx.scene.layout.Background;
+import javafx.scene.layout.BackgroundFill;
+import javafx.scene.paint.Color;
+import javafx.stage.Stage;
+import javafx.util.Callback;
+
+/**
+ * This app is meant to be used with a preloader. Run with:
+ * -Djavafx.preloader=preloader.PreloaderApp
+ *
+ * This will run with the preloader on desktop and iOS.
+ */
+public class SlowStartingApp extends Application {
+    private ListView<Background> list;
+    public Stage preloaderApp;
+
+    @Override
+    public void init() throws Exception {
+        System.out.println("App init: " + Thread.currentThread());
+        ObservableList<Background> data = FXCollections.observableArrayList();
+        for (int i=0; i<100; i++) {
+            data.add(new Background(new BackgroundFill(
+                    new Color(Math.random(), Math.random(), Math.random(), 1), null, null)));
+        }
+        list = new ListView<>(data);
+        list.setCellFactory(new Callback<ListView<Background>, ListCell<Background>>() {
+            @Override
+            public ListCell<Background> call(ListView<Background> param) {
+                ListCell<Background> cell = new ListCell<Background>() {
+                    @Override
+                    protected void updateItem(Background item, boolean empty) {
+                        super.updateItem(item, empty);
+                        if (!empty) {
+                            setBackground(item);
+                        }
+                    }
+                };
+                cell.setPrefHeight(100);
+                return cell;
+            }
+        });
+        System.out.println("Simulating a really slow startup");
+        Thread.sleep(10000);
+    }
+
+    @Override
+    public void start(Stage stage) throws Exception {
+        System.out.println("App start: " + Thread.currentThread());
+        Scene scene = new Scene(list);
+        stage.setScene(scene);
+        stage.show();
+        preloaderApp.close();
+    }
+
+    /**
+     * Java main for when running without JavaFX launcher
+     */
+    public static void main(String[] args) {
+        launch(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/performance/GraphicsPerformance/src/main/java/scrolling/PixelAlignedTranslatingGridTest.java	Tue Aug 27 09:36:40 2013 -0700
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates.
+ * All rights reserved. Use is subject to license terms.
+ *
+ * This file is available and licensed under the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the distribution.
+ *  - Neither the name of Oracle Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package scrolling;
+
+import javafx.animation.Animation;
+import javafx.animation.KeyFrame;
+import javafx.animation.KeyValue;
+import javafx.animation.Timeline;
+import javafx.beans.property.IntegerProperty;
+import javafx.beans.property.SimpleIntegerProperty;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.util.Duration;
+
+/**
+ * Translates a grid of items, but does so on pixel boundaries only.
+ */
+public class PixelAlignedTranslatingGridTest extends TranslatingGridTest {
+    PixelAlignedTranslatingGridTest(ScrollingBenchBase benchmark, int rows, int cols) {
+        super(benchmark, rows, cols);
+    }
+
+    // For each test, we need to start our timeline which will scroll stuff...
+    @Override protected Animation createBenchmarkDriver(Scene scene) {
+        final Parent root = (Parent) scene.getRoot().getChildrenUnmodifiable().get(0);
+        final IntegerProperty translation = new SimpleIntegerProperty();
+        root.translateYProperty().bind(translation);
+        Timeline t = new Timeline(
+                new KeyFrame(Duration.seconds(0), new KeyValue(translation, 0)),
+                new KeyFrame(Duration.seconds(3), new KeyValue(translation, scene.getHeight()-height)));
+        t.setAutoReverse(true);
+        t.setCycleCount(2);
+        return t;
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/performance/GraphicsPerformance/src/main/java/scrolling/RectScrollingBench.java	Tue Aug 27 09:36:40 2013 -0700
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates.
+ * All rights reserved. Use is subject to license terms.
+ *
+ * This file is available and licensed under the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the distribution.
+ *  - Neither the name of Oracle Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package scrolling;
+
+import javafx.scene.paint.Color;
+import javafx.scene.shape.Rectangle;
+
+/**
+ */
+public class RectScrollingBench extends ScrollingBenchBase<Rectangle> {
+    @Override protected void resizeAndRelocate(Rectangle rect, double x, double y, double width, double height) {
+        rect.setX(x);
+        rect.setY(y);
+        rect.setWidth(width);
+        rect.setHeight(height);
+    }
+
+    @Override protected Rectangle createNode() {
+        Rectangle rect = new Rectangle();
+        rect.setFill(new Color(Math.random(), Math.random(), Math.random(), 1));
+        return rect;
+    }
+
+    /**
+     * Java main for when running without JavaFX launcher
+     */
+    public static void main(String[] args) {
+        launch(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/performance/GraphicsPerformance/src/main/java/scrolling/ScrollPaneGridTest.java	Tue Aug 27 09:36:40 2013 -0700
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates.
+ * All rights reserved. Use is subject to license terms.
+ *
+ * This file is available and licensed under the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the distribution.
+ *  - Neither the name of Oracle Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package scrolling;
+
+import javafx.animation.Animation;
+import javafx.animation.KeyFrame;
+import javafx.animation.KeyValue;
+import javafx.animation.Timeline;
+import javafx.beans.InvalidationListener;
+import javafx.beans.Observable;
+import javafx.beans.property.IntegerProperty;
+import javafx.beans.property.SimpleIntegerProperty;
+import javafx.scene.Scene;
+import javafx.scene.control.ScrollPane;
+import javafx.scene.layout.Pane;
+import javafx.util.Duration;
+import nodecount.BenchTest;
+
+/**
+ * Uses a ScrollPane for scrolling a grid of items, using "pure" fractional
+ * positions.
+ */
+public class ScrollPaneGridTest extends BenchTest {
+    ScrollPaneGridTest(ScrollingBenchBase benchmark, int rows, int cols) {
+        // Pixel snap the grid itself, always, so we know we are measuring
+        // the effect of translating fractionally, and not the cost of having
+        // nodes on fractional boundaries inherently.
+        super(benchmark, rows, cols, true);
+    }
+
+    // For each test, we need to start our timeline which will scroll stuff...
+    @Override protected Animation createBenchmarkDriver(Scene scene) {
+        final ScrollPane root = (ScrollPane) scene.getRoot();
+        final IntegerProperty vpos = new SimpleIntegerProperty() {
+            @Override
+            public void set(int newValue) {
+                super.set(newValue);
+                root.setVvalue(newValue);
+            }
+        };
+        Timeline t = new Timeline(
+                new KeyFrame(Duration.seconds(0), new KeyValue(vpos, 0)),
+                new KeyFrame(Duration.seconds(3), new KeyValue(vpos, root.getVmax())));
+        t.setAutoReverse(true);
+        t.setCycleCount(2);
+
+        // Uncomment to see that the scroll pane is in fact pixel snapping already!
+//        final InvalidationListener layoutListener = new InvalidationListener() {
+//            @Override
+//            public void invalidated(Observable observable) {
+//                System.out.println(root.getContent().getParent().getLayoutY());
+//            }
+//        };
+//        root.getContent().parentProperty().addListener(new ChangeListener<Parent>() {
+//            @Override
+//            public void changed(ObservableValue<? extends Parent> observable, Parent oldValue, Parent newValue) {
+//                if (oldValue != null) oldValue.layoutYProperty().removeListener(layoutListener);
+//                if (newValue != null) newValue.layoutYProperty().addListener(layoutListener);
+//            }
+//        });
+
+        return t;
+    }
+
+    @Override
+    public void setup(Scene scene) {
+        super.setup(scene);
+
+        // Wrap in a ScrollPane
+        double side = ((scene.getWidth() + GAP) / getCols()) - GAP;
+        double height = (side * getRows()) + (GAP * (getRows() - 1));
+        final Pane pane = (Pane) scene.getRoot();
+        final ScrollPane sp = new ScrollPane(pane);
+        sp.setFitToWidth(true);
+        sp.heightProperty().addListener(new InvalidationListener() {
+            @Override
+            public void invalidated(Observable observable) {
+                pane.setPrefHeight(height);
+                sp.setVmin(0);
+                sp.setVmax(pane.getPrefHeight());
+            }
+        });
+//        pane.resize(scene.getWidth(), height);
+        scene.setRoot(sp);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/performance/GraphicsPerformance/src/main/java/scrolling/ScrollingBenchBase.java	Tue Aug 27 09:36:40 2013 -0700
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates.
+ * All rights reserved. Use is subject to license terms.
+ *
+ * This file is available and licensed under the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the distribution.
+ *  - Neither the name of Oracle Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package scrolling;
+
+import javafx.scene.Node;
+import nodecount.BenchBase;
+import nodecount.BenchTest;
+
+/**
+ * A type of grid-based test which scrolls in one dimension. The scrolling parent
+ * might be a Group with a translation, or a ScrollPane.
+ */
+public abstract class ScrollingBenchBase<T extends Node> extends BenchBase<T> {
+
+    @Override protected BenchTest[] createTests() {
+        int[][] sizes = new int[][] {
+                {30, 6},
+                {50, 6},
+                {100, 6},
+                {120, 6},
+                {180, 6},
+                {200, 6},
+        };
+        BenchTest[] tests = new BenchTest[3 * 6];
+        int sizeIndex = 0;
+        for (int i=0; i<tests.length; i+=3) {
+            int rows = sizes[sizeIndex][0];
+            int cols = sizes[sizeIndex][1];
+            tests[i] = new TranslatingGridTest(this, rows, cols);
+            tests[i+1] = new ScrollPaneGridTest(this, rows, cols);
+            tests[i+2] = new PixelAlignedTranslatingGridTest(this, rows, cols);
+            sizeIndex++;
+        }
+        return tests;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/performance/GraphicsPerformance/src/main/java/scrolling/TranslatingGridTest.java	Tue Aug 27 09:36:40 2013 -0700
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates.
+ * All rights reserved. Use is subject to license terms.
+ *
+ * This file is available and licensed under the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the distribution.
+ *  - Neither the name of Oracle Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package scrolling;
+
+import javafx.animation.Animation;
+import javafx.animation.KeyFrame;
+import javafx.animation.KeyValue;
+import javafx.animation.Timeline;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.StackPane;
+import javafx.scene.shape.Rectangle;
+import javafx.util.Duration;
+import nodecount.BenchTest;
+
+/**
+ * Translates a grid of items to their "pure" fractional positions.
+ */
+public class TranslatingGridTest extends BenchTest {
+    private Rectangle clip = new Rectangle();
+    protected double height;
+
+    TranslatingGridTest(ScrollingBenchBase benchmark, int rows, int cols) {
+        // Pixel snap the grid itself, always, so we know we are measuring
+        // the effect of translating fractionally, and not the cost of having
+        // nodes on fractional boundaries inherently.
+        super(benchmark, rows, cols, true);
+    }
+
+    // For each test, we need to start our timeline which will scroll stuff...
+    @Override protected Animation createBenchmarkDriver(Scene scene) {
+        final Parent root = (Parent) scene.getRoot().getChildrenUnmodifiable().get(0);
+        Timeline t = new Timeline(
+                new KeyFrame(Duration.seconds(0), new KeyValue(root.translateYProperty(), 0)),
+                new KeyFrame(Duration.seconds(3), new KeyValue(root.translateYProperty(), scene.getHeight()-height)));
+        t.setAutoReverse(true);
+        t.setCycleCount(2);
+        return t;
+    }
+
+    @Override
+    public void setup(Scene scene) {
+        super.setup(scene);
+
+        double side = ((scene.getWidth() + GAP) / getCols()) - GAP;
+        height = (side * getRows()) + (GAP * (getRows() - 1));
+
+        // Gotta handle layout so the old root pane is taller than the window but wide as the window
+        final Pane pane = (Pane) scene.getRoot();
+        Pane root = new Pane(pane) {
+            @Override
+            protected void layoutChildren() {
+                pane.resize(getWidth(), height);
+            }
+        };
+        pane.resize(scene.getWidth(), height);
+        clip.widthProperty().bind(scene.widthProperty());
+        clip.heightProperty().bind(scene.heightProperty());
+        Pane p = new StackPane(root);
+        p.setCache(true);
+        p.setClip(clip);
+        scene.setRoot(p);
+    }
+
+    @Override
+    public void tearDown() {
+        super.tearDown();
+        clip.widthProperty().unbind();
+        clip.heightProperty().unbind();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/performance/GraphicsPerformance/src/main/java/startup/StartupApp.java	Tue Aug 27 09:36:40 2013 -0700
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates.
+ * All rights reserved. Use is subject to license terms.
+ *
+ * This file is available and licensed under the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the distribution.
+ *  - Neither the name of Oracle Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package startup;
+
+import javafx.application.Application;
+import javafx.scene.Group;
+import javafx.scene.Scene;
+import javafx.scene.paint.Color;
+import javafx.stage.Stage;
+
+/**
+ * A very basic application for testing startup. You must make sure to have:
+ * -Dsun.perflog
+ * -Dsun.perflog.fx.firstpaintflush
+ *
+ * both specified so that you get the startup metrics. You may also want:
+ * -verbose:class
+ *
+ * to be able to see which classes are being loaded.
+ */
+public class StartupApp extends Application {
+
+    @Override
+    public void start(Stage stage) throws Exception {
+        Scene scene = new Scene(new Group(), 320, 200, Color.PURPLE);
+        stage.setScene(scene);
+        stage.show();
+    }
+
+    /**
+     * Java main for when running without JavaFX launcher
+     */
+    public static void main(String[] args) {
+        launch(args);
+    }
+}
Binary file apps/performance/GraphicsPerformance/src/main/resources/nodecount/Duke_Wave_Opaque.png has changed
--- a/apps/samples/Ensemble8/src/generated/java/ensemble/generated/Samples.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/apps/samples/Ensemble8/src/generated/java/ensemble/generated/Samples.java	Tue Aug 27 09:36:40 2013 -0700
@@ -13,7 +13,7 @@
     private static final SampleInfo SAMPLE_6 = new SampleInfo("Path Transition","A sample in which a node moves along a path from end to end over a given time. ","/Animation/Transitions/Path Transition","/ensemble/samples/animation/transitions/pathtransition","ensemble.samples.animation.transitions.pathtransition.PathTransitionApp","/ensemble/samples/animation/transitions/pathtransition/preview.png",new String[]{"/ensemble/samples/animation/transitions/pathtransition/PathTransitionApp.java",},new String[]{"javafx.animation.PathTransition","javafx.animation.Transition",},new String[]{},new String[]{"/Animation/Transitions/Fade Transition","/Animation/Transitions/Fill Transition","/Animation/Transitions/Parallel Transition","/Animation/Transitions/Pause Transition","/Animation/Transitions/Rotate Transition","/Animation/Transitions/Scale Transition","/Animation/Transitions/Sequential Transition","/Animation/Transitions/Stroke Transition","/Animation/Transitions/Translate Transition",},"/ensemble/samples/animation/transitions/pathtransition/PathTransitionApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_7 = new SampleInfo("Pause Transition","A sample in which a node pauses over a given time. ","/Animation/Transitions/Pause Transition","/ensemble/samples/animation/transitions/pausetransition","ensemble.samples.animation.transitions.pausetransition.PauseTransitionApp","/ensemble/samples/animation/transitions/pausetransition/preview.png",new String[]{"/ensemble/samples/animation/transitions/pausetransition/PauseTransitionApp.java",},new String[]{"javafx.animation.PauseTransition","javafx.animation.Transition",},new String[]{},new String[]{"/Animation/Transitions/Fade Transition","/Animation/Transitions/Fill Transition","/Animation/Transitions/Parallel Transition","/Animation/Transitions/Path Transition","/Animation/Transitions/Rotate Transition","/Animation/Transitions/Scale Transition","/Animation/Transitions/Sequential Transition","/Animation/Transitions/Stroke Transition","/Animation/Transitions/Translate Transition",},"/ensemble/samples/animation/transitions/pausetransition/PauseTransitionApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_8 = new SampleInfo("Rotate Transition","A sample in which a node rotates around its center over a given time. ","/Animation/Transitions/Rotate Transition","/ensemble/samples/animation/transitions/rotatetransition","ensemble.samples.animation.transitions.rotatetransition.RotateTransitionApp","/ensemble/samples/animation/transitions/rotatetransition/preview.png",new String[]{"/ensemble/samples/animation/transitions/rotatetransition/RotateTransitionApp.java",},new String[]{"javafx.animation.RotateTransition","javafx.animation.Transition",},new String[]{},new String[]{"/Animation/Transitions/Fade Transition","/Animation/Transitions/Fill Transition","/Animation/Transitions/Parallel Transition","/Animation/Transitions/Path Transition","/Animation/Transitions/Pause Transition","/Animation/Transitions/Scale Transition","/Animation/Transitions/Sequential Transition","/Animation/Transitions/Stroke Transition","/Animation/Transitions/Translate Transition",},"/ensemble/samples/animation/transitions/rotatetransition/RotateTransitionApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
-    private static final SampleInfo SAMPLE_9 = new SampleInfo("Scale Transition","A sample in which a node scales larger and smaller over a given time. ","/Animation/Transitions/Scale Transition","/ensemble/samples/animation/transitions/scaletransition","ensemble.samples.animation.transitions.scaletransition.ScaleTransitionApp","/ensemble/samples/animation/transitions/scaletransition/preview.png",new String[]{"/ensemble/samples/animation/transitions/scaletransition/ScaleTransitionApp.java","/ensemble/samples/animation/transitions/scaletransition/ScaleTransitionApp.java.orig","/ensemble/samples/animation/transitions/scaletransition/ScaleTransitionApp.java.typoFixed",},new String[]{"javafx.animation.ScaleTransition","javafx.animation.Transition",},new String[]{},new String[]{"/Animation/Transitions/Fade Transition","/Animation/Transitions/Fill Transition","/Animation/Transitions/Parallel Transition","/Animation/Transitions/Path Transition","/Animation/Transitions/Pause Transition","/Animation/Transitions/Rotate Transition","/Animation/Transitions/Sequential Transition","/Animation/Transitions/Stroke Transition","/Animation/Transitions/Translate Transition",},"/ensemble/samples/animation/transitions/scaletransition/ScaleTransitionApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
+    private static final SampleInfo SAMPLE_9 = new SampleInfo("Scale Transition","A sample in which a node scales larger and smaller over a given time. ","/Animation/Transitions/Scale Transition","/ensemble/samples/animation/transitions/scaletransition","ensemble.samples.animation.transitions.scaletransition.ScaleTransitionApp","/ensemble/samples/animation/transitions/scaletransition/preview.png",new String[]{"/ensemble/samples/animation/transitions/scaletransition/ScaleTransitionApp.java",},new String[]{"javafx.animation.ScaleTransition","javafx.animation.Transition",},new String[]{},new String[]{"/Animation/Transitions/Fade Transition","/Animation/Transitions/Fill Transition","/Animation/Transitions/Parallel Transition","/Animation/Transitions/Path Transition","/Animation/Transitions/Pause Transition","/Animation/Transitions/Rotate Transition","/Animation/Transitions/Sequential Transition","/Animation/Transitions/Stroke Transition","/Animation/Transitions/Translate Transition",},"/ensemble/samples/animation/transitions/scaletransition/ScaleTransitionApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_10 = new SampleInfo("Sequential Transition","A sample in which various transitions are executed sequentially. ","/Animation/Transitions/Sequential Transition","/ensemble/samples/animation/transitions/sequentialtransition","ensemble.samples.animation.transitions.sequentialtransition.SequentialTransitionApp","/ensemble/samples/animation/transitions/sequentialtransition/preview.png",new String[]{"/ensemble/samples/animation/transitions/sequentialtransition/SequentialTransitionApp.java",},new String[]{"javafx.animation.SequentialTransition","javafx.animation.Transition",},new String[]{},new String[]{"/Animation/Transitions/Fade Transition","/Animation/Transitions/Fill Transition","/Animation/Transitions/Parallel Transition","/Animation/Transitions/Path Transition","/Animation/Transitions/Pause Transition","/Animation/Transitions/Rotate Transition","/Animation/Transitions/Scale Transition","/Animation/Transitions/Stroke Transition","/Animation/Transitions/Translate Transition",},"/ensemble/samples/animation/transitions/sequentialtransition/SequentialTransitionApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_11 = new SampleInfo("Stroke Transition","A sample in which the stroke color of a shape changes over a given time. ","/Animation/Transitions/Stroke Transition","/ensemble/samples/animation/transitions/stroketransition","ensemble.samples.animation.transitions.stroketransition.StrokeTransitionApp","/ensemble/samples/animation/transitions/stroketransition/preview.png",new String[]{"/ensemble/samples/animation/transitions/stroketransition/StrokeTransitionApp.java",},new String[]{"javafx.animation.StrokeTransition","javafx.animation.Transition",},new String[]{},new String[]{"/Animation/Transitions/Fade Transition","/Animation/Transitions/Fill Transition","/Animation/Transitions/Parallel Transition","/Animation/Transitions/Path Transition","/Animation/Transitions/Pause Transition","/Animation/Transitions/Rotate Transition","/Animation/Transitions/Scale Transition","/Animation/Transitions/Sequential Transition","/Animation/Transitions/Translate Transition",},"/ensemble/samples/animation/transitions/stroketransition/StrokeTransitionApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_12 = new SampleInfo("Translate Transition","A sample in which a node moves from one location to another over a given time. ","/Animation/Transitions/Translate Transition","/ensemble/samples/animation/transitions/translatetransition","ensemble.samples.animation.transitions.translatetransition.TranslateTransitionApp","/ensemble/samples/animation/transitions/translatetransition/preview.png",new String[]{"/ensemble/samples/animation/transitions/translatetransition/TranslateTransitionApp.java",},new String[]{"javafx.animation.TranslateTransition","javafx.animation.Transition",},new String[]{},new String[]{"/Animation/Transitions/Fade Transition","/Animation/Transitions/Fill Transition","/Animation/Transitions/Parallel Transition","/Animation/Transitions/Path Transition","/Animation/Transitions/Pause Transition","/Animation/Transitions/Rotate Transition","/Animation/Transitions/Scale Transition","/Animation/Transitions/Sequential Transition","/Animation/Transitions/Stroke Transition",},"/ensemble/samples/animation/transitions/translatetransition/TranslateTransitionApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
@@ -43,7 +43,7 @@
     private static final SampleInfo SAMPLE_36 = new SampleInfo("ChoiceBox","An example of a ChoiceBox with several options. The ChoiceBox control displays a default or current selection, with an icon to click that expands the list for a selection. ","/Controls/ChoiceBox","/ensemble/samples/controls/choicebox","ensemble.samples.controls.choicebox.ChoiceBoxApp","/ensemble/samples/controls/choicebox/preview.png",new String[]{"/ensemble/samples/controls/choicebox/ChoiceBoxApp.java",},new String[]{"javafx.scene.control.ChoiceBox",},new String[]{},new String[]{},"/ensemble/samples/controls/choicebox/ChoiceBoxApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_37 = new SampleInfo("ColorPicker","A sample that demonstrates the ColorPicker. ","/Controls/ColorPicker","/ensemble/samples/controls/colorpicker","ensemble.samples.controls.colorpicker.ColorPickerApp","/ensemble/samples/controls/colorpicker/preview.png",new String[]{"/ensemble/samples/controls/colorpicker/ColorPickerApp.java",},new String[]{"javafx.scene.control.ColorPicker",},new String[]{},new String[]{},"/ensemble/samples/controls/colorpicker/ColorPickerApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_38 = new SampleInfo("HyperLink","A sample that shows a simple hyperlink and a hyperlink with an image. ","/Controls/HyperLink","/ensemble/samples/controls/hyperlink","ensemble.samples.controls.hyperlink.HyperLinkApp","/ensemble/samples/controls/hyperlink/preview.png",new String[]{"/ensemble/samples/shared-resources/icon-48x48.png","/ensemble/samples/controls/hyperlink/HyperLinkApp.java",},new String[]{"javafx.scene.control.Hyperlink",},new String[]{},new String[]{},"/ensemble/samples/controls/hyperlink/HyperLinkApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
-    private static final SampleInfo SAMPLE_39 = new SampleInfo("Menu","An example of a menu bar. The example includes use of the system bar, if the current platform supports a system bar. ","/Controls/Menu","/ensemble/samples/controls/menu","ensemble.samples.controls.menu.MenuApp","/ensemble/samples/controls/menu/preview.png",new String[]{"/ensemble/samples/shared-resources/menuInfo.png","/ensemble/samples/controls/menu/MenuApp.java","/ensemble/samples/controls/menu/MenuApp.java.orig",},new String[]{"javafx.scene.control.MenuBar","javafx.scene.control.Menu","javafx.scene.control.MenuItem",},new String[]{},new String[]{},"/ensemble/samples/controls/menu/MenuApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
+    private static final SampleInfo SAMPLE_39 = new SampleInfo("Menu","An example of a menu bar. The example includes use of the system bar, if the current platform supports a system bar. ","/Controls/Menu","/ensemble/samples/controls/menu","ensemble.samples.controls.menu.MenuApp","/ensemble/samples/controls/menu/preview.png",new String[]{"/ensemble/samples/shared-resources/menuInfo.png","/ensemble/samples/controls/menu/MenuApp.java",},new String[]{"javafx.scene.control.MenuBar","javafx.scene.control.Menu","javafx.scene.control.MenuItem",},new String[]{},new String[]{},"/ensemble/samples/controls/menu/MenuApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_40 = new SampleInfo("Pagination","A sample that demonstrates pagination. ","/Controls/Pagination","/ensemble/samples/controls/pagination","ensemble.samples.controls.pagination.PaginationApp","/ensemble/samples/controls/pagination/preview.png",new String[]{"/ensemble/samples/shared-resources/Animal1.jpg","/ensemble/samples/shared-resources/Animal2.jpg","/ensemble/samples/shared-resources/Animal3.jpg","/ensemble/samples/shared-resources/Animal4.jpg","/ensemble/samples/shared-resources/Animal5.jpg","/ensemble/samples/shared-resources/Animal6.jpg","/ensemble/samples/shared-resources/Animal7.jpg","/ensemble/samples/controls/pagination/PaginationApp.java",},new String[]{"javafx.scene.control.Pagination",},new String[]{},new String[]{},"/ensemble/samples/controls/pagination/PaginationApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_41 = new SampleInfo("Progress Bar","A sample that demonstrates the ProgressBar control. ","/Controls/Progress Bar","/ensemble/samples/controls/progressbar","ensemble.samples.controls.progressbar.ProgressBarApp","/ensemble/samples/controls/progressbar/preview.png",new String[]{"/ensemble/samples/controls/progressbar/ProgressBarApp.java",},new String[]{"javafx.scene.control.ProgressBar",},new String[]{},new String[]{"/Controls/Progress Indicator",},"/ensemble/samples/controls/progressbar/ProgressBarApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_42 = new SampleInfo("Progress Indicator","A sample that demonstrates the Progress Indicator control in various modes. ","/Controls/Progress Indicator","/ensemble/samples/controls/progressindicator","ensemble.samples.controls.progressindicator.ProgressIndicatorApp","/ensemble/samples/controls/progressindicator/preview.png",new String[]{"/ensemble/samples/controls/progressindicator/ProgressIndicatorApp.java",},new String[]{"javafx.scene.control.ProgressIndicator",},new String[]{},new String[]{"/Controls/Progress Bar",},"/ensemble/samples/controls/progressindicator/ProgressIndicatorApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
@@ -59,7 +59,7 @@
     private static final SampleInfo SAMPLE_52 = new SampleInfo("Simple ListView","A simple implementation of the ListView control, in which a list of items is displayed vertically.  ListView is a powerful multirow control, in which each of a virtually unlimited number of horizontal or vertical rows is defined as a cell. The control also supports dynamically variable nonhomogenous row heights. ","/Controls/Listview/Simple ListView","/ensemble/samples/controls/listview/simplelistview","ensemble.samples.controls.listview.simplelistview.SimpleListViewApp","/ensemble/samples/controls/listview/simplelistview/preview.png",new String[]{"/ensemble/samples/controls/listview/simplelistview/SimpleListViewApp.java",},new String[]{"javafx.scene.control.ListView","javafx.scene.control.SelectionModel",},new String[]{},new String[]{"/Controls/Listview/HorizontalListView","/Controls/Listview/ListViewCellFactory",},"/ensemble/samples/controls/listview/simplelistview/SimpleListViewApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_53 = new SampleInfo("Hidden SplitPane","A sample that demonstrates styling a hidden split pane with CSS. ","/Controls/Splitpane/Hidden SplitPane","/ensemble/samples/controls/splitpane/hiddensplitpane","ensemble.samples.controls.splitpane.hiddensplitpane.HiddenSplitPaneApp","/ensemble/samples/controls/splitpane/hiddensplitpane/preview.png",new String[]{"/ensemble/samples/controls/splitpane/hiddensplitpane/HiddenSplitPaneApp.java","/ensemble/samples/controls/splitpane/hiddensplitpane/HiddenSplitPane.css",},new String[]{"javafx.scene.control.SplitPane",},new String[]{},new String[]{},"/ensemble/samples/controls/splitpane/hiddensplitpane/HiddenSplitPaneApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_54 = new SampleInfo("TabPane","Some implementations of tabs using the TabPane class. ","/Controls/Tab/TabPane","/ensemble/samples/controls/tab/tabpane","ensemble.samples.controls.tab.tabpane.TabPaneApp","/ensemble/samples/controls/tab/tabpane/preview.png",new String[]{"/ensemble/samples/controls/tab/tabpane/TabPaneApp.java","/ensemble/samples/controls/tab/tabpane/tab_16.png",},new String[]{"javafx.scene.control.Tab","javafx.scene.control.TabPane","javafx.scene.control.TabBuilder",},new String[]{},new String[]{},"/ensemble/samples/controls/tab/tabpane/TabPaneApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
-    private static final SampleInfo SAMPLE_55 = new SampleInfo("TableCellFactory","A simple table that uses cell factories to add a checkbox to a table column and to add textfields to table columns. The latter enables editing of first name, last name, and email. ","/Controls/Table/TableCellFactory","/ensemble/samples/controls/table/tablecellfactory","ensemble.samples.controls.table.tablecellfactory.TableCellFactoryApp","/ensemble/samples/controls/table/tablecellfactory/preview.png",new String[]{"/ensemble/samples/controls/table/tablecellfactory/CheckBoxTableCell.java.orig","/ensemble/samples/controls/table/tablecellfactory/CheckBoxTableCell.java.save","/ensemble/samples/controls/table/tablecellfactory/EditingCell.java.orig","/ensemble/samples/controls/table/tablecellfactory/Person.java","/ensemble/samples/controls/table/tablecellfactory/TableCellFactoryApp.java",},new String[]{"javafx.scene.control.TableCell","javafx.scene.control.TableColumn","javafx.scene.control.TablePosition","javafx.scene.control.TableRow","javafx.scene.control.TableView",},new String[]{},new String[]{},"/ensemble/samples/controls/table/tablecellfactory/TableCellFactoryApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
+    private static final SampleInfo SAMPLE_55 = new SampleInfo("TableCellFactory","A simple table that uses cell factories to add a checkbox to a table column and to add textfields to table columns. The latter enables editing of first name, last name, and email. ","/Controls/Table/TableCellFactory","/ensemble/samples/controls/table/tablecellfactory","ensemble.samples.controls.table.tablecellfactory.TableCellFactoryApp","/ensemble/samples/controls/table/tablecellfactory/preview.png",new String[]{"/ensemble/samples/controls/table/tablecellfactory/Person.java","/ensemble/samples/controls/table/tablecellfactory/TableCellFactoryApp.java",},new String[]{"javafx.scene.control.TableCell","javafx.scene.control.TableColumn","javafx.scene.control.TablePosition","javafx.scene.control.TableRow","javafx.scene.control.TableView",},new String[]{},new String[]{},"/ensemble/samples/controls/table/tablecellfactory/TableCellFactoryApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_56 = new SampleInfo("TableView","A simple table with a header row. ","/Controls/Table/TableView","/ensemble/samples/controls/table/tableview","ensemble.samples.controls.table.tableview.TableViewApp","/ensemble/samples/controls/table/tableview/preview.png",new String[]{"/ensemble/samples/controls/table/tableview/Person.java","/ensemble/samples/controls/table/tableview/TableViewApp.java",},new String[]{"javafx.scene.control.TableColumn","javafx.scene.control.TablePosition","javafx.scene.control.TableRow","javafx.scene.control.TableView",},new String[]{},new String[]{},"/ensemble/samples/controls/table/tableview/TableViewApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_57 = new SampleInfo("Advanced Label","Several Label controls, displayed in various alignments with respect to an image. ","/Controls/Text/Advanced Label","/ensemble/samples/controls/text/advancedlabel","ensemble.samples.controls.text.advancedlabel.AdvancedLabelApp","/ensemble/samples/controls/text/advancedlabel/preview.png",new String[]{"/ensemble/samples/shared-resources/icon-48x48.png","/ensemble/samples/controls/text/advancedlabel/AdvancedLabelApp.java",},new String[]{"javafx.scene.control.Label",},new String[]{},new String[]{"/Controls/Text/Simple Label","/Controls/Button/Graphic Button",},"/ensemble/samples/controls/text/advancedlabel/AdvancedLabelApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_58 = new SampleInfo("Inset Text","A sample that shows styling of text through CSS. ","/Controls/Text/Inset Text","/ensemble/samples/controls/text/insettext","ensemble.samples.controls.text.insettext.InsetTextApp","/ensemble/samples/controls/text/insettext/preview.png",new String[]{"/ensemble/samples/controls/text/insettext/InsetTextApp.java","/ensemble/samples/controls/text/insettext/InsetText.css",},new String[]{"javafx.geometry.Insets","javafx.scene.control.LabelBuilder",},new String[]{},new String[]{"/Controls/Text/Simple Label",},"/ensemble/samples/controls/text/insettext/InsetTextApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
@@ -71,7 +71,7 @@
     private static final SampleInfo SAMPLE_64 = new SampleInfo("Tool Bar","A toolbar with three buttons. ","/Controls/Toolbar/Tool Bar","/ensemble/samples/controls/toolbar/toolbar","ensemble.samples.controls.toolbar.toolbar.ToolBarApp","/ensemble/samples/controls/toolbar/toolbar/preview.png",new String[]{"/ensemble/samples/controls/toolbar/toolbar/ToolBarApp.java",},new String[]{"javafx.scene.control.ToolBar",},new String[]{},new String[]{},"/ensemble/samples/controls/toolbar/toolbar/ToolBarApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_65 = new SampleInfo("FXML Login Demo","FXML-based Login screen sample ","/Fxml/FXML Login Demo","/ensemble/samples/fxml/fxmldemo","ensemble.samples.fxml.fxmldemo.FXMLLoginDemoApp","/ensemble/samples/fxml/fxmldemo/preview.png",new String[]{"/ensemble/samples/fxml/fxmldemo/Authenticator.java","/ensemble/samples/fxml/fxmldemo/FXMLLoginDemoApp.java","/ensemble/samples/fxml/fxmldemo/LoginController.java","/ensemble/samples/fxml/fxmldemo/ProfileController.java","/ensemble/samples/fxml/fxmldemo/User.java","/ensemble/samples/fxml/fxmldemo/Login.css","/ensemble/samples/fxml/fxmldemo/Login.fxml","/ensemble/samples/fxml/fxmldemo/Profile.fxml",},new String[]{"java.util.HashMap","java.util.Map","java.io.InputStream","java.util.logging.Level","java.util.logging.Logger","javafx.fxml.FXML","javafx.fxml.FXMLLoader","javafx.fxml.Initializable","javafx.fxml.JavaFXBuilderFactory","javafx.stage.Stage",},new String[]{},new String[]{},"/ensemble/samples/fxml/fxmldemo/FXMLLoginDemoApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_66 = new SampleInfo("Bouncing Balls","A sample that shows animated bouncing balls. Select a ball to start or stop the animation. Select the reset button to stop all the balls. ","/Graphics/Bouncing Balls","/ensemble/samples/graphics/bouncingballs","ensemble.samples.graphics.bouncingballs.BouncingBallsApp","/ensemble/samples/graphics/bouncingballs/preview.png",new String[]{"/ensemble/samples/graphics/bouncingballs/Ball.java","/ensemble/samples/graphics/bouncingballs/BallsPane.java","/ensemble/samples/graphics/bouncingballs/BallsScreen.java","/ensemble/samples/graphics/bouncingballs/BouncingBallsApp.java","/ensemble/samples/graphics/bouncingballs/Constants.java",},new String[]{"java.util.ArrayList","java.util.List","javafx.util.Duration","javafx.stage.Stage","javafx.stage.Screen","javafx.scene.Parent","javafx.scene.Group","javafx.scene.Scene","javafx.scene.Node","javafx.scene.effect.Reflection","javafx.scene.shape.Rectangle","javafx.scene.shape.Line","javafx.scene.shape.Circle","javafx.scene.paint.Color","javafx.scene.paint.CycleMethod","javafx.scene.paint.RadialGradient","javafx.scene.paint.Stop","javafx.scene.control.Button","javafx.scene.text.Text","javafx.application.Application","javafx.animation.Interpolator","javafx.animation.KeyFrame","javafx.animation.KeyValue","javafx.animation.Timeline","javafx.animation.Animation.Status","javafx.event.EventHandler","javafx.event.ActionEvent","javafx.scene.input.MouseEvent","javafx.geometry.Insets",},new String[]{},new String[]{},"/ensemble/samples/graphics/bouncingballs/BouncingBallsApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
-    private static final SampleInfo SAMPLE_67 = new SampleInfo("Brick Breaker","The main purpose of the game is to break all the bricks and not drop the ball. ","/Graphics/Brick Breaker","/ensemble/samples/graphics/brickbreaker","ensemble.samples.graphics.brickbreaker.BrickBreakerApp","/ensemble/samples/graphics/brickbreaker/preview.png",new String[]{"/ensemble/samples/graphics/brickbreaker/Ball.java","/ensemble/samples/graphics/brickbreaker/Bat.java","/ensemble/samples/graphics/brickbreaker/Bonus.java","/ensemble/samples/graphics/brickbreaker/Brick.java","/ensemble/samples/graphics/brickbreaker/BrickBreakerApp.java","/ensemble/samples/graphics/brickbreaker/BrickBreakerApp.java.orig","/ensemble/samples/shared-resources/brickImages/background.png","/ensemble/samples/shared-resources/brickImages/bat/left.png","/ensemble/samples/shared-resources/brickImages/bat/center.png","/ensemble/samples/shared-resources/brickImages/bat/right.png","/ensemble/samples/shared-resources/brickImages/ball/ball0.png","/ensemble/samples/shared-resources/brickImages/ball/ball1.png","/ensemble/samples/shared-resources/brickImages/ball/ball2.png","/ensemble/samples/shared-resources/brickImages/ball/ball3.png","/ensemble/samples/shared-resources/brickImages/ball/ball4.png","/ensemble/samples/shared-resources/brickImages/ball/ball5.png","/ensemble/samples/shared-resources/brickImages/logo.png","/ensemble/samples/shared-resources/brickImages/splash/brick.png","/ensemble/samples/shared-resources/brickImages/splash/brickshadow.png","/ensemble/samples/shared-resources/brickImages/splash/breaker.png","/ensemble/samples/shared-resources/brickImages/splash/breakershadow.png","/ensemble/samples/shared-resources/brickImages/splash/pressanykey.png","/ensemble/samples/shared-resources/brickImages/splash/pressanykeyshadow.png","/ensemble/samples/shared-resources/brickImages/splash/strike.png","/ensemble/samples/shared-resources/brickImages/splash/strikeshadow.png","/ensemble/samples/shared-resources/brickImages/splash/sun.png","/ensemble/samples/shared-resources/brickImages/ready.png","/ensemble/samples/shared-resources/brickImages/gameover.png","/ensemble/samples/shared-resources/brickImages/brick/blue.png","/ensemble/samples/shared-resources/brickImages/brick/broken1.png","/ensemble/samples/shared-resources/brickImages/brick/broken2.png","/ensemble/samples/shared-resources/brickImages/brick/brown.png","/ensemble/samples/shared-resources/brickImages/brick/cyan.png","/ensemble/samples/shared-resources/brickImages/brick/green.png","/ensemble/samples/shared-resources/brickImages/brick/grey.png","/ensemble/samples/shared-resources/brickImages/brick/magenta.png","/ensemble/samples/shared-resources/brickImages/brick/orange.png","/ensemble/samples/shared-resources/brickImages/brick/red.png","/ensemble/samples/shared-resources/brickImages/brick/violet.png","/ensemble/samples/shared-resources/brickImages/brick/white.png","/ensemble/samples/shared-resources/brickImages/brick/yellow.png","/ensemble/samples/shared-resources/brickImages/bonus/ballslow.png","/ensemble/samples/shared-resources/brickImages/bonus/ballfast.png","/ensemble/samples/shared-resources/brickImages/bonus/catch.png","/ensemble/samples/shared-resources/brickImages/bonus/batgrow.png","/ensemble/samples/shared-resources/brickImages/bonus/batreduce.png","/ensemble/samples/shared-resources/brickImages/bonus/ballgrow.png","/ensemble/samples/shared-resources/brickImages/bonus/ballreduce.png","/ensemble/samples/shared-resources/brickImages/bonus/strike.png","/ensemble/samples/shared-resources/brickImages/bonus/extralife.png","/ensemble/samples/graphics/brickbreaker/Config.java","/ensemble/samples/graphics/brickbreaker/Config.java.orig","/ensemble/samples/shared-resources/brickImages/vline.png","/ensemble/samples/graphics/brickbreaker/Level.java","/ensemble/samples/graphics/brickbreaker/Level.java.orig","/ensemble/samples/graphics/brickbreaker/LevelData.java","/ensemble/samples/graphics/brickbreaker/Splash.java","/ensemble/samples/graphics/brickbreaker/Utils.java",},new String[]{"javafx.scene.image.Image","javafx.scene.image.ImageView","javafx.util.Duration","javafx.animation.KeyFrame","javafx.animation.KeyValue","javafx.animation.Timeline","javafx.application.Application","javafx.application.Platform","javafx.collections.ObservableList","javafx.geometry.Rectangle2D","javafx.geometry.VPos",},new String[]{},new String[]{},"/ensemble/samples/graphics/brickbreaker/BrickBreakerApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
+    private static final SampleInfo SAMPLE_67 = new SampleInfo("Brick Breaker","The main purpose of the game is to break all the bricks and not drop the ball. ","/Graphics/Brick Breaker","/ensemble/samples/graphics/brickbreaker","ensemble.samples.graphics.brickbreaker.BrickBreakerApp","/ensemble/samples/graphics/brickbreaker/preview.png",new String[]{"/ensemble/samples/graphics/brickbreaker/Ball.java","/ensemble/samples/graphics/brickbreaker/Bat.java","/ensemble/samples/graphics/brickbreaker/Bonus.java","/ensemble/samples/graphics/brickbreaker/Brick.java","/ensemble/samples/graphics/brickbreaker/BrickBreakerApp.java","/ensemble/samples/shared-resources/brickImages/background.png","/ensemble/samples/shared-resources/brickImages/bat/left.png","/ensemble/samples/shared-resources/brickImages/bat/center.png","/ensemble/samples/shared-resources/brickImages/bat/right.png","/ensemble/samples/shared-resources/brickImages/ball/ball0.png","/ensemble/samples/shared-resources/brickImages/ball/ball1.png","/ensemble/samples/shared-resources/brickImages/ball/ball2.png","/ensemble/samples/shared-resources/brickImages/ball/ball3.png","/ensemble/samples/shared-resources/brickImages/ball/ball4.png","/ensemble/samples/shared-resources/brickImages/ball/ball5.png","/ensemble/samples/shared-resources/brickImages/logo.png","/ensemble/samples/shared-resources/brickImages/splash/brick.png","/ensemble/samples/shared-resources/brickImages/splash/brickshadow.png","/ensemble/samples/shared-resources/brickImages/splash/breaker.png","/ensemble/samples/shared-resources/brickImages/splash/breakershadow.png","/ensemble/samples/shared-resources/brickImages/splash/pressanykey.png","/ensemble/samples/shared-resources/brickImages/splash/pressanykeyshadow.png","/ensemble/samples/shared-resources/brickImages/splash/strike.png","/ensemble/samples/shared-resources/brickImages/splash/strikeshadow.png","/ensemble/samples/shared-resources/brickImages/splash/sun.png","/ensemble/samples/shared-resources/brickImages/ready.png","/ensemble/samples/shared-resources/brickImages/gameover.png","/ensemble/samples/shared-resources/brickImages/brick/blue.png","/ensemble/samples/shared-resources/brickImages/brick/broken1.png","/ensemble/samples/shared-resources/brickImages/brick/broken2.png","/ensemble/samples/shared-resources/brickImages/brick/brown.png","/ensemble/samples/shared-resources/brickImages/brick/cyan.png","/ensemble/samples/shared-resources/brickImages/brick/green.png","/ensemble/samples/shared-resources/brickImages/brick/grey.png","/ensemble/samples/shared-resources/brickImages/brick/magenta.png","/ensemble/samples/shared-resources/brickImages/brick/orange.png","/ensemble/samples/shared-resources/brickImages/brick/red.png","/ensemble/samples/shared-resources/brickImages/brick/violet.png","/ensemble/samples/shared-resources/brickImages/brick/white.png","/ensemble/samples/shared-resources/brickImages/brick/yellow.png","/ensemble/samples/shared-resources/brickImages/bonus/ballslow.png","/ensemble/samples/shared-resources/brickImages/bonus/ballfast.png","/ensemble/samples/shared-resources/brickImages/bonus/catch.png","/ensemble/samples/shared-resources/brickImages/bonus/batgrow.png","/ensemble/samples/shared-resources/brickImages/bonus/batreduce.png","/ensemble/samples/shared-resources/brickImages/bonus/ballgrow.png","/ensemble/samples/shared-resources/brickImages/bonus/ballreduce.png","/ensemble/samples/shared-resources/brickImages/bonus/strike.png","/ensemble/samples/shared-resources/brickImages/bonus/extralife.png","/ensemble/samples/graphics/brickbreaker/Config.java","/ensemble/samples/shared-resources/brickImages/vline.png","/ensemble/samples/graphics/brickbreaker/Level.java","/ensemble/samples/graphics/brickbreaker/LevelData.java","/ensemble/samples/graphics/brickbreaker/Splash.java","/ensemble/samples/graphics/brickbreaker/Utils.java",},new String[]{"javafx.scene.image.Image","javafx.scene.image.ImageView","javafx.util.Duration","javafx.animation.KeyFrame","javafx.animation.KeyValue","javafx.animation.Timeline","javafx.application.Application","javafx.application.Platform","javafx.collections.ObservableList","javafx.geometry.Rectangle2D","javafx.geometry.VPos",},new String[]{},new String[]{},"/ensemble/samples/graphics/brickbreaker/BrickBreakerApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_68 = new SampleInfo("Calculator","A calculator that performs simple math exercises. ","/Graphics/Calculator","/ensemble/samples/graphics/calc","ensemble.samples.graphics.calc.CalculatorApp","/ensemble/samples/graphics/calc/preview.png",new String[]{"/ensemble/samples/graphics/calc/Calculator.java","/ensemble/samples/graphics/calc/CalculatorApp.java","/ensemble/samples/graphics/calc/Key.java","/ensemble/samples/graphics/calc/Util.java",},new String[]{"javafx.application.Application","javafx.stage.Stage","javafx.scene.Scene","javafx.scene.Group","javafx.scene.Parent","javafx.scene.paint.Color","javafx.scene.paint.CycleMethod","javafx.scene.paint.LinearGradient","javafx.scene.paint.Stop","javafx.scene.input.KeyEvent","javafx.scene.input.MouseEvent","javafx.scene.shape.Rectangle","javafx.scene.text.Font","javafx.scene.text.Text","javafx.event.EventHandler","javafx.geometry.VPos",},new String[]{},new String[]{},"/ensemble/samples/graphics/calc/CalculatorApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_69 = new SampleInfo("Colorful Circles","A sample that demonstrates how to draw and paint shapes, apply visual effects, blend colors in overlapping objects, and animate objects. ","/Graphics/Colorful Circles","/ensemble/samples/graphics/colorfulcircles","ensemble.samples.graphics.colorfulcircles.ColorfulCirclesApp","/ensemble/samples/graphics/colorfulcircles/preview.png",new String[]{"/ensemble/samples/graphics/colorfulcircles/ColorfulCirclesApp.java",},new String[]{"javafx.scene.effect.BlendMode","javafx.scene.effect.BoxBlur","javafx.scene.shape.Circle","javafx.scene.Group","javafx.scene.paint.LinearGradient","javafx.animation.Timeline",},new String[]{},new String[]{},"/ensemble/samples/graphics/colorfulcircles/ColorfulCirclesApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_70 = new SampleInfo("Digital Clock","A digital clock application that demonstrates JavaFX animation, images, and effects. ","/Graphics/Digital Clock","/ensemble/samples/graphics/digitalclock","ensemble.samples.graphics.digitalclock.DigitalClockApp","/ensemble/samples/graphics/digitalclock/preview.png",new String[]{"/ensemble/samples/graphics/digitalclock/Clock.java","/ensemble/samples/graphics/digitalclock/Digit.java","/ensemble/samples/shared-resources/DigitalClock-background.png","/ensemble/samples/graphics/digitalclock/DigitalClockApp.java",},new String[]{"javafx.scene.effect.Glow","javafx.scene.shape.Polygon","javafx.scene.transform.Shear",},new String[]{},new String[]{},"/ensemble/samples/graphics/digitalclock/DigitalClockApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
@@ -99,10 +99,10 @@
     private static final SampleInfo SAMPLE_92 = new SampleInfo("Polyline","A sample that demonstrates polyline construction with stroke and fill. ","/Graphics/Shapes/Polyline","/ensemble/samples/graphics/shapes/polyline","ensemble.samples.graphics.shapes.polyline.PolylineApp","/ensemble/samples/graphics/shapes/polyline/preview.png",new String[]{"/ensemble/samples/graphics/shapes/polyline/PolylineApp.java",},new String[]{"javafx.scene.shape.Polyline","javafx.scene.shape.Shape","javafx.scene.paint.Color",},new String[]{},new String[]{},"/ensemble/samples/graphics/shapes/polyline/PolylineApp.java",new PlaygroundProperty[]{new PlaygroundProperty("polyline1","fill","name","Polyline 1 Fill"),new PlaygroundProperty("polyline1","stroke","name","Polyline 1 Stroke"),new PlaygroundProperty("polyline2","stroke","name","Polyline 2 Stroke"),},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_93 = new SampleInfo("Quad Curve","An example of how various settings affect a quadratic B??zier parametric curve. ","/Graphics/Shapes/Quad Curve","/ensemble/samples/graphics/shapes/quadcurve","ensemble.samples.graphics.shapes.quadcurve.QuadCurveApp","/ensemble/samples/graphics/shapes/quadcurve/preview.png",new String[]{"/ensemble/samples/graphics/shapes/quadcurve/QuadCurveApp.java",},new String[]{"javafx.scene.shape.QuadCurve","javafx.scene.shape.Shape","javafx.scene.paint.Color",},new String[]{},new String[]{},"/ensemble/samples/graphics/shapes/quadcurve/QuadCurveApp.java",new PlaygroundProperty[]{new PlaygroundProperty("quadCurve","fill","name","Cubic Curve Fill"),new PlaygroundProperty("quadCurve","stroke","name","Cubic Curve Stroke"),new PlaygroundProperty("quadCurve","startX","min","0","max","170","name","Cubic Curve Start X"),new PlaygroundProperty("quadCurve","startY","min","10","max","80","name","Cubic Curve Start Y"),new PlaygroundProperty("quadCurve","controlX","min","0","max","180","name","Cubic Curve Control X"),new PlaygroundProperty("quadCurve","controlY","min","0","max","90","name","Cubic Curve Control Y"),new PlaygroundProperty("quadCurve","endX","min","10","max","180","name","Cubic Curve End X"),new PlaygroundProperty("quadCurve","endY","min","10","max","80","name","Cubic Curve End Y"),},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_94 = new SampleInfo("Rectangle","A sample showing how various settings effect two rectangles. ","/Graphics/Shapes/Rectangle","/ensemble/samples/graphics/shapes/rectangle","ensemble.samples.graphics.shapes.rectangle.RectangleApp","/ensemble/samples/graphics/shapes/rectangle/preview.png",new String[]{"/ensemble/samples/graphics/shapes/rectangle/RectangleApp.java",},new String[]{"javafx.scene.shape.Rectangle","javafx.scene.shape.Shape","javafx.scene.paint.Color",},new String[]{},new String[]{},"/ensemble/samples/graphics/shapes/rectangle/RectangleApp.java",new PlaygroundProperty[]{new PlaygroundProperty("rect1","fill","name","Rectangle 1 Fill"),new PlaygroundProperty("rect1","width","min","10","max","50","name","Rectangle 1 Width"),new PlaygroundProperty("rect1","height","min","10","max","50","name","Rectangle 1 Height"),new PlaygroundProperty("rect1","arcWidth","min","0","max","50","name","Rectangle 1 Arc Width"),new PlaygroundProperty("rect1","arcHeight","min","0","max","50","name","Rectangle 1 Arc Height"),new PlaygroundProperty("rect2","stroke","name","Rectangle 2 Stroke"),new PlaygroundProperty("rect2","strokeWidth","min","1","max","5","name","Rectangle 2 Stroke Width"),new PlaygroundProperty("rect2","width","min","10","max","50","name","Rectangle 2 Width"),new PlaygroundProperty("rect2","height","min","10","max","50","name","Rectangle 2 Height"),new PlaygroundProperty("rect2","arcWidth","min","0","max","50","name","Rectangle 2 Arc Width"),new PlaygroundProperty("rect2","arcHeight","min","0","max","50","name","Rectangle 2 Arc Height"),},new ConditionalFeature[]{});
-    private static final SampleInfo SAMPLE_95 = new SampleInfo("3D Cubes","A sample that demonstrates an animated rotation of 3D cubes. When the application runs in standalone mode, the scene must be constructed with the depthBuffer argument set to true, and the root node must have depthTest set to true. ","/Graphics 3d/3D Cubes","/ensemble/samples/graphics3d/cube","ensemble.samples.graphics3d.cube.CubeApp","/ensemble/samples/graphics3d/cube/preview.png",new String[]{"/ensemble/samples/graphics3d/cube/Cube.java","/ensemble/samples/graphics3d/cube/CubeApp.java",},new String[]{"javafx.scene.transform.Rotate","javafx.scene.paint.Color","javafx.scene.shape.RectangleBuilder",},new String[]{},new String[]{},"/ensemble/samples/graphics3d/cube/CubeApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
+    private static final SampleInfo SAMPLE_95 = new SampleInfo("3D Cubes","A sample that demonstrates an animated rotation of 3D cubes. When the application runs in standalone mode, the scene must be constructed with the depthBuffer argument set to true, and the root node must have depthTest set to true. ","/Graphics 3d/3D Cubes","/ensemble/samples/graphics3d/cube","ensemble.samples.graphics3d.cube.CubeApp","/ensemble/samples/graphics3d/cube/preview.png",new String[]{"/ensemble/samples/graphics3d/cube/Cube.java","/ensemble/samples/graphics3d/cube/CubeApp.java","/ensemble/samples/graphics3d/cube/CubeApp.java.orig","/ensemble/samples/graphics3d/cube/CubeApp.java.save",},new String[]{"javafx.scene.transform.Rotate","javafx.scene.paint.Color","javafx.scene.shape.RectangleBuilder",},new String[]{},new String[]{},"/ensemble/samples/graphics3d/cube/CubeApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_96 = new SampleInfo("3D Cube System","A sample that demonstrates an animated rotation of 3D cubes. When the application runs in standalone mode, the scene must be constructed with the depthBuffer argument set to true, and the root node must have depthTest set to true. ","/Graphics 3d/3D Cube System","/ensemble/samples/graphics3d/cubesystem","ensemble.samples.graphics3d.cubesystem.CubeSystemApp","/ensemble/samples/graphics3d/cubesystem/preview.png",new String[]{"/ensemble/samples/graphics3d/cubesystem/Cube.java","/ensemble/samples/graphics3d/cubesystem/CubeSystemApp.java","/ensemble/samples/graphics3d/cubesystem/Xform.java",},new String[]{"javafx.scene.transform.Rotate","javafx.scene.paint.Color","javafx.scene.shape.RectangleBuilder",},new String[]{},new String[]{},"/ensemble/samples/graphics3d/cubesystem/CubeSystemApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_97 = new SampleInfo("3D Box","A sample that shows a 3D box and uses a perspective camera for rendering the scene. ","/Graphics 3d/3D Box","/ensemble/samples/graphics3d/simple3dbox","ensemble.samples.graphics3d.simple3dbox.Simple3DBoxApp","/ensemble/samples/graphics3d/simple3dbox/preview.png",new String[]{"/ensemble/samples/graphics3d/simple3dbox/Simple3DBoxApp.java",},new String[]{"javafx.scene.paint.Color","javafx.scene.transform.Rotate","javafx.scene.transform.Translate",},new String[]{},new String[]{},"/ensemble/samples/graphics3d/simple3dbox/Simple3DBoxApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
-    private static final SampleInfo SAMPLE_98 = new SampleInfo("Xylophone","A sample that demonstrates a xylophone made of 3D cubes. When the application runs in standalone mode, the scene must be constructed with the depthBuffer argument set to true, and the root node must have depthTest set to true. ","/Graphics 3d/Xylophone","/ensemble/samples/graphics3d/xylophone","ensemble.samples.graphics3d.xylophone.XylophoneApp","/ensemble/samples/graphics3d/xylophone/preview.png",new String[]{"/ensemble/samples/graphics3d/xylophone/Cube.java","/ensemble/samples/graphics3d/xylophone/Xform.java","/ensemble/samples/shared-resources/Note1.wav","/ensemble/samples/shared-resources/Note2.wav","/ensemble/samples/shared-resources/Note3.wav","/ensemble/samples/shared-resources/Note4.wav","/ensemble/samples/shared-resources/Note5.wav","/ensemble/samples/shared-resources/Note6.wav","/ensemble/samples/shared-resources/Note7.wav","/ensemble/samples/shared-resources/Note8.wav","/ensemble/samples/graphics3d/xylophone/XylophoneApp.java",},new String[]{"javafx.scene.transform.Rotate","javafx.scene.paint.Color","javafx.scene.shape.RectangleBuilder",},new String[]{},new String[]{},"/ensemble/samples/graphics3d/xylophone/XylophoneApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
+    private static final SampleInfo SAMPLE_98 = new SampleInfo("Xylophone","A sample that demonstrates a xylophone made of 3D cubes. ","/Graphics 3d/Xylophone","/ensemble/samples/graphics3d/xylophone","ensemble.samples.graphics3d.xylophone.XylophoneApp","/ensemble/samples/graphics3d/xylophone/preview.png",new String[]{"/ensemble/samples/graphics3d/xylophone/Cube.java","/ensemble/samples/graphics3d/xylophone/Xform.java","/ensemble/samples/shared-resources/Note1.wav","/ensemble/samples/shared-resources/Note2.wav","/ensemble/samples/shared-resources/Note3.wav","/ensemble/samples/shared-resources/Note4.wav","/ensemble/samples/shared-resources/Note5.wav","/ensemble/samples/shared-resources/Note6.wav","/ensemble/samples/shared-resources/Note7.wav","/ensemble/samples/shared-resources/Note8.wav","/ensemble/samples/graphics3d/xylophone/XylophoneApp.java","/ensemble/samples/graphics3d/xylophone/XylophoneApp.java.alex","/ensemble/samples/graphics3d/xylophone/XylophoneApp.java.baseGroupTransform","/ensemble/samples/graphics3d/xylophone/XylophoneApp.java.saveAlexsPlusTests","/ensemble/samples/graphics3d/xylophone/XylophoneApp.java.subScene",},new String[]{"javafx.scene.transform.Rotate","javafx.scene.paint.Color","javafx.scene.PerspectiveCamera","javafx.scene.shape.RectangleBuilder","javafx.scene.SubScene",},new String[]{},new String[]{},"/ensemble/samples/graphics3d/xylophone/XylophoneApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_99 = new SampleInfo("ChangeListener","A sample that demonstrates how to add or remove a change listener on a node (for example, a Rectangle node) for some property (for example, Rectangle.hover). Once you add a listener, the text field  shows the hover property change. ","/Language/Beans/ChangeListener","/ensemble/samples/language/beans/changelistener","ensemble.samples.language.beans.changelistener.ChangeListenerApp","/ensemble/samples/language/beans/changelistener/preview.png",new String[]{"/ensemble/samples/language/beans/changelistener/ChangeListenerApp.java",},new String[]{"javafx.beans.value.ChangeListener","javafx.beans.InvalidationListener","javafx.beans.value.ObservableValue",},new String[]{},new String[]{},"/ensemble/samples/language/beans/changelistener/ChangeListenerApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_100 = new SampleInfo("String Binding","A sample that demonstrates how to bind text properties so the value of the bound property is updated automatically when the value of the original property is changed. ","/Language/Beans/String Binding","/ensemble/samples/language/beans/stringbinding","ensemble.samples.language.beans.stringbinding.StringBindingApp","/ensemble/samples/language/beans/stringbinding/preview.png",new String[]{"/ensemble/samples/language/beans/stringbinding/StringBindingApp.java",},new String[]{"javafx.beans.binding.StringBinding","javafx.scene.control.TextField","javafx.scene.control.Label",},new String[]{},new String[]{},"/ensemble/samples/language/beans/stringbinding/StringBindingApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_101 = new SampleInfo("ObservableList","A sample that demonstrates the ObservableList interface, which extends the java.util.List interface. Click the button to change an integer to a new random number in a random position in the list. Once you add a listener, the index of the changed number is displayed to the left of the list. ","/Language/Collections/ObservableList","/ensemble/samples/language/collections/observablelist","ensemble.samples.language.collections.observablelist.ObservableListApp","/ensemble/samples/language/collections/observablelist/preview.png",new String[]{"/ensemble/samples/language/collections/observablelist/ObservableListApp.java",},new String[]{"javafx.beans.value.ChangeListener","javafx.collections.FXCollections","javafx.collections.ListChangeListener","javafx.collections.ObservableList",},new String[]{},new String[]{},"/ensemble/samples/language/collections/observablelist/ObservableListApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
@@ -114,18 +114,18 @@
     private static final SampleInfo SAMPLE_107 = new SampleInfo("StackPane","A simple example of a StackPane layout. ","/Layout/StackPane","/ensemble/samples/layout/stackpane","ensemble.samples.layout.stackpane.StackPaneApp","/ensemble/samples/layout/stackpane/preview.png",new String[]{"/ensemble/samples/layout/stackpane/StackPaneApp.java",},new String[]{"javafx.scene.layout.StackPane",},new String[]{},new String[]{},"/ensemble/samples/layout/stackpane/StackPaneApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_108 = new SampleInfo("TilePane","An example of a TilePane layout. ","/Layout/TilePane","/ensemble/samples/layout/tilepane","ensemble.samples.layout.tilepane.TilePaneApp","/ensemble/samples/layout/tilepane/preview.png",new String[]{"/ensemble/samples/shared-resources/icon-48x48.png","/ensemble/samples/layout/tilepane/TilePaneApp.java",},new String[]{"javafx.scene.layout.TilePane",},new String[]{},new String[]{"/Graphics/Images/Image Creation",},"/ensemble/samples/layout/tilepane/TilePaneApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_109 = new SampleInfo("VBox","A simple example of a VBox layout. ","/Layout/VBox","/ensemble/samples/layout/vbox","ensemble.samples.layout.vbox.VBoxApp","/ensemble/samples/layout/vbox/preview.png",new String[]{"/ensemble/samples/layout/vbox/VBoxApp.java",},new String[]{"javafx.scene.layout.VBox",},new String[]{},new String[]{},"/ensemble/samples/layout/vbox/VBoxApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
-    private static final SampleInfo SAMPLE_110 = new SampleInfo("Advanced Media","An advanced media player with controls for play/pause, seek, and volume. ","/Media/Advanced Media","/ensemble/samples/media/advancedmedia","ensemble.samples.media.advancedmedia.AdvancedMediaApp","/ensemble/samples/media/advancedmedia/preview.png",new String[]{"/ensemble/samples/media/advancedmedia/AdvancedMediaApp.java","/ensemble/samples/shared-resources/playbutton.png","/ensemble/samples/shared-resources/pausebutton.png","/ensemble/samples/media/advancedmedia/MediaControl.java",},new String[]{"javafx.scene.media.MediaPlayer","javafx.scene.media.Media",},new String[]{},new String[]{"/Media/Alpha Media Player","/Media/Overlay Media Player","/Media/Streaming Media Player",},"/ensemble/samples/media/advancedmedia/AdvancedMediaApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{ConditionalFeature.WEB,});
+    private static final SampleInfo SAMPLE_110 = new SampleInfo("Advanced Media","An advanced media player with controls for play/pause, seek, and volume. ","/Media/Advanced Media","/ensemble/samples/media/advancedmedia","ensemble.samples.media.advancedmedia.AdvancedMediaApp","/ensemble/samples/media/advancedmedia/preview.png",new String[]{"/ensemble/samples/media/advancedmedia/AdvancedMediaApp.java","/ensemble/samples/media/advancedmedia/AdvancedMediaApp.java.orig","/ensemble/samples/media/advancedmedia/AdvancedMediaApp.java.save","/ensemble/samples/shared-resources/playbutton.png","/ensemble/samples/shared-resources/pausebutton.png","/ensemble/samples/media/advancedmedia/MediaControl.java","/ensemble/samples/media/advancedmedia/MediaControl.java.fixed","/ensemble/samples/media/advancedmedia/MediaControl.java.orig",},new String[]{"javafx.scene.media.MediaPlayer","javafx.scene.media.Media",},new String[]{},new String[]{"/Media/Alpha Media Player","/Media/Overlay Media Player","/Media/Streaming Media Player",},"/ensemble/samples/media/advancedmedia/AdvancedMediaApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{ConditionalFeature.WEB,});
     private static final SampleInfo SAMPLE_111 = new SampleInfo("Alpha Media Player","An alpha media player with 2 different media views and alpha channels. ","/Media/Alpha Media Player","/ensemble/samples/media/alphamediaplayer","ensemble.samples.media.alphamediaplayer.AlphaMediaPlayerApp","/ensemble/samples/media/alphamediaplayer/preview.png",new String[]{"/ensemble/samples/media/alphamediaplayer/AlphaMediaPlayerApp.java","/ensemble/samples/media/alphamediaplayer/PlanetaryPlayerPane.java","/ensemble/samples/media/alphamediaplayer/AlphaMediaPlayer.css",},new String[]{"javafx.scene.media.MediaPlayer","javafx.scene.media.Media",},new String[]{},new String[]{"/Media/Advanced Media","/Media/Overlay Media Player","/Media/Streaming Media Player",},"/ensemble/samples/media/alphamediaplayer/AlphaMediaPlayerApp.java",new PlaygroundProperty[]{new PlaygroundProperty(null,"arthPos","min","-100","max","100","name","Arth Position"),new PlaygroundProperty(null,"fierPos","min","-100","max","100","name","Fier Position"),new PlaygroundProperty(null,"arthRate","min","0.1","max","1","name","Arth Rate"),new PlaygroundProperty(null,"fierRate","min","0.1","max","1","name","Fier Rate"),},new ConditionalFeature[]{ConditionalFeature.WEB,});
-    private static final SampleInfo SAMPLE_112 = new SampleInfo("Audio Clip","A sample that demonstrates the basics of AudioClips. ","/Media/Audio Clip","/ensemble/samples/media/audioclip","ensemble.samples.media.audioclip.AudioClipApp","/ensemble/samples/media/audioclip/preview.png",new String[]{"/ensemble/samples/shared-resources/Note1.wav","/ensemble/samples/shared-resources/Note2.wav","/ensemble/samples/shared-resources/Note3.wav","/ensemble/samples/shared-resources/Note4.wav","/ensemble/samples/shared-resources/Note5.wav","/ensemble/samples/shared-resources/Note6.wav","/ensemble/samples/shared-resources/Note7.wav","/ensemble/samples/shared-resources/Note8.wav","/ensemble/samples/media/audioclip/AudioClipApp.java","/ensemble/samples/media/audioclip/AudioClipApp.java.orig",},new String[]{"javafx.scene.media.AudioClip",},new String[]{},new String[]{"/Graphics3d/Xylophone",},"/ensemble/samples/media/audioclip/AudioClipApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{ConditionalFeature.WEB,});
+    private static final SampleInfo SAMPLE_112 = new SampleInfo("Audio Clip","A sample that demonstrates the basics of AudioClips. ","/Media/Audio Clip","/ensemble/samples/media/audioclip","ensemble.samples.media.audioclip.AudioClipApp","/ensemble/samples/media/audioclip/preview.png",new String[]{"/ensemble/samples/shared-resources/Note1.wav","/ensemble/samples/shared-resources/Note2.wav","/ensemble/samples/shared-resources/Note3.wav","/ensemble/samples/shared-resources/Note4.wav","/ensemble/samples/shared-resources/Note5.wav","/ensemble/samples/shared-resources/Note6.wav","/ensemble/samples/shared-resources/Note7.wav","/ensemble/samples/shared-resources/Note8.wav","/ensemble/samples/media/audioclip/AudioClipApp.java",},new String[]{"javafx.scene.media.AudioClip",},new String[]{},new String[]{"/Graphics3d/Xylophone",},"/ensemble/samples/media/audioclip/AudioClipApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{ConditionalFeature.WEB,});
     private static final SampleInfo SAMPLE_113 = new SampleInfo("Overlay Media Player","A media player with controls for play, pause, stop, seek, and volume. This media player also demonstrates overlaying the player controls on top of the media. ","/Media/Overlay Media Player","/ensemble/samples/media/overlaymediaplayer","ensemble.samples.media.overlaymediaplayer.OverlayMediaPlayerApp","/ensemble/samples/media/overlaymediaplayer/preview.png",new String[]{"/ensemble/samples/media/overlaymediaplayer/OverlayMediaPlayerApp.java","/ensemble/samples/media/overlaymediaplayer/PlayerPane.java","/ensemble/samples/media/overlaymediaplayer/OverlayMediaPlayer.css",},new String[]{"javafx.scene.media.MediaPlayer","javafx.scene.media.Media",},new String[]{},new String[]{"/Media/Advanced Media","/Media/Alpha Media Player","/Media/Streaming Media Player",},"/ensemble/samples/media/overlaymediaplayer/OverlayMediaPlayerApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{ConditionalFeature.WEB,});
     private static final SampleInfo SAMPLE_114 = new SampleInfo("Streaming Media Player","A media player with controls for play, pause, stop, seek, and volume. This media player is playing media via HTTP Live Streaming, also known as HLS. ","/Media/Streaming Media Player","/ensemble/samples/media/streamingmediaplayer","ensemble.samples.media.streamingmediaplayer.StreamingMediaPlayerApp","/ensemble/samples/media/streamingmediaplayer/preview.png",new String[]{"/ensemble/samples/media/streamingmediaplayer/PlayerPane.java","/ensemble/samples/media/streamingmediaplayer/StreamingMediaPlayerApp.java","/ensemble/samples/media/streamingmediaplayer/StreamingMediaPlayer.css",},new String[]{"javafx.scene.media.MediaPlayer","javafx.scene.media.Media",},new String[]{},new String[]{"/Media/Advanced Media","/Media/Alpha Media Player","/Media/Overlay Media Player",},"/ensemble/samples/media/streamingmediaplayer/StreamingMediaPlayerApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{ConditionalFeature.WEB,});
-    private static final SampleInfo SAMPLE_115 = new SampleInfo("Cursor","A sample that demonstrates changing the cursor icon. ","/Scenegraph/Events/Cursor","/ensemble/samples/scenegraph/events/cursor","ensemble.samples.scenegraph.events.cursor.CursorApp","/ensemble/samples/scenegraph/events/cursor/preview.png",new String[]{"/ensemble/samples/scenegraph/events/cursor/CursorApp.java","/ensemble/samples/scenegraph/events/cursor/CursorApp.java.orig",},new String[]{"javafx.scene.Cursor",},new String[]{},new String[]{},"/ensemble/samples/scenegraph/events/cursor/CursorApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
+    private static final SampleInfo SAMPLE_115 = new SampleInfo("Cursor","A sample that demonstrates changing the cursor icon. ","/Scenegraph/Events/Cursor","/ensemble/samples/scenegraph/events/cursor","ensemble.samples.scenegraph.events.cursor.CursorApp","/ensemble/samples/scenegraph/events/cursor/preview.png",new String[]{"/ensemble/samples/scenegraph/events/cursor/CursorApp.java",},new String[]{"javafx.scene.Cursor",},new String[]{},new String[]{},"/ensemble/samples/scenegraph/events/cursor/CursorApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_116 = new SampleInfo("Gesture Event","A sample that demonstrates various gesture events and their usage. Scroll the rectangle or the background behind the rectangle to move the rectangle itself. Similarly, rotate, zoom in, or zoom out the rectangle. All events are logged to the console. ","/Scenegraph/Events/Gesture Event","/ensemble/samples/scenegraph/events/gestureevent","ensemble.samples.scenegraph.events.gestureevent.GestureEventApp","/ensemble/samples/scenegraph/events/gestureevent/preview.png",new String[]{"/ensemble/samples/scenegraph/events/gestureevent/GestureEventApp.java",},new String[]{"javafx.collections.ObservableList","javafx.scene.Cursor","javafx.scene.input.GestureEvent","javafx.scene.input.RotateEvent","javafx.scene.input.ScrollEvent","javafx.scene.input.SwipeEvent","javafx.scene.input.ZoomEvent","javafx.event.EventHandler",},new String[]{},new String[]{"/Scenegraph/Events/MouseEvent",},"/ensemble/samples/scenegraph/events/gestureevent/GestureEventApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_117 = new SampleInfo("KeyEvent","A sample that demonstrates various key events and their usage. Type in the text box to view the triggered events: key pressed, key typed and key released. Pressing the Shift, Ctrl, and Alt keys also trigger events. ","/Scenegraph/Events/KeyEvent","/ensemble/samples/scenegraph/events/keyevent","ensemble.samples.scenegraph.events.keyevent.KeyEventApp","/ensemble/samples/scenegraph/events/keyevent/preview.png",new String[]{"/ensemble/samples/scenegraph/events/keyevent/KeyEventApp.java",},new String[]{"javafx.scene.input.KeyCode","javafx.scene.input.KeyEvent","javafx.event.EventHandler",},new String[]{},new String[]{},"/ensemble/samples/scenegraph/events/keyevent/KeyEventApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_118 = new SampleInfo("Key Stroke Motion","An example of animation generated from key events. Click the grey area to give it focus and try typing letters. ","/Scenegraph/Events/Key Stroke Motion","/ensemble/samples/scenegraph/events/keystrokemotion","ensemble.samples.scenegraph.events.keystrokemotion.KeyStrokeMotionApp","/ensemble/samples/scenegraph/events/keystrokemotion/preview.png",new String[]{"/ensemble/samples/scenegraph/events/keystrokemotion/KeyStrokeMotionApp.java","/ensemble/samples/scenegraph/events/keystrokemotion/LettersPane.java",},new String[]{"javafx.scene.input.KeyEvent","javafx.animation.Interpolator",},new String[]{},new String[]{},"/ensemble/samples/scenegraph/events/keystrokemotion/KeyStrokeMotionApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_119 = new SampleInfo("MouseEvent","A sample that demonstrates various mouse and scroll events and their usage. Click the circles and drag them across the screen. Scroll the whole screen. All events are logged to the console. ","/Scenegraph/Events/MouseEvent","/ensemble/samples/scenegraph/events/mouseevent","ensemble.samples.scenegraph.events.mouseevent.MouseEventApp","/ensemble/samples/scenegraph/events/mouseevent/preview.png",new String[]{"/ensemble/samples/scenegraph/events/mouseevent/MouseEventApp.java",},new String[]{"javafx.scene.Cursor","javafx.scene.input.MouseEvent","javafx.event.EventHandler",},new String[]{},new String[]{},"/ensemble/samples/scenegraph/events/mouseevent/MouseEventApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_120 = new SampleInfo("Multi-Touch","A sample that demonstrates multi-touch support. You can zoom in and out of the images and also rotate the images with multi-touch. ","/Scenegraph/Events/Multi-Touch","/ensemble/samples/scenegraph/events/multitouch","ensemble.samples.scenegraph.events.multitouch.MultiTouchApp","/ensemble/samples/scenegraph/events/multitouch/preview.png",new String[]{"/ensemble/samples/scenegraph/events/multitouch/MultiTouchApp.java","/ensemble/samples/scenegraph/events/multitouch/MultiTouchImageView.java","/ensemble/samples/shared-resources/warning.png","/ensemble/samples/shared-resources/Animal1.jpg","/ensemble/samples/shared-resources/Animal2.jpg","/ensemble/samples/shared-resources/Animal3.jpg","/ensemble/samples/scenegraph/events/multitouch/MultiTouchPane.java",},new String[]{"javafx.scene.input.MouseEvent","javafx.event.EventHandler","javafx.scene.input.RotateEvent","javafx.scene.input.ZoomEvent",},new String[]{},new String[]{},"/ensemble/samples/scenegraph/events/multitouch/MultiTouchApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{ConditionalFeature.INPUT_MULTITOUCH,});
-    private static final SampleInfo SAMPLE_121 = new SampleInfo("Custom Node","A sample that demonstrates how to create a custom node by extending the Parent class. ","/Scenegraph/Node/Custom Node","/ensemble/samples/scenegraph/node/customnode","ensemble.samples.scenegraph.node.customnode.CustomNodeApp","/ensemble/samples/scenegraph/node/customnode/preview.png",new String[]{"/ensemble/samples/scenegraph/node/customnode/CustomNodeApp.java","/ensemble/samples/scenegraph/node/customnode/CustomNodeApp.java.orig","/ensemble/samples/scenegraph/node/customnode/MyNode.java",},new String[]{"javafx.scene.Parent","javafx.scene.Node",},new String[]{},new String[]{},"/ensemble/samples/scenegraph/node/customnode/CustomNodeApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
+    private static final SampleInfo SAMPLE_121 = new SampleInfo("Custom Node","A sample that demonstrates how to create a custom node by extending the Parent class. ","/Scenegraph/Node/Custom Node","/ensemble/samples/scenegraph/node/customnode","ensemble.samples.scenegraph.node.customnode.CustomNodeApp","/ensemble/samples/scenegraph/node/customnode/preview.png",new String[]{"/ensemble/samples/scenegraph/node/customnode/CustomNodeApp.java","/ensemble/samples/scenegraph/node/customnode/MyNode.java",},new String[]{"javafx.scene.Parent","javafx.scene.Node",},new String[]{},new String[]{},"/ensemble/samples/scenegraph/node/customnode/CustomNodeApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_122 = new SampleInfo("Node Properties","A sample that demonstrates some properties of nodes. Use the radio buttons to send any of the rectangles to the front or back. Use the controls to change opacity or horizontal position. ","/Scenegraph/Node/Node Properties","/ensemble/samples/scenegraph/node/nodeproperties","ensemble.samples.scenegraph.node.nodeproperties.NodePropertiesApp","/ensemble/samples/scenegraph/node/nodeproperties/preview.png",new String[]{"/ensemble/samples/scenegraph/node/nodeproperties/NodePropertiesApp.java",},new String[]{"javafx.scene.Node",},new String[]{},new String[]{},"/ensemble/samples/scenegraph/node/nodeproperties/NodePropertiesApp.java",new PlaygroundProperty[]{new PlaygroundProperty("rectA","translateX","min","0","max","50","name","Rectangle A translate X"),new PlaygroundProperty("rectB","translateX","min","0","max","50","name","Rectangle B translate X"),new PlaygroundProperty("rectC","translateX","min","0","max","50","name","Rectangle C translate X"),new PlaygroundProperty("rectA","opacity","min","0","max","1","name","Rectangle A Opacity"),new PlaygroundProperty("rectB","opacity","min","0","max","1","name","Rectangle B Opacity"),new PlaygroundProperty("rectC","opacity","min","0","max","1","name","Rectangle C Opacity"),},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_123 = new SampleInfo("Advanced Stage","A sample with a control that creates a transparent stage that is centered on your desktop. You can drag the stage with your mouse or use the scene controls to minimize or close it. With a transparent stage, you must add your own event handlers to perform these actions. ","/Scenegraph/Stage/Advanced Stage","/ensemble/samples/scenegraph/stage/advancedstage","ensemble.samples.scenegraph.stage.advancedstage.AdvancedStageApp","/ensemble/samples/scenegraph/stage/advancedstage/preview.png",new String[]{"/ensemble/samples/scenegraph/stage/advancedstage/AdvancedStageApp.java",},new String[]{"javafx.stage.Stage","javafx.scene.Scene","javafx.stage.StageStyle","javafx.application.Platform",},new String[]{},new String[]{"/Scenegraph/Stage/Stage",},"/ensemble/samples/scenegraph/stage/advancedstage/AdvancedStageApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
     private static final SampleInfo SAMPLE_124 = new SampleInfo("Stage","A sample with a control that creates a decorated stage that is centered on your desktop. ","/Scenegraph/Stage/Stage","/ensemble/samples/scenegraph/stage/stage","ensemble.samples.scenegraph.stage.stage.StageApp","/ensemble/samples/scenegraph/stage/stage/preview.png",new String[]{"/ensemble/samples/scenegraph/stage/stage/StageApp.java",},new String[]{"javafx.stage.Stage","javafx.scene.Scene",},new String[]{},new String[]{"/Scenegraph/Stage/Advanced Stage",},"/ensemble/samples/scenegraph/stage/stage/StageApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{});
@@ -134,7 +134,7 @@
     private static final SampleInfo SAMPLE_127 = new SampleInfo("WebView","A sample that demonstrates a WebView object accessing a web page. ","/Web/WebView","/ensemble/samples/web/webview","ensemble.samples.web.webview.WebViewApp","/ensemble/samples/web/webview/preview.png",new String[]{"/ensemble/samples/web/webview/WebViewApp.java",},new String[]{"javafx.scene.web.WebView","javafx.scene.web.WebEngine",},new String[]{},new String[]{},"/ensemble/samples/web/webview/WebViewApp.java",new PlaygroundProperty[]{},new ConditionalFeature[]{ConditionalFeature.WEB,});
     public static final SampleCategory ROOT = new SampleCategory("ROOT",null,null,new SampleCategory[]{new SampleCategory("Animation",new SampleInfo[]{SAMPLE_0,},new SampleInfo[]{SAMPLE_0,SAMPLE_1,SAMPLE_2,SAMPLE_3,SAMPLE_4,SAMPLE_5,SAMPLE_6,SAMPLE_7,SAMPLE_8,SAMPLE_9,SAMPLE_10,SAMPLE_11,SAMPLE_12,},new SampleCategory[]{new SampleCategory("Timeline",new SampleInfo[]{SAMPLE_1,SAMPLE_2,},null,null),new SampleCategory("Transitions",new SampleInfo[]{SAMPLE_3,SAMPLE_4,SAMPLE_5,SAMPLE_6,SAMPLE_7,SAMPLE_8,SAMPLE_9,SAMPLE_10,SAMPLE_11,SAMPLE_12,},null,null),}),new SampleCategory("Canvas",new SampleInfo[]{SAMPLE_13,},new SampleInfo[]{SAMPLE_13,},null),new SampleCategory("Charts",null,new SampleInfo[]{SAMPLE_14,SAMPLE_15,SAMPLE_16,SAMPLE_17,SAMPLE_18,SAMPLE_19,SAMPLE_20,SAMPLE_21,SAMPLE_22,SAMPLE_23,SAMPLE_24,SAMPLE_25,SAMPLE_26,SAMPLE_27,SAMPLE_28,SAMPLE_29,SAMPLE_30,SAMPLE_31,},new SampleCategory[]{new SampleCategory("Area",new SampleInfo[]{SAMPLE_14,SAMPLE_15,SAMPLE_16,SAMPLE_17,},null,null),new SampleCategory("Bar",new SampleInfo[]{SAMPLE_18,SAMPLE_19,SAMPLE_20,SAMPLE_21,SAMPLE_22,},null,null),new SampleCategory("Bubble",new SampleInfo[]{SAMPLE_23,},null,null),new SampleCategory("Custom",new SampleInfo[]{SAMPLE_24,},null,null),new SampleCategory("Line",new SampleInfo[]{SAMPLE_25,SAMPLE_26,SAMPLE_27,},null,null),new SampleCategory("Pie",new SampleInfo[]{SAMPLE_28,SAMPLE_29,},null,null),new SampleCategory("Scatter",new SampleInfo[]{SAMPLE_30,SAMPLE_31,},null,null),}),new SampleCategory("Concurrency",new SampleInfo[]{SAMPLE_32,SAMPLE_33,},new SampleInfo[]{SAMPLE_32,SAMPLE_33,},null),new SampleCategory("Controls",new SampleInfo[]{SAMPLE_34,SAMPLE_35,SAMPLE_36,SAMPLE_37,SAMPLE_38,SAMPLE_39,SAMPLE_40,SAMPLE_41,SAMPLE_42,SAMPLE_43,SAMPLE_44,SAMPLE_45,SAMPLE_46,},new SampleInfo[]{SAMPLE_34,SAMPLE_47,SAMPLE_48,SAMPLE_49,SAMPLE_35,SAMPLE_36,SAMPLE_37,SAMPLE_38,SAMPLE_50,SAMPLE_51,SAMPLE_52,SAMPLE_39,SAMPLE_40,SAMPLE_41,SAMPLE_42,SAMPLE_43,SAMPLE_44,SAMPLE_53,SAMPLE_54,SAMPLE_55,SAMPLE_56,SAMPLE_57,SAMPLE_58,SAMPLE_59,SAMPLE_60,SAMPLE_61,SAMPLE_62,SAMPLE_45,SAMPLE_63,SAMPLE_64,SAMPLE_46,},new SampleCategory[]{new SampleCategory("Button",new SampleInfo[]{SAMPLE_47,SAMPLE_48,SAMPLE_49,},null,null),new SampleCategory("Listview",new SampleInfo[]{SAMPLE_50,SAMPLE_51,SAMPLE_52,},null,null),new SampleCategory("Splitpane",new SampleInfo[]{SAMPLE_53,},null,null),new SampleCategory("Tab",new SampleInfo[]{SAMPLE_54,},null,null),new SampleCategory("Table",new SampleInfo[]{SAMPLE_55,SAMPLE_56,},null,null),new SampleCategory("Text",new SampleInfo[]{SAMPLE_57,SAMPLE_58,SAMPLE_59,SAMPLE_60,SAMPLE_61,SAMPLE_62,},null,null),new SampleCategory("Toolbar",new SampleInfo[]{SAMPLE_63,SAMPLE_64,},null,null),}),new SampleCategory("Fxml",new SampleInfo[]{SAMPLE_65,},new SampleInfo[]{SAMPLE_65,},null),new SampleCategory("Graphics",new SampleInfo[]{SAMPLE_66,SAMPLE_67,SAMPLE_68,SAMPLE_69,SAMPLE_70,SAMPLE_71,SAMPLE_72,SAMPLE_73,},new SampleInfo[]{SAMPLE_66,SAMPLE_67,SAMPLE_68,SAMPLE_69,SAMPLE_70,SAMPLE_71,SAMPLE_74,SAMPLE_75,SAMPLE_76,SAMPLE_77,SAMPLE_78,SAMPLE_79,SAMPLE_80,SAMPLE_81,SAMPLE_82,SAMPLE_83,SAMPLE_84,SAMPLE_72,SAMPLE_85,SAMPLE_86,SAMPLE_87,SAMPLE_88,SAMPLE_89,SAMPLE_90,SAMPLE_91,SAMPLE_92,SAMPLE_93,SAMPLE_94,SAMPLE_73,},new SampleCategory[]{new SampleCategory("Effects",new SampleInfo[]{SAMPLE_74,SAMPLE_75,SAMPLE_76,SAMPLE_77,SAMPLE_78,},null,null),new SampleCategory("Images",new SampleInfo[]{SAMPLE_79,SAMPLE_80,SAMPLE_81,},null,null),new SampleCategory("Paints",new SampleInfo[]{SAMPLE_82,SAMPLE_83,SAMPLE_84,},null,null),new SampleCategory("Shapes",new SampleInfo[]{SAMPLE_85,SAMPLE_86,SAMPLE_87,SAMPLE_88,SAMPLE_89,SAMPLE_90,SAMPLE_91,SAMPLE_92,SAMPLE_93,SAMPLE_94,},null,null),}),new SampleCategory("Graphics 3d",new SampleInfo[]{SAMPLE_95,SAMPLE_96,SAMPLE_97,SAMPLE_98,},new SampleInfo[]{SAMPLE_95,SAMPLE_96,SAMPLE_97,SAMPLE_98,},null),new SampleCategory("Language",null,new SampleInfo[]{SAMPLE_99,SAMPLE_100,SAMPLE_101,},new SampleCategory[]{new SampleCategory("Beans",new SampleInfo[]{SAMPLE_99,SAMPLE_100,},null,null),new SampleCategory("Collections",new SampleInfo[]{SAMPLE_101,},null,null),}),new SampleCategory("Layout",new SampleInfo[]{SAMPLE_102,SAMPLE_103,SAMPLE_104,SAMPLE_105,SAMPLE_106,SAMPLE_107,SAMPLE_108,SAMPLE_109,},new SampleInfo[]{SAMPLE_102,SAMPLE_103,SAMPLE_104,SAMPLE_105,SAMPLE_106,SAMPLE_107,SAMPLE_108,SAMPLE_109,},null),new SampleCategory("Media",new SampleInfo[]{SAMPLE_110,SAMPLE_111,SAMPLE_112,SAMPLE_113,SAMPLE_114,},new SampleInfo[]{SAMPLE_110,SAMPLE_111,SAMPLE_112,SAMPLE_113,SAMPLE_114,},null),new SampleCategory("Scenegraph",null,new SampleInfo[]{SAMPLE_115,SAMPLE_116,SAMPLE_117,SAMPLE_118,SAMPLE_119,SAMPLE_120,SAMPLE_121,SAMPLE_122,SAMPLE_123,SAMPLE_124,},new SampleCategory[]{new SampleCategory("Events",new SampleInfo[]{SAMPLE_115,SAMPLE_116,SAMPLE_117,SAMPLE_118,SAMPLE_119,SAMPLE_120,},null,null),new SampleCategory("Node",new SampleInfo[]{SAMPLE_121,SAMPLE_122,},null,null),new SampleCategory("Stage",new SampleInfo[]{SAMPLE_123,SAMPLE_124,},null,null),}),new SampleCategory("Swing",new SampleInfo[]{SAMPLE_125,},new SampleInfo[]{SAMPLE_125,},null),new SampleCategory("Web",new SampleInfo[]{SAMPLE_126,SAMPLE_127,},new SampleInfo[]{SAMPLE_126,SAMPLE_127,},null),});
     public static final SampleInfo[] HIGHLIGHTS = new SampleInfo[]{SAMPLE_24,SAMPLE_112,};
-    private static final HashMap<String,SampleInfo[]> DOCS_URL_TO_SAMPLE = new HashMap<String,SampleInfo[]>(168);
+    private static final HashMap<String,SampleInfo[]> DOCS_URL_TO_SAMPLE = new HashMap<String,SampleInfo[]>(170);
     static {
         DOCS_URL_TO_SAMPLE.put("javafx.animation.PauseTransition",new SampleInfo[]{SAMPLE_7,});
         DOCS_URL_TO_SAMPLE.put("java.io.InputStream",new SampleInfo[]{SAMPLE_65,});
@@ -176,6 +176,7 @@
         DOCS_URL_TO_SAMPLE.put("javafx.animation.ParallelTransition",new SampleInfo[]{SAMPLE_5,});
         DOCS_URL_TO_SAMPLE.put("javafx.beans.value.ObservableValue",new SampleInfo[]{SAMPLE_99,});
         DOCS_URL_TO_SAMPLE.put("javafx.scene.transform.Shear",new SampleInfo[]{SAMPLE_70,});
+        DOCS_URL_TO_SAMPLE.put("javafx.scene.SubScene",new SampleInfo[]{SAMPLE_98,});
         DOCS_URL_TO_SAMPLE.put("javafx.scene.media.Media",new SampleInfo[]{SAMPLE_114,SAMPLE_113,SAMPLE_111,SAMPLE_18,SAMPLE_110,SAMPLE_14,});
         DOCS_URL_TO_SAMPLE.put("javafx.scene.chart.XYChart",new SampleInfo[]{SAMPLE_125,SAMPLE_24,SAMPLE_18,SAMPLE_14,});
         DOCS_URL_TO_SAMPLE.put("javafx.scene.control.Hyperlink",new SampleInfo[]{SAMPLE_38,});
@@ -196,6 +197,7 @@
         DOCS_URL_TO_SAMPLE.put("javafx.scene.input.KeyCode",new SampleInfo[]{SAMPLE_117,});
         DOCS_URL_TO_SAMPLE.put("javafx.scene.shape.Ellipse",new SampleInfo[]{SAMPLE_73,SAMPLE_88,});
         DOCS_URL_TO_SAMPLE.put("java.util.HashMap",new SampleInfo[]{SAMPLE_65,});
+        DOCS_URL_TO_SAMPLE.put("javafx.scene.PerspectiveCamera",new SampleInfo[]{SAMPLE_98,});
         DOCS_URL_TO_SAMPLE.put("javafx.scene.control.Menu",new SampleInfo[]{SAMPLE_39,});
         DOCS_URL_TO_SAMPLE.put("javafx.scene.media.AudioClip",new SampleInfo[]{SAMPLE_112,});
         DOCS_URL_TO_SAMPLE.put("javafx.scene.control.TabBuilder",new SampleInfo[]{SAMPLE_54,});
--- a/apps/samples/Ensemble8/src/samples/java/ensemble/samples/graphics3d/xylophone/XylophoneApp.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/apps/samples/Ensemble8/src/samples/java/ensemble/samples/graphics3d/xylophone/XylophoneApp.java	Tue Aug 27 09:36:40 2013 -0700
@@ -40,24 +40,26 @@
 import javafx.event.EventHandler;
 import javafx.scene.Group;
 import javafx.scene.Parent;
+import javafx.scene.PerspectiveCamera;
 import javafx.scene.Scene;
+import javafx.scene.SubScene;
 import javafx.scene.input.MouseEvent;
 import javafx.scene.media.AudioClip;
 import javafx.scene.paint.Color;
+import javafx.scene.transform.Rotate;
 import javafx.stage.Stage;
 import javafx.util.Duration;
 
 /**
- * A sample that demonstrates a xylophone made of 3D cubes. When the
- * application runs in standalone mode, the scene must be constructed with
- * the depthBuffer argument set to true, and the root node must have depthTest
- * set to true.
+ * A sample that demonstrates a xylophone made of 3D cubes.
  *
  * @sampleName Xylophone
  * @preview preview.png
  * @see javafx.scene.transform.Rotate
  * @see javafx.scene.paint.Color
+ * @see javafx.scene.PerspectiveCamera
  * @see javafx.scene.shape.RectangleBuilder
+ * @see javafx.scene.SubScene
  */
 public class XylophoneApp extends Application {
 
@@ -68,7 +70,7 @@
         Xform sceneRoot = new Xform();
         sceneRoot.rx.setAngle(225.0);
         sceneRoot.ry.setAngle(30.0);
-        sceneRoot.setScale(2.1);
+        sceneRoot.setScale(1.2);
 
         final AudioClip bar1Note =
                 new AudioClip(XylophoneApp.class.getResource("/ensemble/samples/shared-resources/Note1.wav").toString());
@@ -98,7 +100,7 @@
 
         // Base1
         Cube base1Cube = new Cube(1.0, new Color(0.2, 0.12, 0.1, 1.0), 1.0);
-        base1Cube.setTranslateX(xStart + 135);
+        base1Cube.setTranslateX(xStart + 128);
         base1Cube.setTranslateZ(yPos + 20.0);
         base1Cube.setTranslateY(11.0);
         base1Cube.setScaleX(barWidth * 11.5);
@@ -107,7 +109,7 @@
 
         // Base2
         Cube base2Cube = new Cube(1.0, new Color(0.2, 0.12, 0.1, 1.0), 1.0);
-        base2Cube.setTranslateX(xStart + 135);
+        base2Cube.setTranslateX(xStart + 128);
         base2Cube.setTranslateZ(yPos - 20.0);
         base2Cube.setTranslateY(11.0);
         base2Cube.setScaleX(barWidth * 11.5);
@@ -221,6 +223,7 @@
             }
         });
         bar8Cube.setOnMousePressed(new EventHandler<MouseEvent>() {
+            @Override
             public void handle(MouseEvent me) {
                 bar8Note.play();
             }
@@ -257,9 +260,19 @@
                 Duration.seconds(1.0), 200d))));
         animation2.setCycleCount(Animation.INDEFINITE);
 
-        return sceneRoot;
+        PerspectiveCamera camera = new PerspectiveCamera();
 
+        SubScene subScene = new SubScene(sceneRoot, 460, 240, true, true); 
+        subScene.setCamera(camera);
+        
+        sceneRoot.translateXProperty().bind(subScene.widthProperty().divide(2.2));
+        sceneRoot.translateYProperty().bind(subScene.heightProperty().divide(2));
+        sceneRoot.getTransforms().addAll(new Rotate(180, Rotate.X_AXIS));
 
+        Group group = new Group();
+        group.getChildren().add(subScene);       
+        
+        return group;
     }
 
     public void play() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/toys/Hello/src/main/java/hello/HelloRectangle.java	Tue Aug 27 09:36:40 2013 -0700
@@ -0,0 +1,101 @@
+/*
+ * 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.  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 hello;
+
+import javafx.application.Application;
+import javafx.scene.Group;
+import javafx.scene.Scene;
+import javafx.scene.control.Slider;
+import javafx.scene.effect.BlendMode;
+import javafx.scene.layout.VBox;
+import javafx.scene.paint.Color;
+import javafx.scene.shape.Circle;
+import javafx.scene.shape.Ellipse;
+import javafx.scene.shape.Rectangle;
+import javafx.stage.Stage;
+
+/**
+ */
+public class HelloRectangle extends Application {
+    @Override public void start(Stage stage) {
+        stage.setTitle("Hello Rectangle");
+
+        Group root = new Group();
+        Scene scene = new Scene(root, 600, 450);
+
+        Slider aw = new Slider(-300, 300, 0);
+        Slider ah = new Slider(-300, 300, 0);
+
+        Rectangle rect = new Rectangle();
+        rect.setX(25);
+        rect.setY(40);
+        rect.setWidth(300);
+        rect.setHeight(300);
+        rect.setFill(Color.RED);
+        rect.arcWidthProperty().bind(aw.valueProperty());
+        rect.arcHeightProperty().bind(ah.valueProperty());
+
+        Circle circle = new Circle();
+        circle.setCenterX(450);
+        circle.setCenterY(200);
+        circle.setRadius(50);
+        circle.setFill(Color.RED);
+        circle.radiusProperty().bind(aw.valueProperty());
+
+        Ellipse ellipse = new Ellipse();
+        ellipse.setCenterX(450);
+        ellipse.setCenterY(375);
+        ellipse.radiusXProperty().bind(aw.valueProperty());
+        ellipse.radiusYProperty().bind(ah.valueProperty());
+        ellipse.setFill(Color.RED);
+
+        VBox box = new VBox(aw, ah);
+        box.relocate(350, 20);
+
+//        root.getChildren().addAll(rect, circle, ellipse, box);
+
+        Rectangle behind = new Rectangle(100, 100, new Color(1, 0, 0, .1));
+        Rectangle front = new Rectangle(10, 10, Color.GREEN);
+        front.setBlendMode(BlendMode.SRC_ATOP);
+
+        root.getChildren().addAll(behind, front);
+
+//        FillTransition tx = new FillTransition(Duration.seconds(3), behind, Color.RED, Color.BLUE);
+//        tx.setAutoReverse(true);
+//        tx.setCycleCount(FillTransition.INDEFINITE);
+//        tx.play();
+
+        stage.setScene(scene);
+        stage.show();
+    }
+
+    /**
+     * @param args the command line arguments
+     */
+    public static void main(String[] args) {
+        Application.launch(args);
+    }
+}
--- a/build.gradle	Tue Aug 27 09:59:24 2013 -0400
+++ b/build.gradle	Tue Aug 27 09:36:40 2013 -0700
@@ -1677,9 +1677,9 @@
     def projectsToDocument = [
             project(":base"), project(":graphics"), project(":controls"),
             project(":swing"), project(":swt"), project(":fxml"), project(":web")]
-    source(projectsToDocument.collect({
+    source = projectsToDocument.collect({
         [it.sourceSets.main.java, "$it.buildDir/generated-src/builders"]
-    }));
+    });
     setDestinationDir(new File(buildDir, 'javadoc'));
     // Might need a classpath
     classpath = files(projectsToDocument.collect { project ->
@@ -1688,6 +1688,13 @@
     classpath += files(projectsToDocument.collect { project ->
         project.sourceSets.main.output
     });
+
+    // TODO: temporary for javadoc build until media is open sourced
+    if (BUILD_CLOSED) {
+        source += fileTree(dir: "$mediaApiDir").include('**/*.java')
+        classpath += files("modules/media/build/classes/main")
+    }
+
     exclude("com/**/*", "javafx/scene/ParentDesignInfo*", "Compile*", "javafx/builder/**/*");
     options.windowTitle("JavaFX ${RELEASE_NAME}")
     options.links(JDK_DOCS);
@@ -1843,7 +1850,15 @@
 
         dependsOn(subprojects.collect { project -> project.getTasksByName("assemble", true)});
     }
-    jfxrt.dependsOn(jfxrtTask)
+    def jfxrtIndexTask = task("jfxrtIndex$t.capital") {
+        //the following is a workaround for the lack of indexing in gradle 1.4 through 1.7
+        dependsOn(jfxrtTask)
+
+        doLast() {
+            ant.jar (update: true, index: true, destfile: jfxrtTask.archiveName)
+        }
+    }
+    jfxrt.dependsOn(jfxrtIndexTask)
 
     // The 'sdk' task will build the rest of the SDK, and depends on the 'jfxrtTask' task. After
     // executing this task the sdk bundle for the current COMPILE_TARGETS will be fully created.
--- a/buildSrc/android.gradle	Tue Aug 27 09:59:24 2013 -0400
+++ b/buildSrc/android.gradle	Tue Aug 27 09:36:40 2013 -0700
@@ -349,7 +349,6 @@
 android.prism.maxTextureSize=2048
 android.prism.dirtyopts=true
 android.prism.vsync=false
-android.prism.device=true
 android.use.egl=true
 android.com.sun.javafx.isEmbedded=true
 """
--- a/buildSrc/armv6hf.gradle	Tue Aug 27 09:59:24 2013 -0400
+++ b/buildSrc/armv6hf.gradle	Tue Aug 27 09:36:40 2013 -0700
@@ -185,7 +185,6 @@
 eglfb.glass.lens=eglfb
 eglfb.prism.order=es2
 eglfb.prism.eglfb=true
-eglfb.prism.device=true
 eglfb.prism.lcdtext=false
 eglfb.use.egl=true
 eglfb.use.gles2=true
@@ -204,7 +203,6 @@
 eglx11.glass.lens=eglx11
 eglx11.prism.order=es2
 eglx11.prism.eglx11=true
-eglx11.prism.device=true
 eglx11.prism.lcdtext=false
 eglx11.use.egl=true
 eglx11.use.gles2=true
--- a/buildSrc/armv6sf.gradle	Tue Aug 27 09:59:24 2013 -0400
+++ b/buildSrc/armv6sf.gradle	Tue Aug 27 09:36:40 2013 -0700
@@ -204,7 +204,6 @@
 eglfb.glass.lens=eglfb
 eglfb.prism.order=es2
 eglfb.prism.eglfb=true
-eglfb.prism.device=true
 eglfb.prism.lcdtext=false
 eglfb.use.egl=true
 eglfb.doNativeComposite=true
@@ -223,7 +222,6 @@
 eglx11.glass.lens=eglx11
 eglx11.prism.order=es2
 eglx11.prism.eglx11=true
-eglx11.prism.device=true
 eglx11.prism.lcdtext=false
 eglx11.use.egl=true
 eglx11.use.gles2=true
--- a/buildSrc/ios.gradle	Tue Aug 27 09:59:24 2013 -0400
+++ b/buildSrc/ios.gradle	Tue Aug 27 09:36:40 2013 -0700
@@ -120,7 +120,6 @@
 ios.jfxmedia.platforms=IOSPlatform
 ios.glass.platform=ios
 ios.prism.allowhidpi=false
-ios.prism.device=true
 ios.prism.mintexturesize=16
 ios.prism.verbose=true
 ios.prism.static.libraries=true
--- a/buildSrc/x86egl.gradle	Tue Aug 27 09:59:24 2013 -0400
+++ b/buildSrc/x86egl.gradle	Tue Aug 27 09:36:40 2013 -0700
@@ -154,7 +154,6 @@
 eglfb.glass.lens=eglfb
 eglfb.prism.order=es2
 eglfb.prism.eglfb=true
-eglfb.prism.device=true
 eglfb.prism.lcdtext=false
 eglfb.use.egl=true
 eglfb.use.gles2=true
@@ -172,7 +171,6 @@
 eglx11.glass.lens=eglx11
 eglx11.prism.order=es2
 eglx11.prism.eglx11=true
-eglx11.prism.device=true
 eglx11.prism.lcdtext=false
 eglx11.use.egl=true
 eglx11.use.gles2=true
@@ -273,7 +271,8 @@
     file("modules/graphics/src/main/native-glass/lens/wm"),
     file("modules/graphics/src/main/native-glass/lens/cursor/fbCursor"),
     file("modules/graphics/src/main/native-glass/lens/input/udev"),
-    file("modules/graphics/src/main/native-glass/lens/wm/screen/fbdevScreen.c")]
+    file("modules/graphics/src/main/native-glass/lens/wm/screen/fbdevScreen.c"),
+    file("modules/graphics/src/main/native-glass/lens/platform-util") ]
     //file("modules/graphics/src/main/native-glass/lens/wm/screen")]
 X86EGL.glass.fb.compiler = compiler
 X86EGL.glass.fb.ccFlags = ["-ffast-math", extraCFlags, "-DLINUX"].flatten()
--- a/modules/base/src/main/java/com/sun/javafx/PlatformUtil.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/base/src/main/java/com/sun/javafx/PlatformUtil.java	Tue Aug 27 09:36:40 2013 -0700
@@ -40,6 +40,7 @@
     private static final String os = System.getProperty("os.name");
     private static final String version = System.getProperty("os.version");
     private static final boolean embedded;
+    private static final boolean embedded3DEnabled;
     private static final String embeddedType;
     private static final boolean useEGL;
     private static final boolean doEGLCompositing;
@@ -58,6 +59,11 @@
                 return Boolean.getBoolean("com.sun.javafx.isEmbedded");
             }
         });
+        embedded3DEnabled = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
+            @Override public Boolean run() {
+                return Boolean.getBoolean("com.sun.javafx.experimental.embedded.3d");
+            }
+        });
         embeddedType = AccessController.doPrivileged(new PrivilegedAction<String>() {
             @Override public String run() {
                 return System.getProperty("embedded");
@@ -183,6 +189,13 @@
     }
 
     /**
+     * Returns true if the embedded platform is 3D enabled.
+     */
+    public static boolean isEmbedded3DEnabled() {
+        return embedded3DEnabled;
+    }
+
+    /**
      * Returns a string with the embedded type - ie eglx11, eglfb, dfb or null.
      */
     public static String getEmbeddedType() {
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/TextInputControlSkin.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/TextInputControlSkin.java	Tue Aug 27 09:36:40 2013 -0700
@@ -365,9 +365,8 @@
                 Window window = scene.getWindow();
                 Rectangle2D characterBounds = getCharacterBounds(imstart + offset);
                 Point2D p = getSkinnable().localToScene(characterBounds.getMinX(), characterBounds.getMaxY());
-                // TODO: Find out where these offsets come from
-                Point2D location = new Point2D(window.getX() + scene.getX() + p.getX() -  6,
-                                               window.getY() + scene.getY() + p.getY() - 42);
+                Point2D location = new Point2D(window.getX() + scene.getX() + p.getX(),
+                                               window.getY() + scene.getY() + p.getY());
                 return location;
             }
 
--- a/modules/fxml/src/main/docs/javafx/fxml/doc-files/introduction_to_fxml.html	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/fxml/src/main/docs/javafx/fxml/doc-files/introduction_to_fxml.html	Tue Aug 27 09:36:40 2013 -0700
@@ -3,19 +3,19 @@
 <html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">    
 <head>
 <link href="fxml.css" rel="stylesheet"/>    
-<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
 <title>Introduction to FXML | JavaFX 2.2</title>
 <meta name="description" content="The document introduces FXML, an XML-based declarative markup language for defining user interfaces in JavaFX 2.2 applications."/>
 <meta name="keywords" content="JavaFX 2.2, FXML, JavaFX GUI development, web development, Java application development, GUI applications, rich internet applications, RIA, expressive content"/>
+</head>
 <body>
-<p>
+
 <div class="fx-code-header">
-<div class="version"><br/>Release: JavaFX 2.2</div>
+<div class="version"><br/>Release: JavaFX 8.0</div>
 </div>
-</p>
 
 <h1>Introduction to FXML</h1>
-<p class="subtitle">Last updated: 6/21/2012</p>
+<p class="subtitle">Last updated: 8/23/2013</p>
 
 <h2>Contents</h2>
 <ul class="contents">
@@ -632,10 +632,9 @@
 
 &lt;VBox xmlns:fx="http://javafx.com/fxml"&gt;
     &lt;fx:script&gt;
-    importClass(java.lang.System);
 
     function handleButtonAction(event) {
-       System.out.println('You clicked me!');
+       java.lang.System.out.println('You clicked me!');
     }
     &lt;/fx:script&gt;
 
@@ -665,10 +664,9 @@
 
 <div class="caption">example.js</div>
 <pre class="code">
-importClass(java.lang.System);
 
 function handleButtonAction(event) {
-   System.out.println('You clicked me!');
+   java.lang.System.out.println('You clicked me!');
 }
 </pre>
 
@@ -688,6 +686,17 @@
 </pre>
 </assert>
 
+<p><strong>Warning:</strong>As of JavaFX 8.0, <span class="code">importClass()</span> javascript function is no longer supported. You have to use fully qualified names as in the example above or load a nashorn compatibility script.</p>
+
+<pre class="code">
+load("nashorn:mozilla_compat.js");
+importClass(java.lang.System);
+
+function handleButtonAction(event) {
+   System.out.println('You clicked me!');
+}
+</pre> 
+
 <h2><a name="controllers">Controllers</a></h2>
 <p>While it can be convenient to write simple event handlers in script, either inline or defined in external files, it is often preferable to define more complex application logic in a compiled, strongly-typed language such as Java. As discussed earlier, the <span class="code">fx:controller</span> attribute allows a caller to associate a "controller" class with an FXML document. A controller is a compiled class that implements the "code behind" the object hierarchy defined by the document.</p>
 
--- a/modules/fxml/src/main/java/javafx/fxml/FXMLLoader.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/fxml/src/main/java/javafx/fxml/FXMLLoader.java	Tue Aug 27 09:36:40 2013 -0700
@@ -962,7 +962,7 @@
                         loadListener.readInternalAttribute(localName, value);
                     }
 
-                    resources = ResourceBundle.getBundle(value, Locale.getDefault(), 
+                    resources = ResourceBundle.getBundle(value, Locale.getDefault(),
                             FXMLLoader.this.resources.getClass().getClassLoader());
                 } else if (localName.equals(INCLUDE_CHARSET_ATTRIBUTE)) {
                     if (loadListener != null) {
@@ -1370,8 +1370,6 @@
                         + " extension " + extension + ".");
                 }
 
-                scriptEngine.setBindings(scriptEngineManager.getBindings(), ScriptContext.ENGINE_SCOPE);
-
                 try {
                     URL location;
                     if (source.charAt(0) == '/') {
@@ -1527,6 +1525,7 @@
             Bindings engineBindings = scriptEngine.getBindings(ScriptContext.ENGINE_SCOPE);
             Bindings localBindings = scriptEngine.createBindings();
             localBindings.put(EVENT_KEY, event);
+            localBindings.putAll(engineBindings);
             scriptEngine.setBindings(localBindings, ScriptContext.ENGINE_SCOPE);
 
             // Execute the script
@@ -2459,7 +2458,6 @@
         if (!staticLoad) {
             ScriptEngineManager scriptEngineManager = getScriptEngineManager();
             scriptEngine = scriptEngineManager.getEngineByName(language);
-            scriptEngine.setBindings(scriptEngineManager.getBindings(), ScriptContext.ENGINE_SCOPE);
         }
     }
 
--- a/modules/graphics/src/main/java/com/sun/glass/ui/lens/LensApplication.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/glass/ui/lens/LensApplication.java	Tue Aug 27 09:36:40 2013 -0700
@@ -240,7 +240,7 @@
     private static class LensWindowEvent extends Event {
 
         static enum EType {
-            CLOSE, DESTROY, EXPOSE, FOCUS, MOVE, RESIZE, UNGRAB
+            CLOSE, DESTROY, EXPOSE, FOCUS, MOVE, RESIZE, UNGRAB, FOCUS_DISABLED
         };
 
         private EType type;
@@ -320,6 +320,10 @@
                 case EXPOSE:
                     window._notifyExpose(x, y, width, height);
                     break;
+                case FOCUS_DISABLED:
+                    window._notifyFocusDisabled();
+                    break;
+
                 default:
                     LensLogger.getLogger().severe(
                         "Unrecognized window event type");
@@ -1012,9 +1016,12 @@
             case WindowEvent.FOCUS_UNGRAB:
                 etype = LensWindowEvent.EType.UNGRAB;
                 break;
+            case WindowEvent.FOCUS_DISABLED:
+                etype = LensWindowEvent.EType.FOCUS_DISABLED;
+                break;
             default:
                 LensLogger.getLogger().warning("Unsupported event type ("+
-                    WindowEvent.getEventName(windowEvent)+" skipping event");
+                    WindowEvent.getEventName(windowEvent)+") skipping event");
                 return;
         }
 
--- a/modules/graphics/src/main/java/com/sun/glass/ui/lens/LensWindow.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/glass/ui/lens/LensWindow.java	Tue Aug 27 09:36:40 2013 -0700
@@ -376,6 +376,10 @@
         notifyFocusUngrab();
     }
 
+    protected void _notifyFocusDisabled() {
+        notifyFocusDisabled();
+    }
+
     //**************************************************************
     // upcalls from native, need to forward to event loop
 
--- a/modules/graphics/src/main/java/com/sun/javafx/application/LauncherImpl.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/application/LauncherImpl.java	Tue Aug 27 09:36:40 2013 -0700
@@ -25,8 +25,12 @@
 
 package com.sun.javafx.application;
 
-import com.sun.javafx.jmx.MXExtension;
-import com.sun.javafx.runtime.SystemProperties;
+import javafx.application.Application;
+import javafx.application.Preloader;
+import javafx.application.Preloader.ErrorNotification;
+import javafx.application.Preloader.PreloaderNotification;
+import javafx.application.Preloader.StateChangeNotification;
+import javafx.stage.Stage;
 import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.Constructor;
@@ -43,13 +47,8 @@
 import java.util.jar.Attributes;
 import java.util.jar.JarFile;
 import java.util.jar.Manifest;
-
-import javafx.application.Application;
-import javafx.application.Preloader;
-import javafx.application.Preloader.ErrorNotification;
-import javafx.application.Preloader.PreloaderNotification;
-import javafx.application.Preloader.StateChangeNotification;
-import javafx.stage.Stage;
+import com.sun.javafx.jmx.MXExtension;
+import com.sun.javafx.runtime.SystemProperties;
 import sun.misc.BASE64Decoder;
 
 
@@ -275,6 +274,7 @@
             }
         } else if (launchMode.equals(LAUNCH_MODE_CLASS)) {
             mainClassName = launchName;
+            preloaderClassName = System.getProperty("javafx.preloader");
         } else {
             abort(new IllegalArgumentException("The launchMode argument must be one of LM_CLASS or LM_JAR"),
                     "Invalid launch mode: %1$s", launchMode);
--- a/modules/graphics/src/main/java/com/sun/javafx/font/CompositeStrike.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/font/CompositeStrike.java	Tue Aug 27 09:36:40 2013 -0700
@@ -166,12 +166,6 @@
         return getStrikeSlot(slot).getGlyph(slotglyphCode);
     }
 
-    public Glyph getGlyph(GlyphList gl, int gi) {
-        int glyphCode = gl.getGlyphCode(gi);
-        int slot = (glyphCode >>> 24);
-        return getStrikeSlot(slot).getGlyph(gl, gi);
-    }
-
      /**
      * Access to individual character advances are frequently needed for layout
      * understand that advance may vary for single glyph if ligatures or kerning
--- a/modules/graphics/src/main/java/com/sun/javafx/font/FontStrike.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/font/FontStrike.java	Tue Aug 27 09:36:40 2013 -0700
@@ -38,7 +38,6 @@
     public Metrics getMetrics();
     public Glyph getGlyph(char symbol);
     public Glyph getGlyph(int glyphCode);
-    public Glyph getGlyph(GlyphList gl, int glyphIndex);
     public void clearDesc(); // for cache management.
     public int getAAMode();
 
--- a/modules/graphics/src/main/java/com/sun/javafx/font/PrismFontStrike.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/font/PrismFontStrike.java	Tue Aug 27 09:36:40 2013 -0700
@@ -154,11 +154,6 @@
 
     protected abstract Glyph createGlyph(int glyphCode);
 
-    protected Glyph createGlyph(GlyphList gl, int gi) {
-        int glyphCode = gl.getGlyphCode(gi) & CompositeGlyphMapper.GLYPHMASK;
-        return createGlyph(glyphCode);
-    }
-
     public Glyph getGlyph(int glyphCode) {
         Glyph glyph = glyphMap.get(glyphCode);
         if (glyph == null) {
@@ -168,16 +163,6 @@
         return glyph;
     }
 
-    public Glyph getGlyph(GlyphList gl, int gi) {
-        int glyphCode = gl.getGlyphCode(gi) & CompositeGlyphMapper.GLYPHMASK;
-        Glyph glyph = glyphMap.get(glyphCode);
-        if (glyph == null) {
-            glyph = createGlyph(gl, gi);
-            glyphMap.put(glyphCode, glyph);
-        }
-        return glyph;
-    }
-
     protected abstract Path2D createGlyphOutline(int glyphCode);
 
     public Shape getOutline(GlyphList gl, BaseTransform transform) {
--- a/modules/graphics/src/main/java/com/sun/javafx/font/directwrite/DWFontStrike.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/font/directwrite/DWFontStrike.java	Tue Aug 27 09:36:40 2013 -0700
@@ -25,18 +25,14 @@
 
 package com.sun.javafx.font.directwrite;
 
-import com.sun.javafx.font.CompositeGlyphMapper;
 import com.sun.javafx.font.DisposerRecord;
 import com.sun.javafx.font.FontStrikeDesc;
 import com.sun.javafx.font.Glyph;
 import com.sun.javafx.font.PrismFontFactory;
 import com.sun.javafx.font.PrismFontStrike;
 import com.sun.javafx.geom.Path2D;
-import com.sun.javafx.geom.Point2D;
 import com.sun.javafx.geom.RectBounds;
 import com.sun.javafx.geom.transform.BaseTransform;
-import com.sun.javafx.scene.text.GlyphList;
-import com.sun.javafx.text.TextRun;
 
 class DWFontStrike extends PrismFontStrike<DWFontFile> {
     DWRITE_MATRIX matrix;
@@ -102,21 +98,7 @@
         return fontResource.getGlyphOutline(glyphCode, getSize());
     }
 
-    @Override public Glyph createGlyph(GlyphList gl, int gi) {
-        Point2D offset = (Point2D)((TextRun)gl).getGlyphData(gi);
-        float advanceOffset = offset != null ? offset.x : 0;
-        float ascenderOffset = offset != null ? offset.y : 0;
-        int gc = gl.getGlyphCode(gi) & CompositeGlyphMapper.GLYPHMASK;
-        if (PrismFontFactory.debugFonts) {
-            if (advanceOffset != 0 || ascenderOffset != 0) {
-                System.err.println("Setting glyph[" + Integer.toHexString(gc) +
-                                   "] offsets to " + offset);
-            }
-        }
-        return new DWGlyph(this, gc, advanceOffset, ascenderOffset, drawShapes);
-    }
-
     @Override protected Glyph createGlyph(int glyphCode) {
-        return new DWGlyph(this, glyphCode, 0, 0, drawShapes);
+        return new DWGlyph(this, glyphCode, drawShapes);
     }
 }
--- a/modules/graphics/src/main/java/com/sun/javafx/font/directwrite/DWGlyph.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/font/directwrite/DWGlyph.java	Tue Aug 27 09:36:40 2013 -0700
@@ -52,8 +52,7 @@
     private static D2D1_MATRIX_3X2_F D2D2_MATRIX_IDENTITY = new D2D1_MATRIX_3X2_F(1,0, 0,1, 0,0);
 
 
-    DWGlyph(DWFontStrike strike, int glyphCode, float advanceOffset,
-            float ascenderOffset, boolean drawShapes) {
+    DWGlyph(DWFontStrike strike, int glyphCode, boolean drawShapes) {
         this.strike = strike;
         this.drawShapes = drawShapes;
 
@@ -63,8 +62,8 @@
         run.fontEmSize = strike.getSize();
         run.glyphIndices = (short)glyphCode;
         run.glyphAdvances = 0;
-        run.advanceOffset = advanceOffset;
-        run.ascenderOffset = ascenderOffset;
+        run.advanceOffset = 0;
+        run.ascenderOffset = 0;
         run.bidiLevel = 0; //should not matter as it draws just one glyph
         run.isSideways = false;
 
--- a/modules/graphics/src/main/java/com/sun/javafx/font/directwrite/DWGlyphLayout.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/font/directwrite/DWGlyphLayout.java	Tue Aug 27 09:36:40 2013 -0700
@@ -30,7 +30,6 @@
 import com.sun.javafx.font.FontStrike;
 import com.sun.javafx.font.PGFont;
 import com.sun.javafx.font.PrismFontFactory;
-import com.sun.javafx.geom.Point2D;
 import com.sun.javafx.scene.text.TextSpan;
 import com.sun.javafx.text.GlyphLayout;
 import com.sun.javafx.text.PrismTextLayout;
@@ -159,8 +158,9 @@
         i = 0; j = rtl ? glyphCount - 1 : 0;
         float x = 0;
         while (i < pos.length - 2) {
-            pos[i++] = x;
-            pos[i++] = 0;
+            int g = j << 1;
+            pos[i++] = (rtl ? -offsets[g] : offsets[g]) + x;
+            pos[i++] = -offsets[g + 1];
             x += advances[j];
             j+=step;
         }
@@ -169,18 +169,6 @@
 
         analyzer.Release();
         run.shape(glyphCount, iglyphs, pos, indices);
-
-        /* Checking glyphs offsets */
-        i = 0;
-        j = 0;
-        while (i < glyphCount) {
-            float glyphOffsetX = offsets[j++];
-            float glyphOffsetY = offsets[j++];
-            if (glyphOffsetX != 0 || glyphOffsetY != 0) {
-                run.setGlyphData(i, new Point2D(glyphOffsetX, glyphOffsetY));
-            }
-            i++;
-        }
     }
 
     private String getName(IDWriteLocalizedStrings localizedStrings) {
@@ -322,10 +310,10 @@
         renderer.AddRef();
         layout.Draw(0, renderer, 0, 0);
 
-        int totalGlyphCount = renderer.GetTotalGlyphCount();
-        int[] glyphs = new int[totalGlyphCount];
-        float[] advances = new float[totalGlyphCount];
-        float[] offsets = new float[totalGlyphCount * 2];
+        int glyphCount = renderer.GetTotalGlyphCount();
+        int[] glyphs = new int[glyphCount];
+        float[] advances = new float[glyphCount];
+        float[] offsets = new float[glyphCount * 2];
         int[] clusterMap = new int[length];
         int glyphStart = 0;
         int textStart = 0;
@@ -349,14 +337,15 @@
         format.Release();
 
         /* Adjust glyphs positions */
-        float[] pos = new float[totalGlyphCount * 2 + 2];
+        float[] pos = new float[glyphCount * 2 + 2];
         boolean rtl = !run.isLeftToRight();
-        int i = 0, j = rtl ? totalGlyphCount - 1 : 0;
+        int i = 0, j = rtl ? glyphCount - 1 : 0;
         int step = rtl ? -1 : 1;
         float x = 0;
         while (i < pos.length - 2) {
-            pos[i++] = x;
-            pos[i++] = 0;
+            int g = j << 1;
+            pos[i++] = (rtl ? -offsets[g] : offsets[g]) + x;
+            pos[i++] = -offsets[g + 1];
             x += advances[j];
             j+=step;
         }
@@ -364,10 +353,10 @@
         pos[i++] = 0;
         if (rtl) {
             /* Adjust glyphs */
-            for (i = 0; i < totalGlyphCount / 2; i++) {
+            for (i = 0; i < glyphCount / 2; i++) {
                 int tmp = glyphs[i];
-                glyphs[i] = glyphs[totalGlyphCount - i - 1];
-                glyphs[totalGlyphCount - i - 1] = tmp;
+                glyphs[i] = glyphs[glyphCount - i - 1];
+                glyphs[glyphCount - i - 1] = tmp;
             }
             /* Adjust glyph indices */
             for (i = 0; i < length / 2; i++) {
@@ -376,18 +365,6 @@
                 clusterMap[length - i - 1] = tmp;
             }
         }
-        run.shape(totalGlyphCount, glyphs, pos, clusterMap);
-
-        /* Checking glyphs offsets */
-        i = 0;
-        j = 0;
-        while (i < totalGlyphCount) {
-            float glyphOffsetX = offsets[j++];
-            float glyphOffsetY = offsets[j++];
-            if (glyphOffsetX != 0 || glyphOffsetY != 0) {
-                run.setGlyphData(i, new Point2D(glyphOffsetX, glyphOffsetY));
-            }
-            i++;
-        }
+        run.shape(glyphCount, glyphs, pos, clusterMap);
     }
 }
--- a/modules/graphics/src/main/java/com/sun/javafx/geom/transform/BaseTransform.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/geom/transform/BaseTransform.java	Tue Aug 27 09:36:40 2013 -0700
@@ -73,7 +73,7 @@
 
     /**
      * This flag bit indicates that the transform defined by this object
-     * performs a translation in addition tto the conversions indicated
+     * performs a translation in addition to the conversions indicated
      * by other flag bits.
      * A translation moves the coordinates by a constant amount in x
      * and y without changing the length or angle of vectors.
--- a/modules/graphics/src/main/java/com/sun/javafx/geom/transform/GeneralTransform3D.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/geom/transform/GeneralTransform3D.java	Tue Aug 27 09:36:40 2013 -0700
@@ -35,7 +35,7 @@
  * GeneralTransform is typically used only for projection transforms.
  *
  */
-public class GeneralTransform3D implements CanTransformVec3d{
+public final class GeneralTransform3D implements CanTransformVec3d {
 
     //The 4x4 double-precision floating point matrix.  The mathematical
     //representation is row major, as in traditional matrix mathematics.
--- a/modules/graphics/src/main/java/com/sun/javafx/sg/prism/CacheFilter.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/sg/prism/CacheFilter.java	Tue Aug 27 09:36:40 2013 -0700
@@ -34,6 +34,7 @@
 import com.sun.javafx.geom.transform.Affine2D;
 import com.sun.javafx.geom.transform.Affine3D;
 import com.sun.javafx.geom.transform.BaseTransform;
+import com.sun.javafx.geom.transform.GeneralTransform3D;
 import com.sun.prism.Graphics;
 import com.sun.prism.RTTexture;
 import com.sun.prism.Texture;
@@ -625,7 +626,7 @@
             if (dirtyBounds != null) {
                 TEMP_CONTAINER.deriveWithNewRegion((RectBounds)TEMP_BOUNDS.deriveWithNewBounds(dirtyBounds));
                 // Culling might save us a lot when there's a dirty region
-                node.doPreCulling(TEMP_CONTAINER, TEMP_CACHEFILTER_TRANSFORM, null);
+                node.doPreCulling(TEMP_CONTAINER, TEMP_CACHEFILTER_TRANSFORM, new GeneralTransform3D());
                 g.setHasPreCullingBits(true);
                 g.setClipRectIndex(0);
                 g.setClipRect(dirtyBounds);
@@ -692,8 +693,7 @@
         }
 
         NGNode clip = node.getClipNode();
-        return clip != null && clip instanceof NGRectangle &&
-                ((NGRectangle)clip).isRectClip(BaseTransform.IDENTITY_TRANSFORM, false);
+        return clip != null && clip.isRectClip(BaseTransform.IDENTITY_TRANSFORM, false);
     }
 
     /**
--- a/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGCircle.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGCircle.java	Tue Aug 27 09:36:40 2013 -0700
@@ -26,6 +26,7 @@
 package com.sun.javafx.sg.prism;
 
 import com.sun.javafx.geom.Ellipse2D;
+import com.sun.javafx.geom.RectBounds;
 import com.sun.javafx.geom.Shape;
 import com.sun.prism.Graphics;
 import com.sun.prism.shape.ShapeRep;
@@ -34,14 +35,26 @@
  *
  */
 public class NGCircle extends NGShape {
+    /**
+     * .5 * 1/Math.sqrt(2). If you multiply this value by the diameter of the
+     * circle, then you will get half the length of the side of the square which
+     * is inscribed within the circle. This is used when computing the opaque region
+     * of the circle and ellipse. This value has been precomputed and stored
+     * as a constant to make the resulting math faster. It is low in precision
+     * to compute a conservative inscribed square.
+     */
+    static final float HALF_SQRT_HALF = .353f; // really .35355339059327...
 
     private Ellipse2D ellipse = new Ellipse2D();
+    private float cx, cy;
 
     public void updateCircle(float cx, float cy, float r) {
         ellipse.x = cx - r;
         ellipse.y = cy - r;
         ellipse.width = r * 2f;
         ellipse.height = ellipse.width;
+        this.cx = cx;
+        this.cy = cy;
         geometryChanged();
     }
 
@@ -50,6 +63,29 @@
         return ellipse;
     }
 
+    @Override protected boolean supportsOpaqueRegions() { return true; }
+
+    @Override
+    protected boolean hasOpaqueRegion() {
+        // Since this is a circle, both ellipse.width & ellipse.height are the
+        // same, so I can just get away with checking one of them.
+        // Although a circle with a very small radius won't produce a very large
+        // opaque region on its own, it might be subsequently scaled in which
+        // case even a very small radius (like .00001) could become something
+        // significant.
+        return super.hasOpaqueRegion() && ellipse.width > 0;
+    }
+
+    @Override
+    protected RectBounds computeOpaqueRegion(RectBounds opaqueRegion) {
+        final float halfSquareLength = ellipse.width * HALF_SQRT_HALF;
+        return (RectBounds) opaqueRegion.deriveWithNewBounds(
+                cx - halfSquareLength,
+                cy - halfSquareLength, 0,
+                cx + halfSquareLength,
+                cy + halfSquareLength, 0);
+    }
+
     @Override
     protected ShapeRep createShapeRep(Graphics g) {
         return g.getResourceFactory().createEllipseRep();
--- a/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGEllipse.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGEllipse.java	Tue Aug 27 09:36:40 2013 -0700
@@ -26,6 +26,7 @@
 package com.sun.javafx.sg.prism;
 
 import com.sun.javafx.geom.Ellipse2D;
+import com.sun.javafx.geom.RectBounds;
 import com.sun.javafx.geom.Shape;
 import com.sun.prism.Graphics;
 import com.sun.prism.shape.ShapeRep;
@@ -35,12 +36,15 @@
 public class NGEllipse extends NGShape {
 
     private Ellipse2D ellipse = new Ellipse2D();
+    private float cx, cy;
 
     public void updateEllipse(float cx, float cy, float rx, float ry) {
         ellipse.x = cx - rx;
         ellipse.width = rx * 2f;
         ellipse.y = cy - ry;
         ellipse.height = ry * 2f;
+        this.cx = cx;
+        this.cy = cy;
         geometryChanged();
     }
 
@@ -53,4 +57,31 @@
     protected ShapeRep createShapeRep(Graphics g) {
         return g.getResourceFactory().createEllipseRep();
     }
+
+    @Override
+    protected boolean supportsOpaqueRegions() { return true; }
+
+    @Override
+    protected boolean hasOpaqueRegion() {
+        return super.hasOpaqueRegion() && ellipse.width > 0 && ellipse.height > 0;
+    }
+
+    @Override
+    protected RectBounds computeOpaqueRegion(RectBounds opaqueRegion) {
+        // An ellipse can be viewed as a circle which has been stretched both
+        // horizontally and vertically. We can approach computing the inscribed
+        // rectangle in two steps. First, find the length of the inscribed
+        // square if you were to have a circle with the diameter of the width
+        // of the ellipse. This will give you the width of the rectangle. Second,
+        // find the length of the inscribed square if you were to have a circle
+        // with a diameter of the height of the ellipse. This gives you the
+        // height of the inscribed rectangle.
+        final float halfWidth = ellipse.width * NGCircle.HALF_SQRT_HALF;
+        final float halfHeight = ellipse.height * NGCircle.HALF_SQRT_HALF;
+        return (RectBounds) opaqueRegion.deriveWithNewBounds(
+                cx - halfWidth,
+                cy - halfHeight, 0,
+                cx + halfWidth,
+                cy + halfHeight, 0);
+    }
 }
--- a/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGGroup.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGGroup.java	Tue Aug 27 09:36:40 2013 -0700
@@ -56,13 +56,13 @@
     private List<NGNode> children = new ArrayList<>(1);
     private List<NGNode> unmod = Collections.unmodifiableList(children);
     private List<NGNode> removed;
-    
+
     /**
      * This mask has all bits that mark that a region intersects this group.
      * Which means it looks like this: 00010101010101010101010101010101 (first bit for sign)
      */
     private static final int REGION_INTERSECTS_MASK = 0x15555555;
-    
+
     /***************************************************************************
      *                                                                         *
      * Implementation of the PGGroup interface                                 *
@@ -131,10 +131,10 @@
         if (dirtyChildrenAccumulated > DIRTY_CHILDREN_ACCUMULATED_THRESHOLD) {
             return;
         }
-        
+
         removed.add(n);
         dirtyChildrenAccumulated++;
-        
+
         if (dirtyChildrenAccumulated > DIRTY_CHILDREN_ACCUMULATED_THRESHOLD) {
             removed.clear(); //no need to store anything in this case
         }
@@ -193,21 +193,21 @@
     protected void renderContent(Graphics g) {
         renderChildren(g, (NodePath<NGNode>)g.getRenderRoot());
     }
-    
+
     private void renderChildren(Graphics g, NodePath<NGNode> renderRoot) {
         if (children == null) {
             return;
         }
-        
+
         int startPos = 0;
         if (renderRoot != null) {
-            startPos = children.indexOf(renderRoot.getCurrentNode());
-
-            for (int i = 0; i < startPos; ++i) {
-                children.get(i).clearDirtyTree();
-            }
             if (renderRoot.hasNext()) {
                 renderRoot.next();
+                startPos = children.indexOf(renderRoot.getCurrentNode());
+
+                for (int i = 0; i < startPos; ++i) {
+                    children.get(i).clearDirtyTree();
+                }
             } else {
                 g.setRenderRoot(null);
             }
@@ -271,7 +271,7 @@
             bot.unref();
         }
     }
-    
+
     @Override
     protected boolean hasOverlappingContents() {
         if (blendMode != Mode.SRC_OVER) {
@@ -288,7 +288,7 @@
     public boolean isEmpty() {
         return children == null || children.isEmpty();
     }
-    
+
     @Override
     protected boolean hasVisuals() {
         return false;
@@ -309,39 +309,39 @@
      *                                                                         *
      **************************************************************************/
     @Override
-    protected NodePath<NGNode> computeRenderRoot(NodePath<NGNode> path, RectBounds dirtyRegion, int cullingIndex, BaseTransform tx,
+    protected RenderRootResult computeRenderRoot(NodePath<NGNode> path, RectBounds dirtyRegion, int cullingIndex, BaseTransform tx,
                                        GeneralTransform3D pvTx) {
 
         // If the NGGroup is completely outside the culling area, then we don't have to traverse down
         // to the children yo.
         if (cullingIndex != -1) {
             final int bits = cullingBits >> (cullingIndex*2);
-            if ((bits & CULLING_REGION_CONTAINS_OR_INTERSECTS_CLIP) == 0) {
-                return null;
+            if ((bits & DIRTY_REGION_CONTAINS_OR_INTERSECTS_NODE_BOUNDS) == 0) {
+                return RenderRootResult.NONE;
             }
-            if ((bits & CULLING_REGION_CONTAINS_CLIP) != 0) {
-                cullingIndex = -1; // Do not check culling in children, 
+            if ((bits & DIRTY_REGION_CONTAINS_NODE_BOUNDS) != 0) {
+                cullingIndex = -1; // Do not check culling in children,
                                    // as culling bits are not set for fully interior groups
             }
         }
-        
+
         if (!isVisible()) {
-            return null;
+            return RenderRootResult.NONE;
         }
 
         if (getOpacity() != 1.0 || (getEffect() != null && getEffect().reducesOpaquePixels()) || needsBlending()) {
-            return null;
+            return RenderRootResult.NONE;
         }
 
         if (getClipNode() != null) {
-            final NGNode clip = (NGNode)getClipNode();
-            RectBounds clipBounds = clip.computeOpaqueRegion(TEMP_RECT_BOUNDS);
+            final NGNode clip = getClipNode();
+            RectBounds clipBounds = clip.getOpaqueRegion();
             if (clipBounds == null) {
-                return null;
+                return RenderRootResult.NONE;
             }
             TEMP_TRANSFORM.deriveWithNewTransform(tx).deriveWithConcatenation(getTransform()).deriveWithConcatenation(clip.getTransform());
             if (!checkBoundsInQuad(clipBounds, dirtyRegion, TEMP_TRANSFORM, pvTx)) {
-                return null;
+                return RenderRootResult.NONE;
             }
         }
 
@@ -363,18 +363,25 @@
         double mzz = tx.getMzz();
         double mzt = tx.getMzt();
         final BaseTransform chTx = tx.deriveWithConcatenation(getTransform());
-        NodePath childPath = null;
-        for (int i=children.size()-1; i>=0; i--) {
-            final NGNode child = (NGNode) children.get(i);
-            childPath = child.computeRenderRoot(path, dirtyRegion, cullingIndex, chTx, pvTx);
-            if (childPath != null) break;
+        RenderRootResult result = RenderRootResult.NONE;
+        int resultIdx;
+        boolean followingChildrenClean = true;
+        for (resultIdx=children.size()-1; resultIdx>=0; resultIdx--) {
+            final NGNode child = children.get(resultIdx);
+            result = child.computeRenderRoot(path, dirtyRegion, cullingIndex, chTx, pvTx);
+            if (result != RenderRootResult.NONE) break;
+            followingChildrenClean &= child.isClean();
         }
         // restore previous transform state
         tx.restoreTransform(mxx, mxy, mxz, mxt, myx, myy, myz, myt, mzx, mzy, mzz, mzt);
-        if (childPath != null) {
-            childPath.add(this);
+        if (result != RenderRootResult.NONE) {
+            if (result == RenderRootResult.HAS_RENDER_ROOT || dirty != DirtyFlag.CLEAN ||
+                    (childDirty && !followingChildrenClean)) {
+                path.add(this);
+                result = RenderRootResult.HAS_RENDER_ROOT;
+            }
         }
-        return childPath;
+        return result;
     }
 
     @Override
@@ -386,7 +393,7 @@
 
         //set culling bits for this group first.
         super.markCullRegions(drc, cullingRegionsBitsOfParent, tx, pvTx);
-        
+
         //cullingRegionsBits == 0 group is outside all dirty regions
         // we can cull all children otherwise check children.
         // If none of the regions intersect this group, skip pre-culling
@@ -449,7 +456,7 @@
             g.transform(getTransform());
             NGNode child;
             for (int chldIdx = 0; chldIdx < children.size(); chldIdx++) {
-                child = (NGNode)children.get(chldIdx);
+                child = children.get(chldIdx);
                 child.drawCullBits(g);
             }
             // restore previous transform state
--- a/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGImageView.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGImageView.java	Tue Aug 27 09:36:40 2013 -0700
@@ -25,6 +25,7 @@
 
 package com.sun.javafx.sg.prism;
 
+import com.sun.javafx.geom.RectBounds;
 import com.sun.prism.Graphics;
 import com.sun.prism.Image;
 import com.sun.prism.ResourceFactory;
@@ -172,4 +173,20 @@
     // RT-18701: this method does nothing
     public void setSmooth(boolean s) {}
 
+    @Override
+    protected boolean supportsOpaqueRegions() { return true; }
+
+    @Override
+    protected boolean hasOpaqueRegion() {
+        // An image, being a raster, needs to be at least 1 pixel in width to have any opaque
+        // pixel content, even when scaled up. So we check against w >= 1 and h >= 1 here, unlike
+        // in NGCircle or others where we test against > 0.
+        assert image == null || (image.getWidth() >= 1 && image.getHeight() >= 1);
+        return super.hasOpaqueRegion() && w >= 1 && h >= 1 && image != null && image.isOpaque();
+    }
+
+    @Override
+    protected RectBounds computeOpaqueRegion(RectBounds opaqueRegion) {
+        return (RectBounds) opaqueRegion.deriveWithNewBounds(x, y, 0, x+w, y+h, 0);
+    }
 }
--- a/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGNode.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGNode.java	Tue Aug 27 09:36:40 2013 -0700
@@ -115,11 +115,20 @@
      * where we have multi-threaded rasterization, we might need to make
      * this per-instance instead of static.
      */
-    protected static final BoxBounds TEMP_BOUNDS = new BoxBounds();
-    protected static final RectBounds TEMP_RECT_BOUNDS = new RectBounds();
+    private static final BoxBounds TEMP_BOUNDS = new BoxBounds();
+    private static final RectBounds TEMP_RECT_BOUNDS = new RectBounds();
     protected static final Affine3D TEMP_TRANSFORM = new Affine3D();
 
     /**
+     * Statics for defining what the culling bits are. We use 2 bits to
+     * determine culling status
+     */
+    static final int DIRTY_REGION_INTERSECTS_NODE_BOUNDS = 0x1;
+    static final int DIRTY_REGION_CONTAINS_NODE_BOUNDS = 0x2;
+    static final int DIRTY_REGION_CONTAINS_OR_INTERSECTS_NODE_BOUNDS =
+            DIRTY_REGION_INTERSECTS_NODE_BOUNDS | DIRTY_REGION_CONTAINS_NODE_BOUNDS;
+
+    /**
      * The transform for this node. Although we are handed all the bounds
      * during synchronization (including the transformed bounds), we still
      * need the transform so that we can apply it to the clip and so forth
@@ -241,15 +250,20 @@
      * Marks position of this node in dirty regions.
      */
     protected int cullingBits = 0x0;
+    private DirtyHint hint;
 
-    static final int CULLING_REGION_INTERSECTS_CLIP = 0x1;
-    static final int CULLING_REGION_CONTAINS_CLIP = 0x2;
-    static final int CULLING_REGION_CONTAINS_OR_INTERSECTS_CLIP =
-            CULLING_REGION_INTERSECTS_CLIP | CULLING_REGION_CONTAINS_CLIP;
+    /**
+     * A cached representation of the opaque region for this node. This
+     * cached version needs to be recomputed whenever the opaque region becomes
+     * invalid, which includes local transform changes (translations included!).
+     */
+    private RectBounds opaqueRegion = null;
 
-    private RectBounds opaqueRegion = null;
+    /**
+     * To avoid object churn we keep opaqueRegion around, and just toggle this
+     * boolean to indicate whether we need to recompute the opaqueRegion.
+     */
     private boolean opaqueRegionInvalid = true;
-    private DirtyHint hint;
 
     protected NGNode() { }
 
@@ -370,6 +384,7 @@
         } else {
             markDirty();
         }
+        invalidateOpaqueRegion();
     }
 
     /**
@@ -389,6 +404,7 @@
             this.clipNode = clipNode;
             // Mark this node dirty, invalidate its cache, and all parents.
             visualsChanged();
+            invalidateOpaqueRegion();
         }
     }
 
@@ -406,8 +422,15 @@
         // then we do not want to invalidate the cache due to an opacity
         // change. However, as usual, all parent caches must be invalidated.
         if (opacity != this.opacity) {
+            final float old = this.opacity;
             this.opacity = opacity;
             markDirty();
+            // Even though the opacity has changed, for example from .5 to .6,
+            // we don't need to invalidate the opaque region unless it has toggled
+            // from 1 to !1, or from !1 to 1.
+            if (old < 1 && (opacity == 1 || opacity == 0) || opacity < 1 && (old == 1 || old == 0)) {
+                invalidateOpaqueRegion();
+            }
         }
     }
 
@@ -416,12 +439,20 @@
      * @param blendMode may be null to indicate "default"
      */
     public void setNodeBlendMode(Blend.Mode blendMode) {
+        // A SRC_OVER blend mode is the same as null, so just convert it here to save us trouble
+        // down the line.
+        if (blendMode == Blend.Mode.SRC_OVER) {
+            blendMode = null;
+        }
+
         // If the blend mode has changed, react. If this node is being cached,
         // then we do not want to invalidate the cache due to a compositing
         // change. However, as usual, all parent caches must be invalidated.
+
         if (this.nodeBlendMode != blendMode) {
             this.nodeBlendMode = blendMode;
             markDirty();
+            invalidateOpaqueRegion();
         }
     }
 
@@ -496,7 +527,13 @@
      * Called by the FX scene graph to set the effect.
      * @param effect the effect (can be null to clear it)
      */
-    public void setEffect(Object effect) {
+    public void setEffect(Effect effect) {
+        final Effect old = getEffect();
+        // When effects are disabled, be sure to reset the effect filter
+        if (PrismSettings.disableEffects) {
+            effect = null;
+        }
+
         // We only need to take action if the effect is different than what was
         // set previously. There are four possibilities. Of these, #1 and #3 matter:
         // 0. effectFilter == null, effect == null
@@ -507,16 +544,25 @@
         // the cache for this node (if there is one) and all parents, and mark
         // this node as dirty.
         if (effectFilter == null && effect != null) {
-            effectFilter = new EffectFilter((Effect)effect, this);
+            effectFilter = new EffectFilter(effect, this);
             visualsChanged();
         } else if (effectFilter != null && effectFilter.getEffect() != effect) {
             effectFilter.dispose();
             effectFilter = null;
             if (effect != null) {
-                effectFilter = new EffectFilter((Effect)effect, this);
+                effectFilter = new EffectFilter(effect, this);
             }
             visualsChanged();
         }
+
+        // The only thing we do with the effect in #computeOpaqueRegion is to check
+        // whether the effect is null / not null. If the answer to these question has
+        // not changed from last time, then there is no need to recompute the opaque region.
+        if (old != effect) {
+            if (old == null || effect == null) {
+                invalidateOpaqueRegion();
+            }
+        }
     }
 
     /**
@@ -705,6 +751,7 @@
 
     protected void geometryChanged() {
         invalidateCache();
+        invalidateOpaqueRegion();
         if (hasVisuals()) {
             markDirty();
         }
@@ -858,10 +905,10 @@
     /***************************************************************************
      *                                                                         *
      * Dirty Regions                                                           *
-     *
+     *                                                                         *
      * Need to add documentation about dirty regions and how they work. One    *
      * thing to be aware of is that during the dirty region accumulation phase *
-     * we use precise floating point values, but during
+     * we use precise floating point values, but during                        *
      *                                                                         *
      **************************************************************************/
 
@@ -901,7 +948,6 @@
      *         smaller than the clip.
      * TODO: Only made non-final for the sake of testing (see javafx-sg-prism tests) (RT-23957)
      */
-
     public /*final*/ int accumulateDirtyRegions(final RectBounds clip,
                                                 final RectBounds dirtyRegionTemp,
                                                 DirtyRegionPool regionPool,
@@ -909,6 +955,10 @@
                                                 final BaseTransform tx,
                                                 final GeneralTransform3D pvTx)
     {
+        // This is the main entry point, make sure to check these inputs for validity
+        if (clip == null || dirtyRegionTemp == null || regionPool == null || dirtyRegionContainer == null ||
+                tx == null || pvTx == null) throw new NullPointerException();
+
         // Even though a node with 0 visibility or 0 opacity doesn't get
         // rendered, it may contribute to the dirty bounds, for example, if it
         // WAS visible or if it HAD an opacity > 0 last time we rendered then
@@ -991,11 +1041,11 @@
      * TODO: Only made non-final for the sake of testing (see javafx-sg-prism tests) (RT-23957)
      */
     int accumulateGroupDirtyRegion(final RectBounds clip,
-                                             final RectBounds dirtyRegionTemp,
-                                             DirtyRegionPool regionPool,
-                                             DirtyRegionContainer dirtyRegionContainer,
-                                             final BaseTransform tx,
-                                             final GeneralTransform3D pvTx) {
+                                   final RectBounds dirtyRegionTemp,
+                                   final DirtyRegionPool regionPool,
+                                   DirtyRegionContainer dirtyRegionContainer,
+                                   final BaseTransform tx,
+                                   final GeneralTransform3D pvTx) {
         // We should have only made it to this point if this node has a dirty
         // child. If this node itself is dirty, this method never would get called.
         // If this node was not dirty and had no dirty children, then this
@@ -1226,64 +1276,49 @@
     /**
      * Culling support for multiple dirty regions.
      * Set culling bits for the whole graph.
-     * @param drc Array of dirty regions.
-     * @param tx The transform for this render operation.
-     * @param pvTx Perspective camera transformation.
+     * @param drc Array of dirty regions. Cannot be null.
+     * @param tx The transform for this render operation. Cannot be null.
+     * @param pvTx Perspective camera transformation. Cannot be null.
      */
-    public void doPreCulling(DirtyRegionContainer drc, BaseTransform tx, GeneralTransform3D pvTx) {
+    public final void doPreCulling(DirtyRegionContainer drc, BaseTransform tx, GeneralTransform3D pvTx) {
+        if (drc == null || tx == null || pvTx == null) throw new NullPointerException();
         markCullRegions(drc, -1, tx, pvTx);
     }
 
     /**
-     * Set culling bits for the node.
-     * @param bounds Bounds of the node.
-     * @param regionIndex Index of dirty region used.
-     * @param region Dirty region being processed.
-     * @return Bit setting encoding node position to dirty region (without the shift)
-     */
-    protected int setCullBits(RectBounds bounds, int regionIndex, RectBounds region) {
-        int b = 0;
-        if (region != null && !region.isEmpty()) {
-            if (region.intersects(bounds)) {
-                b = CULLING_REGION_INTERSECTS_CLIP;
-                if (region.contains(bounds)) {
-                    b = CULLING_REGION_CONTAINS_CLIP;
-                }
-                cullingBits = cullingBits |  (b << (2 * regionIndex));
-            }
-        }
-        return b;
-    }
-
-    /**
      * Marks placement of the node in dirty region encoded into 2 bit flag:
      * 00 - node outside dirty region
      * 01 - node intersecting dirty region
      * 11 - node completely within dirty region
      *
-     * 32 bits = 15 regions max. * 2 bit each.
+     * 32 bits = 15 regions max. * 2 bit each. The first two bits are not used
+     * because we have a special use case for -1, so they should only be set if
+     * in that case.
      *
      * @param drc The array of dirty regions.
      * @param cullingRegionsBitsOfParent culling bits of parent. -1 if there's no parent.
-     * @param tx The transform for this render operation.
-     * @param pvTx Perspective camera transform.
+     * @param tx The transform for this render operation. Cannot be null.
+     * @param pvTx Perspective camera transform. Cannot be null.
      */
-    protected void markCullRegions(
+    void markCullRegions(
             DirtyRegionContainer drc,
             int cullingRegionsBitsOfParent,
             BaseTransform tx,
             GeneralTransform3D pvTx) {
 
+        // Spent a long time tracking down how cullingRegionsBitsOfParent works. Note that it is
+        // not just the parent's bits, but also -1 in the case of the "root", where the root is
+        // either the actual root, or the root of a sub-render operation such as occurs with
+        // render-to-texture for effects!
+
         if (tx.isIdentity()) {
             TEMP_BOUNDS.deriveWithNewBounds(transformedBounds);
         } else {
             tx.transform(transformedBounds, TEMP_BOUNDS);
         }
 
-        if (pvTx != null) {
-            if (!pvTx.isIdentity()) {
-                pvTx.transform(TEMP_BOUNDS, TEMP_BOUNDS);
-            }
+        if (!pvTx.isIdentity()) {
+            pvTx.transform(TEMP_BOUNDS, TEMP_BOUNDS);
         }
 
         TEMP_BOUNDS.flattenInto(TEMP_RECT_BOUNDS);
@@ -1296,9 +1331,19 @@
             if (region == null || region.isEmpty()) {
                 break;
             }
-            if (cullingRegionsBitsOfParent == -1 ||
-                (cullingRegionsBitsOfParent & mask) != 0) {
-                setCullBits(TEMP_RECT_BOUNDS, i, region);
+            // For each dirty region, we will check to see if this child
+            // intersects with the dirty region and whether it contains the
+            // dirty region. Note however, that we only care to mark those
+            // child nodes which are inside a group that intersects. We don't
+            // care about marking child nodes which are within a parent which
+            // is wholly contained within the dirty region.
+            if ((cullingRegionsBitsOfParent == -1 || (cullingRegionsBitsOfParent & mask) != 0) &&
+                    region.intersects(TEMP_RECT_BOUNDS)) {
+                int b = DIRTY_REGION_INTERSECTS_NODE_BOUNDS;
+                if (region.contains(TEMP_RECT_BOUNDS)) {
+                    b = DIRTY_REGION_CONTAINS_NODE_BOUNDS;
+                }
+                cullingBits = cullingBits | (b << (2 * i));
             }
             mask = mask << 2;
         }//for
@@ -1337,47 +1382,78 @@
      * Identifying render roots                                                *
      *                                                                         *
      **************************************************************************/
+    protected static enum RenderRootResult {
+        /**
+         * The computation to determine whether a branch of the scene graph has
+         * a render root has concluded that indeed, there is one.
+         */
+        HAS_RENDER_ROOT,
+        /**
+         * A RenderRootResult of this value means that although we discovered a
+         * render root, we also determined that there were no dirty nodes that
+         * followed the render root. Therefore, we don't actually have to render
+         * anything (the only dirty nodes are completely occluded by clean
+         * nodes).
+         */
+        EXISTS_BUT_NOT_DIRTY,
+        /**
+         * Represents the case where we did not find an opaque node that covered
+         * the dirty region, and thus we must start rendering from the actual
+         * root of the hierarchy.
+         */
+        NONE
+    }
 
     /**
      * Called <strong>after</strong> preCullingBits in order to get the node
      * from which we should begin drawing. This is our support for occlusion culling.
      * This should only be called on the root node.
      *
+     * If no render root was found, we need to render everything from this root, so the path will contain this node.
+     * If no rendering is needed (everything dirty is occluded), the path will remain empty
+     *
      * @param path node path to store the node path
-     * @return new node path (preferably == path) with first node being a child of this node. Null if renderRoot == this.
      */
-    public final NodePath<NGNode> getRenderRoot(NodePath<NGNode> path, RectBounds dirtyRegion, int cullingIndex, BaseTransform tx,
-                                      GeneralTransform3D pvTx) {
-        // The occlusion culling support depends on dirty opts being enabled
-        if (PrismSettings.occlusionCullingEnabled) {
-            NodePath<NGNode> rootPath = computeRenderRoot(path, dirtyRegion, cullingIndex, tx, pvTx);
-            if (rootPath != null) {
-                rootPath.removeRoot();
-                return rootPath.size() != 0 ? rootPath : null;
-            }
+    public final void getRenderRoot(NodePath<NGNode> path, RectBounds dirtyRegion, int cullingIndex,
+                                                BaseTransform tx, GeneralTransform3D pvTx) {
+
+        // This is the main entry point, make sure to check these inputs for validity
+        if (path == null || dirtyRegion == null || tx == null || pvTx == null) {
+            throw new NullPointerException();
         }
-        return null;
+        if (cullingIndex < -1 || cullingIndex > 15) {
+            throw new IllegalArgumentException("cullingIndex cannot be < -1 or > 15");
+        }
+
+        // This method must NEVER BE CALLED if the depth buffer is turned on. I don't have a good way to test
+        // for that because NGNode doesn't have a reference to the scene it is a part of...
+
+        RenderRootResult result = computeRenderRoot(path, dirtyRegion, cullingIndex, tx, pvTx);
+        if (result == RenderRootResult.NONE) {
+            //Render from the root
+            path.add(this);
+        }
     }
 
     /**
      * Searches for the last node that covers all of the specified dirty region with opaque region,
      * in this node's subtree.
      * Such node can serve as a rendering root as all nodes preceding the node will be covered by it.
-     * @param dirtyRegion the current dirty region
+     * @param dirtyRegion the current dirty region. Cannot be null.
      * @param cullingIndex index of culling information
-     * @param tx current transform
-     * @param pvTx current perspective transform
+     * @param tx current transform. Cannot be null.
+     * @param pvTx current perspective transform. Cannot be null.
      * @return New rendering root or null if no such node exists in this subtree
      */
-    protected NodePath<NGNode> computeRenderRoot(NodePath<NGNode> path, RectBounds dirtyRegion, int cullingIndex, BaseTransform tx,
-                                       GeneralTransform3D pvTx) {
+    RenderRootResult computeRenderRoot(NodePath<NGNode> path, RectBounds dirtyRegion,
+                                       int cullingIndex, BaseTransform tx, GeneralTransform3D pvTx) {
         return computeNodeRenderRoot(path, dirtyRegion, cullingIndex, tx, pvTx);
     }
 
     private static Point2D[] TEMP_POINTS2D_4 =
             new Point2D[] { new Point2D(), new Point2D(), new Point2D(), new Point2D() };
 
-    // Whether (px, py) is clockwise or counter-clowise to a->b
+    // Whether (px, py) is clockwise or counter-clockwise to a->b
     private static int ccw(double px, double py, Point2D a, Point2D b) {
         return (int)Math.signum(((b.x - a.x) * (py - a.y)) - (b.y - a.y) * (px - a.x));
     }
@@ -1406,54 +1482,61 @@
 
     /**
      * Check if this node can serve as rendering root for this dirty region.
-     * @param dirtyRegion the current dirty region
+     * @param dirtyRegion the current dirty region. Cannot be null.
      * @param cullingIndex index of culling information, -1 means culling information should not be used
-     * @param tx current transform
-     * @param pvTx current perspective transform
+     * @param tx current transform. Cannot be null.
+     * @param pvTx current perspective transform. Cannot be null.
      * @return this node if this node's opaque region covers the specified dirty region. Null otherwise.
      */
-    protected final NodePath<NGNode> computeNodeRenderRoot(NodePath<NGNode> path, RectBounds dirtyRegion, int cullingIndex, BaseTransform tx,
-                                       GeneralTransform3D pvTx) {
+    final RenderRootResult computeNodeRenderRoot(NodePath<NGNode> path, RectBounds dirtyRegion,
+                                                 int cullingIndex, BaseTransform tx, GeneralTransform3D pvTx) {
 
         // Nodes outside of the dirty region can be excluded immediately.
         // This can be used only if the culling information is provided.
         if (cullingIndex != -1) {
             final int bits = cullingBits >> (cullingIndex * 2);
-            if ((bits & CULLING_REGION_CONTAINS_OR_INTERSECTS_CLIP) == 0x00) {
-                return null;
+            if ((bits & DIRTY_REGION_CONTAINS_OR_INTERSECTS_NODE_BOUNDS) == 0x00) {
+                return RenderRootResult.NONE;
             }
         }
 
         if (!isVisible()) {
-            return null;
+            return RenderRootResult.NONE;
         }
 
-        // Walk down the tree to the very end. Then working our way back up to
-        // the top of the tree, look for the first node which which marked as
-        // dirty opts 01, and then return it.
+
         final RectBounds opaqueRegion = getOpaqueRegion();
-        if (opaqueRegion == null) return null;
+        if (opaqueRegion == null) return RenderRootResult.NONE;
 
         final BaseTransform localToParentTx = getTransform();
 
         BaseTransform localToSceneTx = TEMP_TRANSFORM.deriveWithNewTransform(tx).deriveWithConcatenation(localToParentTx);
 
-        // Now check if the dirty region is fully contained in our opaque region.
+        // Now check if the dirty region is fully contained in our opaque region. Suppose the above
+        // transform included a rotation about Z. In these cases, the transformed
+        // opaqueRegion might be some non-axis aligned quad. So what we need to do is to check
+        // that each corner of the dirty region lies within the (potentially rotated) quad
+        // of the opaqueRegion.
         if (checkBoundsInQuad(opaqueRegion, dirtyRegion, localToSceneTx, pvTx)) {
+            // We have the potential render root, now check if it needs to be rendered
+            if (dirty != DirtyFlag.CLEAN || childDirty) {
                 path.add(this);
-                return path;
+                return RenderRootResult.HAS_RENDER_ROOT;
+            } else {
+                return RenderRootResult.EXISTS_BUT_NOT_DIRTY;
+            }
         }
 
-        return null;
+        return RenderRootResult.NONE;
     }
 
-    protected static boolean checkBoundsInQuad(RectBounds untransformedQuad,
+    static boolean checkBoundsInQuad(RectBounds untransformedQuad,
             RectBounds innerBounds, BaseTransform tx, GeneralTransform3D pvTx) {
 
-        if ((pvTx == null || pvTx.isIdentity()) && (tx.getType() & ~(BaseTransform.TYPE_TRANSLATION
+        if (pvTx.isIdentity() && (tx.getType() & ~(BaseTransform.TYPE_TRANSLATION
                 | BaseTransform.TYPE_QUADRANT_ROTATION
                 | BaseTransform.TYPE_MASK_SCALE)) == 0) {
-            //If there's no pvTx and there's simple transformation that will result in axis-aligned rectangle,
+            // If pvTx is identity and there's simple transformation that will result in axis-aligned rectangle,
             // we can do a quick test by using bound.contains()
             if (tx.isIdentity()) {
                 TEMP_BOUNDS.deriveWithNewBounds(untransformedQuad);
@@ -1472,7 +1555,7 @@
 
             for (Point2D p : TEMP_POINTS2D_4) {
                 tx.transform(p, p);
-                if (pvTx != null) {
+                if (!pvTx.isIdentity()) {
                     pvTx.transform(p, p);
                 }
             }
@@ -1484,22 +1567,136 @@
         }
     }
 
+    /**
+     * Invalidates any cached representation of the opaque region for this node. On the next
+     * call to getOpaqueRegion, the opaque region will be recalculated. Any changes to state
+     * which is used in the {@link #hasOpaqueRegion()} call must invoke this method
+     * or the opaque region calculations will be wrong.
+     */
+    protected final void invalidateOpaqueRegion() {
+        opaqueRegionInvalid = true;
+        if (isClip) parent.invalidateOpaqueRegion();
+    }
+
+    /**
+     * Gets the opaque region for this node, if there is one, or returns null.
+     * @return The opaque region for this node, or null.
+     */
     final RectBounds getOpaqueRegion() {
-        if (opaqueRegionInvalid) {
-            opaqueRegion = computeOpaqueRegion(opaqueRegion);
+        // Note that when we invalidate the opaqueRegion of an NGNode, we don't
+        // walk up the tree or communicate with the parents (unlike dirty flags).
+        // An NGGroup does not compute an opaqueRegion based on the union of opaque
+        // regions of its children (although this is a fine idea to consider!). See RT-32441
+        // If we ever fix RT-32441, we must be sure to handle the case of a Group being used
+        // as a clip node (such that invalidating a child on the group invalidates the
+        // opaque region of every node up to the root).
+
+        // Because the Effect classes have no reference to NGNode, they cannot tell the
+        // NGNode to invalidate the opaque region whenever properties on the Effect that
+        // would impact the opaqueRegion change. As a result, when an Effect is specified
+        // on the NGNode, we will always treat it as if it were invalid. A more invasive
+        // (but better) change would be to give Effect the ability to invalidate the
+        // NGNode's opaque region when needed.
+        if (opaqueRegionInvalid || getEffect() != null) {
             opaqueRegionInvalid = false;
+            if (supportsOpaqueRegions() && hasOpaqueRegion()) {
+                opaqueRegion = computeOpaqueRegion(opaqueRegion == null ? new RectBounds() : opaqueRegion);
+                // If we got a null result then we encountered an error condition where somebody
+                // claimed supportsOpaqueRegions and hasOpaqueRegion, but then they
+                // returned null! This should never happen, so we have an assert here. However since
+                // assertions are disabled at runtime and we want to avoid the NPE, we also perform
+                // a null check.
+                assert opaqueRegion != null;
+                if (opaqueRegion == null) {
+                    return null;
+                }
+                // If there is a clip, then we need to determine the opaque region of the clip, and
+                // intersect that with our existing opaque region. For example, if I had a rectangle
+                // with a circle for its clip (centered over the rectangle), then the result needs to
+                // be the circle's opaque region.
+                final NGNode clip = getClipNode();
+                if (clip != null) {
+                    final RectBounds clipOpaqueRegion = clip.getOpaqueRegion();
+                    // Technically a flip/quadrant rotation is allowed as well, but we don't have a convenient
+                    // way to do that yet.
+                    if (clipOpaqueRegion == null || (clip.getTransform().getType() & ~(BaseTransform.TYPE_TRANSLATION | BaseTransform.TYPE_MASK_SCALE)) != 0) {
+                        // RT-25095: If this node has a clip who's opaque region cannot be determined, then
+                        // we cannot determine any opaque region for this node (in fact, it might not have one).
+                        // Also, if the transform is something other than identity, scale, or translate then
+                        // we're just going to bail (sorry, rotate, maybe next time!)
+                        return opaqueRegion = null;
+                    }
+                    // We have to take into account any transform specified on the clip to put
+                    // it into the same coordinate system as this node
+                    final BaseBounds b = clip.getTransform().transform(clipOpaqueRegion, TEMP_BOUNDS);
+                    b.flattenInto(TEMP_RECT_BOUNDS);
+                    opaqueRegion.intersectWith(TEMP_RECT_BOUNDS);
+
+                }
+            } else {
+                // The opaqueRegion may have been non-null in the past, but there isn't an opaque region now,
+                // so we will nuke it to save some memory
+                opaqueRegion = null;
+            }
         }
+
         return opaqueRegion;
     }
 
-    protected void invalidateOpaqueRegion() {
-        opaqueRegionInvalid = true;
+    /**
+     * Gets whether this NGNode supports opaque regions at all. Most node types do not,
+     * but some do. If an NGNode subclass is written to support opaque regions, it must override
+     * this method to return true. The subclass must then also override the computeDirtyRegion method
+     * to return the dirty region, or null if the node in its current state doesn't have one.
+     * This method is intended to be immutable.
+     *
+     * @return Whether this NGNode implementation supports opaque regions. This could also have been
+     *         implemented via an interface that some NGNodes implemented, but then we'd have instanceof
+     *         checks which I'd rather avoid.
+     */
+    protected boolean supportsOpaqueRegions() { return false; }
+
+    /**
+     * Called only on NGNode subclasses which override {@link #supportsOpaqueRegions()} to return
+     * true, this method will return whether or not this NGNode is in a state where it has
+     * an opaque region to actually return. If this method returns true, a subsequent call to
+     * {@link #computeOpaqueRegion(com.sun.javafx.geom.RectBounds)} <strong>must</strong> return
+     * a non-null result. Any state used in the computation of this method, when it changes, must
+     * result in a call to {@link #invalidateOpaqueRegion()}.
+     *
+     * @return Whether this NGNode currently has an opaque region.
+     */
+    protected boolean hasOpaqueRegion() {
+        final NGNode clip = getClipNode();
+        final Effect effect = getEffect();
+        return (effect == null || !effect.reducesOpaquePixels()) &&
+               getOpacity() == 1f &&
+               (nodeBlendMode == null || nodeBlendMode == Blend.Mode.SRC_OVER) &&
+               (clip == null ||
+               (clip.supportsOpaqueRegions() && clip.hasOpaqueRegion()));
     }
 
+    /**
+     * Computes and returns the opaque region for this node. This method
+     * @param opaqueRegion
+     * @return
+     */
     protected RectBounds computeOpaqueRegion(RectBounds opaqueRegion) {
         return null;
     }
 
+    /**
+     * Returns whether a clip represented by this node can be rendered using
+     * axis aligned rect clip. The default implementation returns false,
+     * specific subclasses should override to return true when appropriate.
+     *
+     * @return whether this rectangle is axis aligned when rendered given node's
+     * and rendering transform
+     */
+    protected boolean isRectClip(BaseTransform xform, boolean permitRoundedRectangle) {
+        return false;
+    }
+
     /***************************************************************************
      *                                                                         *
      * Rendering                                                               *
@@ -1550,11 +1747,11 @@
             if (g.hasPreCullingBits()) {
                 //preculling bits available
                 final int bits = cullingBits >> (g.getClipRectIndex() * 2);
-                if ((bits & CULLING_REGION_CONTAINS_OR_INTERSECTS_CLIP) == 0) {
+                if ((bits & DIRTY_REGION_CONTAINS_OR_INTERSECTS_NODE_BOUNDS) == 0) {
                     // If no culling bits are set for this region, this group
                     // does not intersect (nor is covered by) the region
                     return;
-                } else if ((bits & CULLING_REGION_CONTAINS_CLIP) != 0) {
+                } else if ((bits & DIRTY_REGION_CONTAINS_NODE_BOUNDS) != 0) {
                     // When this group is fully covered by the region,
                     // turn off the culling checks in the subtree, as everything
                     // gets rendered
@@ -1723,7 +1920,7 @@
         newClip.intersectWith(PrEffectHelper.getGraphicsClipNoClone(g));
         if (newClip.isEmpty() ||
             newClip.getWidth() == 0 ||
-            newClip .getHeight() == 0) {
+            newClip.getHeight() == 0) {
             clearDirtyTree();
             return;
         }
@@ -1896,14 +2093,14 @@
         // The first check is for any of its children contains a 3D Transform.
         // The second check is for any of its parents and itself has a 3D Transform
         if (isContentBounds2D() && g.getTransformNoClone().is2D()) {
-            ((CacheFilter) getCacheFilter()).render(g);
+            getCacheFilter().render(g);
         } else {
             renderContent(g);
         }
     }
 
     protected void renderEffect(Graphics g) {
-        ((EffectFilter)getEffectFilter()).render(g);
+        getEffectFilter().render(g);
     }
 
     protected abstract void renderContent(Graphics g);
--- a/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGRectangle.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGRectangle.java	Tue Aug 27 09:36:40 2013 -0700
@@ -34,7 +34,6 @@
 import com.sun.prism.Graphics;
 import com.sun.prism.RectShadowGraphics;
 import com.sun.prism.paint.Color;
-import com.sun.prism.paint.Paint;
 import com.sun.prism.shape.ShapeRep;
 import com.sun.scenario.effect.Effect;
 import static com.sun.javafx.geom.transform.BaseTransform.TYPE_MASK_SCALE;
@@ -56,77 +55,45 @@
         rrect.arcWidth = arcWidth;
         rrect.arcHeight = arcHeight;
         geometryChanged();
-        invalidateOpaqueRegion();
     }
 
     @Override
-    public void setFillPaint(Object fillPaint) {
-        invalidateOpaqueRegion();
-        super.setFillPaint(fillPaint);
+    protected boolean supportsOpaqueRegions() { return true; }
+
+    @Override
+    protected boolean hasOpaqueRegion() {
+        return super.hasOpaqueRegion() && rrect.width > 1 && rrect.height > 1;
     }
 
-    @Override
-    public void setMode(Mode mode) {
-        invalidateOpaqueRegion();
-        super.setMode(mode);
-    }
+    static final float HALF_MINUS_HALF_SQRT_HALF = 0.5f - NGCircle.HALF_SQRT_HALF;
 
     @Override
-    public void setOpacity(float opacity) {
-        invalidateOpaqueRegion();
-        super.setOpacity(opacity);
-    }
+    protected RectBounds computeOpaqueRegion(RectBounds opaqueRegion) {
+        // Normally the "opaque region" for a rectangle would be the
+        // x, y, w, h unless it has rounded corners, in which case
+        // we subtract the arc width and arc height.
+        final float x = rrect.x;
+        final float y = rrect.y;
+        final float w = rrect.width;
+        final float h = rrect.height;
+        final float aw = rrect.arcWidth;
+        final float ah = rrect.arcHeight;
 
-    @Override
-    public void setClipNode(NGNode clipNode) {
-        invalidateOpaqueRegion();
-        super.setClipNode(clipNode);
-    }
-
-    @Override
-    public void setEffect(Object effect) {
-        invalidateOpaqueRegion();
-        super.setEffect(effect);
-    }
-
-    @Override
-    public void setTransformMatrix(BaseTransform tx) {
-        invalidateOpaqueRegion();
-        super.setTransformMatrix(tx);
-    }
-
-    @Override protected RectBounds computeOpaqueRegion(RectBounds opaqueRegion) {
-        // compute opaque region
-        final Mode mode = getMode();
-        final Paint fillPaint = getFillPaint();
-        final NGNode clip = (NGNode) getClipNode();
-        final Effect effect = getEffect();
-        if ((effect == null || !effect.reducesOpaquePixels()) &&
-                getOpacity() == 1f &&
-                (mode == Mode.FILL || mode == Mode.STROKE_FILL) &&
-                (fillPaint != null && fillPaint.isOpaque()) &&
-                (clip == null || 
-                (clip instanceof NGRectangle && ((NGRectangle)clip).isRectClip(BaseTransform.IDENTITY_TRANSFORM, true)))) {
-            // Normally the "opaque region" for a rectangle would be the
-            // x, y, w, h unless it has rounded corners, in which case
-            // we subtract the arc width and arc height.
-            final float x = rrect.x + rrect.arcWidth;
-            final float y = rrect.y + rrect.arcHeight;
-            final float width = rrect.getWidth() - rrect.arcWidth - rrect.arcWidth;
-            final float height = rrect.getHeight() - rrect.arcHeight - rrect.arcHeight;
-            if (width > 1 && height > 1) {
-                if (opaqueRegion == null) {
-                    opaqueRegion = new RectBounds(x, y, x + width, y + height); 
-                } else {
-                    opaqueRegion.deriveWithNewBounds(x, y, 0, x + width, y + height, 0);
-                }
-                if (clip != null) {
-                    opaqueRegion.intersectWith((clip).getOpaqueRegion());
-                }
-                return opaqueRegion;
-            }
+        if (aw <= 0 || ah <= 0) {
+            // This is the simple case of a rectangle. Note the "||" is correct in the if statement,
+            // because regardless of the size of aw, if ah <= 0 (or vice versa) we draw a non-rounded
+            // rectangle, so we should always enter this case for things that get drawn as rectangles
+            return (RectBounds) opaqueRegion.deriveWithNewBounds(x, y, 0, x + w, y + h, 0);
+        } else {
+            // Gives us a reasonable number of pixels that are the interior of the rounded rectangle
+            // including when aw / ah is massive (in which case we just render an ellipse with w/h
+            // as the dimensions).
+            final float arcInsetWidth = Math.min(w, aw) * HALF_MINUS_HALF_SQRT_HALF;
+            final float arcInsetHeight = Math.min(h, ah) * HALF_MINUS_HALF_SQRT_HALF;
+            return (RectBounds) opaqueRegion.deriveWithNewBounds(
+                    x + arcInsetWidth, y + arcInsetHeight, 0,
+                    x + w - arcInsetWidth, y + h - arcInsetHeight, 0);
         }
-        return null;
     }
 
     boolean isRounded() {
@@ -281,7 +248,7 @@
      * @return whether this rectangle is axis aligned when rendered given node's
      * and rendering transform
      */
-    final boolean isRectClip(BaseTransform xform, boolean permitRoundedRectangle) {
+    @Override protected final boolean isRectClip(BaseTransform xform, boolean permitRoundedRectangle) {
         // must be a simple fill of a non-round rect with opaque paint
         // With more work we could optimize the case of a Rectangle with a
         // Rectangle as a clip, but that would likely slow down some more
--- a/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGRegion.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGRegion.java	Tue Aug 27 09:36:40 2013 -0700
@@ -45,11 +45,16 @@
 import javafx.scene.shape.StrokeLineCap;
 import javafx.scene.shape.StrokeLineJoin;
 import javafx.scene.shape.StrokeType;
+
 import java.util.List;
+import java.util.WeakHashMap;
+
+import com.sun.glass.ui.Screen;
 import com.sun.javafx.PlatformUtil;
 import com.sun.javafx.application.PlatformImpl;
 import com.sun.javafx.geom.Path2D;
 import com.sun.javafx.geom.RectBounds;
+import com.sun.javafx.geom.Rectangle;
 import com.sun.javafx.geom.Shape;
 import com.sun.javafx.geom.transform.Affine2D;
 import com.sun.javafx.geom.transform.BaseTransform;
@@ -61,11 +66,9 @@
 import com.sun.prism.Image;
 import com.sun.prism.RTTexture;
 import com.sun.prism.Texture;
-import com.sun.prism.Texture.WrapMode;
 import com.sun.prism.impl.PrismSettings;
 import com.sun.prism.paint.ImagePattern;
 import com.sun.prism.paint.Paint;
-import com.sun.scenario.effect.Effect;
 import com.sun.scenario.effect.Offset;
 
 /**
@@ -82,10 +85,18 @@
     private static final Affine2D SCRATCH_AFFINE = new Affine2D();
 
     /**
-     * The texture cache used by all regions for storing background fills / shapes which
-     * can be easily cached and reused.
+     * Temporary rect for general use. Because this is a static variable,
+     * it is only intended to be used from a single thread, the render thread
+     * in this case.
      */
-    private static final RegionImageCache CACHE = new RegionImageCache();
+    private static final Rectangle TEMP_RECT = new Rectangle();
+
+    /**
+     * Screen to RegionImageCache mapping. This mapping is required as textures
+     * are only valid in graphics context used to create them (relies on a one
+     * to one mapping between Screen and GraphicsContext).
+     */
+    private static WeakHashMap<Screen, RegionImageCache> imageCacheMap = new WeakHashMap<>();
 
     /**
      * Indicates the cached image can be sliced vertically.
@@ -164,6 +175,12 @@
     private int cacheMode;
 
     /**
+     * Is the key into the image cache that identifies the required background
+     * for the region.
+     */
+    private Integer cacheKey;
+
+    /**
      * Simple Helper Function for cleanup.
      */
     static Paint getPlatformPaint(javafx.scene.paint.Paint paint) {
@@ -198,6 +215,7 @@
         this.centerShape = positionShape;
         this.cacheShape = cacheShape;
         invalidateOpaqueRegion();
+        cacheKey = null;
     }
 
     /**
@@ -212,6 +230,7 @@
         this.height = height;
         invalidateOpaqueRegion();
         backgroundInsets = null;
+        cacheKey = null;
     }
 
     /**
@@ -278,6 +297,7 @@
             }
         }
         backgroundInsets = null;
+        cacheKey = null;
 
         // Only update the geom if the new background is geometrically different from the old
         if (!background.getOutsets().equals(old.getOutsets())) {
@@ -335,56 +355,6 @@
         invalidateOpaqueRegion();
     }
 
-    /**
-     * Overridden so as to invalidate the opaque region, since the opaque region computation
-     * must take opacity into account.
-     *
-     * @param opacity A value between 0 and 1.
-     */
-    @Override public void setOpacity(float opacity) {
-        // We certainly don't want to do any work if opacity hasn't changed!
-        final float old = getOpacity();
-        if (old != opacity) {
-            super.setOpacity(opacity);
-            // Even though the opacity has changed, for example from .5 to .6,
-            // we don't need to invalidate the opaque region unless it has toggled
-            // from 1 to !1, or from !1 to 1.
-            if (old < 1 || opacity < 1) invalidateOpaqueRegion();
-        }
-    }
-
-    /**
-     * Overridden so that we can invalidate the opaque region when the clip
-     * has changed.
-     *
-     * @param clipNode can be null if the clip node is being cleared
-     */
-    @Override public void setClipNode(NGNode clipNode) {
-        super.setClipNode(clipNode);
-        invalidateOpaqueRegion();
-    }
-
-    /**
-     * Overridden so as to invalidate the opaque region when the effect changes.
-     *
-     * @param effect
-     */
-    @Override public void setEffect(Object effect) {
-        // Lets only do work if we have to
-        Effect old = getEffect();
-        if (old != effect) {
-            super.setEffect(effect);
-            // The only thing we do with the effect in #computeOpaqueRegion(RectBounds) is to check
-            // whether the effect is null / not null, and whether a not null effect reduces opaque
-            // pixels. If the answer to these question has not changed from last time, then there
-            // is no need to recompute the opaque region.
-            if (old == null || effect == null ||
-                    old.reducesOpaquePixels() != ((Effect)effect).reducesOpaquePixels()){
-                invalidateOpaqueRegion();
-            }
-        }
-    }
-
     /**************************************************************************
      *                                                                        *
      * Implementations of methods defined in the parent classes, with the     *
@@ -392,6 +362,38 @@
      *                                                                        *
      *************************************************************************/
 
+    private RegionImageCache getImageCache(Graphics g) {
+        Screen screen = g.getAssociatedScreen();
+        RegionImageCache cache = imageCacheMap.get(screen);
+        if (cache == null) {
+            cache = new RegionImageCache(g);
+            imageCacheMap.put(screen, cache);
+        }
+        return cache;
+    }
+
+    private Integer getCacheKey(int w, int h) {
+        if (cacheKey == null) {
+            int key = 31 * w;
+            key = key * 37 + h;
+            key = key * 47 + background.hashCode();
+            if (shape != null) {
+                key = key * 73 + shape.hashCode();
+            }
+            cacheKey = key;
+        }
+        return cacheKey;
+    }
+
+    @Override protected boolean supportsOpaqueRegions() { return true; }
+
+    @Override
+    protected boolean hasOpaqueRegion() {
+        return super.hasOpaqueRegion() &&
+                !Float.isNaN(opaqueTop) && !Float.isNaN(opaqueRight) &&
+                !Float.isNaN(opaqueBottom) && !Float.isNaN(opaqueLeft);
+    }
+
     /**
      * The opaque region of an NGRegion takes into account the opaque insets
      * specified by the Region during synchronization. It also takes into
@@ -401,52 +403,21 @@
      * @return
      */
     @Override protected RectBounds computeOpaqueRegion(RectBounds opaqueRegion) {
-        final NGNode clip = getClipNode();
-        final Effect effect = getEffect();
-        // compute opaque region
-        if ((effect == null || !effect.reducesOpaquePixels()) &&
-                getOpacity() == 1f &&
-                (clip == null ||
-                (clip instanceof NGRectangle && ((NGRectangle)clip).isRectClip(BaseTransform.IDENTITY_TRANSFORM, true))))
-        {
-            if (Float.isNaN(opaqueTop) || Float.isNaN(opaqueRight) || Float.isNaN(opaqueBottom) || Float.isNaN(opaqueLeft)) {
-                return null;
-            }
-
-            // TODO what to do if the opaqueRegion has negative width or height due to excessive opaque insets? (RT-26979)
-            if (opaqueRegion == null) {
-                opaqueRegion = new RectBounds(opaqueLeft, opaqueTop, width - opaqueRight, height - opaqueBottom);
-            } else {
-                opaqueRegion.deriveWithNewBounds(opaqueLeft, opaqueTop, 0, width - opaqueRight, height - opaqueBottom, 0);
-            }
-
-            if (clip != null) { // We already know that clip is rectangular
-                // RT-25095: If this node has a clip who's opaque region cannot be determined, then
-                // we cannot determine any opaque region for this node (in fact, it might not have one).
-                final RectBounds clipOpaqueRegion = clip.getOpaqueRegion();
-                if (clipOpaqueRegion == null) {
-                    return null;
-                } else {
-                    opaqueRegion.intersectWith(clipOpaqueRegion);
-                }
-            }
-
-            return opaqueRegion;
-        }
-        return null;
+        // TODO what to do if the opaqueRegion has negative width or height due to excessive opaque insets? (RT-26979)
+        return (RectBounds) opaqueRegion.deriveWithNewBounds(opaqueLeft, opaqueTop, 0, width - opaqueRight, height - opaqueBottom, 0);
     }
 
-    @Override protected NodePath<NGNode> computeRenderRoot(NodePath<NGNode> path, RectBounds dirtyRegion,
+    @Override protected RenderRootResult computeRenderRoot(NodePath<NGNode> path, RectBounds dirtyRegion,
                                                            int cullingIndex, BaseTransform tx,
                                                            GeneralTransform3D pvTx) {
 
-        NodePath<NGNode> childPath = super.computeRenderRoot(path, dirtyRegion, cullingIndex, tx, pvTx);
-        if (childPath != null) {
-            childPath.add(this);
-        } else {
-            childPath = computeNodeRenderRoot(path, dirtyRegion, cullingIndex, tx, pvTx);
+        RenderRootResult result = super.computeRenderRoot(path, dirtyRegion, cullingIndex, tx, pvTx);
+        if (result == RenderRootResult.HAS_RENDER_ROOT) {
+            path.add(this);
+        } else if (result == RenderRootResult.NONE){
+            result = computeNodeRenderRoot(path, dirtyRegion, cullingIndex, tx, pvTx);
         }
-        return childPath;
+        return result;
     }
 
     @Override protected boolean hasVisuals() {
@@ -503,7 +474,8 @@
         if (shape != null) {
             if (!background.isEmpty()) {
                 final Insets outsets = background.getOutsets();
-                final Shape outsetShape = resizeShape((float) -outsets.getTop(), (float) -outsets.getRight(), (float) -outsets.getBottom(), (float) -outsets.getLeft());
+                final Shape outsetShape = resizeShape((float) -outsets.getTop(), (float) -outsets.getRight(),
+                                                      (float) -outsets.getBottom(), (float) -outsets.getLeft());
                 final RectBounds outsetShapeBounds = outsetShape.getBounds();
                 final int textureWidth = Math.round(outsetShapeBounds.getWidth()),
                           textureHeight = Math.round(outsetShapeBounds.getHeight());
@@ -513,89 +485,36 @@
                 // all examples of cases where we'd like to reuse a cached image for performance reasons rather
                 // than re-drawing everything each time.
 
+                RTTexture cached = null;
+                Rectangle rect = null;
                 // RT-25013: We need to make sure that we do not use a cached image in the case of a
                 // scaled region, or things won't look right (they'll looked scaled instead of vector-resized).
-                final boolean cache = cacheMode != 0 && g.getTransformNoClone().isTranslateOrIdentity();
-                RTTexture cached = cache ? CACHE.getImage(g.getAssociatedScreen(), textureWidth, textureHeight, background, shape) : null;
-                if (cached != null) {
-                    cached.lock();
-                    if (cached.isSurfaceLost()) {
-                        cached = null;
+                if (cacheMode != 0 && g.getTransformNoClone().isTranslateOrIdentity()) {
+                    RegionImageCache imageCache = getImageCache(g);
+                    if (imageCache.isImageCachable(textureWidth, textureHeight)) {
+                        final Integer key = getCacheKey(textureWidth, textureHeight);
+                        rect = TEMP_RECT;
+                        rect.setBounds(0, 0, textureWidth, textureHeight);
+                        boolean render = imageCache.getImageLocation(key, rect, background, shape, g);
+                        if (!rect.isEmpty()) {
+                            // An empty rect indicates a failure occurred in the imageCache
+                            cached = imageCache.getBackingStore();
+                        }
+                        if (cached != null && render) {
+                            Graphics cachedGraphics = cached.createGraphics();
+
+                            // Have to move the origin such that when rendering to x=0, we actually end up rendering
+                            // at x=bounds.getMinX(). Otherwise anything rendered to the left of the origin would be lost
+                            cachedGraphics.translate(rect.x - outsetShapeBounds.getMinX(),
+                                                     rect.y - outsetShapeBounds.getMinY());
+                            renderBackgroundShape(cachedGraphics);
+                            if (PulseLogger.PULSE_LOGGING_ENABLED) {
+                                PulseLogger.PULSE_LOGGER.renderIncrementCounter("Rendering region shape image to cache");
+                            }
+                        }
                     }
                 }
-                // If there is not a cached texture already, then we need to render everything
-                if (cached == null) {
-                    // We will here check to see if we CAN cache the region background. If not, then
-                    // we will render as normal. If we can cache it, however, then we will setup a
-                    // texture and swizzle rendering onto the RTTexture's graphics, and then at the
-                    // end do render from the texture onto the graphics object we were passed.
-                    Graphics old = null;
-                    if (cache && CACHE.isImageCachable(textureWidth, textureHeight)) {
-                        old = g;
-                        cached = g.getResourceFactory().createRTTexture(textureWidth, textureHeight,
-                                                                        WrapMode.CLAMP_TO_ZERO);
-                        cached.contentsUseful();
-                        g = cached.createGraphics();
-                        // Have to move the origin such that when rendering to x=0, we actually end up rendering
-                        // at x=bounds.getMinX(). Otherwise anything rendered to the left of the origin would be lost
-                        g.translate(-outsetShapeBounds.getMinX(), -outsetShapeBounds.getMinY());
-                        CACHE.setImage(cached, old.getAssociatedScreen(), textureWidth, textureHeight, background, shape);
-                        if (PulseLogger.PULSE_LOGGING_ENABLED) {
-                            PulseLogger.PULSE_LOGGER.renderIncrementCounter("Region shape image cached");
-                        }
-                    }
 
-                    // We first need to draw each background fill. We don't pay any attention
-                    // to the radii of the BackgroundFill, but we do honor the insets and
-                    // the fill paint itself.
-                    final List<BackgroundFill> fills = background.getFills();
-                    for (int i = 0, max = fills.size(); i < max; i++) {
-                        final BackgroundFill fill = fills.get(i);
-                        // Get the paint for this BackgroundFill. It should not be possible
-                        // for it to ever be null
-                        final Paint paint = getPlatformPaint(fill.getFill());
-                        assert paint != null;
-                        g.setPaint(paint);
-                        // Adjust the box within which we will fit the shape based on the
-                        // insets. The resize shape method will resize the shape to fit
-                        final Insets insets = fill.getInsets();
-                        g.fill(resizeShape((float) insets.getTop(), (float) insets.getRight(),
-                                           (float) insets.getBottom(), (float) insets.getLeft()));
-                    }
-                    // We now need to draw each background image. Only the "cover" property
-                    // of BackgroundImage, and the "image" property itself, have any impact
-                    // on how the image is applied to a Shape.
-                    final List<BackgroundImage> images = background.getImages();
-                    for (int i = 0, max = images.size(); i < max; i++) {
-                        final BackgroundImage image = images.get(i);
-                        final Image prismImage = (Image) image.getImage().impl_getPlatformImage();
-                        if (prismImage == null) {
-                            // The prismImage might be null if the Image has not completed loading.
-                            // In that case, we simply must skip rendering of that layer this
-                            // time around.
-                            continue;
-                        }
-                        // We need to translate the shape based on 0 insets. This will for example
-                        // center and / or position the shape if necessary.
-                        final Shape translatedShape = resizeShape(0, 0, 0, 0);
-                        // Now ensure that the ImagePattern is based on the x/y position of the
-                        // shape and not on the 0,0 position of the region.
-                        final RectBounds bounds = translatedShape.getBounds();
-                        ImagePattern pattern = image.getSize().isCover() ?
-                                new ImagePattern(prismImage, bounds.getMinX(), bounds.getMinY(),
-                                                 bounds.getWidth(), bounds.getHeight(), false, false) :
-                                new ImagePattern(prismImage, bounds.getMinX(), bounds.getMinY(),
-                                                 prismImage.getWidth(), prismImage.getHeight(), false, false);
-                        g.setPaint(pattern);
-                        // Go ahead and finally fill!
-                        g.fill(translatedShape);
-                    }
-                    // If old != null then that means we were rendering into the "cached" texture, and
-                    // therefore need to reset the graphics.
-                    if (old != null) {
-                        g = old;
-                    }
-                }
                 // cached might not be null if either there was a cached image, or we just created one.
                 // In either case, we need to now render from the cached texture to the graphics
                 if (cached != null) {
@@ -605,16 +524,18 @@
                     final float dstX2 = outsetShapeBounds.getMaxX();
                     final float dstY2 = outsetShapeBounds.getMaxY();
 
-                    final float srcX1 = 0f;
-                    final float srcY1 = 0f;
+                    final float srcX1 = rect.x;
+                    final float srcY1 = rect.y;
                     final float srcX2 = srcX1 + textureWidth;
                     final float srcY2 = srcY1 + textureHeight;
 
                     g.drawTexture(cached, dstX1, dstY1, dstX2, dstY2, srcX1, srcY1, srcX2, srcY2);
                     if (PulseLogger.PULSE_LOGGING_ENABLED) {
-                        PulseLogger.PULSE_LOGGER.renderIncrementCounter("Cached Region shape image used");
+                        PulseLogger.PULSE_LOGGER.renderIncrementCounter("Cached region shape image used");
                     }
-                    cached.unlock();
+                } else {
+                    // no cache, rendering backgrounds directly to graphics
+                    renderBackgroundShape(g);
                 }
             }
 
@@ -684,47 +605,49 @@
                         cacheMode != 0 &&
                         g.getTransformNoClone().isTranslateOrIdentity();
                 RTTexture cached = null;
-                if (cache && CACHE.isImageCachable(textureWidth, textureHeight)) {
-                    cached = CACHE.getImage(g.getAssociatedScreen(), textureWidth, textureHeight, background);
-                    if (cached != null) {
-                        cached.lock();
-                        if (cached.isSurfaceLost()) {
-                            cached = null;
+                Rectangle rect = null;
+                if (cache) {
+                    RegionImageCache imageCache = getImageCache(g);
+                    if (imageCache.isImageCachable(textureWidth, textureHeight)) {
+                        final Integer key = getCacheKey(textureWidth, textureHeight);
+                        rect = TEMP_RECT;
+                        rect.setBounds(0, 0, textureWidth, textureHeight);
+                        boolean render = imageCache.getImageLocation(key, rect, background, shape, g);
+                        if (!rect.isEmpty()) {
+                            // An empty rect indicates a failure occurred in the imageCache
+                            cached = imageCache.getBackingStore();
+                        }
+                        if (cached != null && render) {
+                            Graphics cacheGraphics = cached.createGraphics();
+
+                            // Have to move the origin such that when rendering to x=0, we actually end up rendering
+                            // at x=outsets.getLeft(). Otherwise anything rendered to the left of the origin would be lost
+                            // Round up to the nearest pixel
+                            cacheGraphics.translate(rect.x + outsetsLeft, rect.y + outsetsTop);
+
+                            //rendering backgrounds to the cache
+                            renderBackgrounds(cacheGraphics, cacheWidth, cacheHeight);
+
+                            if (PulseLogger.PULSE_LOGGING_ENABLED) {
+                                PulseLogger.PULSE_LOGGER.renderIncrementCounter("Rendering region background image to cache");
+                            }
                         }
                     }
-                    if (cached == null) {
-                        cached = g.getResourceFactory().createRTTexture(textureWidth, textureHeight, WrapMode.CLAMP_TO_ZERO);
-                        cached.contentsUseful();
-                        CACHE.setImage(cached, g.getAssociatedScreen(), textureWidth, textureHeight, background);
-                        if (PulseLogger.PULSE_LOGGING_ENABLED) {
-                            PulseLogger.PULSE_LOGGER.renderIncrementCounter("Region background image cached");
-                        }
-
-                        Graphics cacheGraphics = cached.createGraphics();
-                        // Have to move the origin such that when rendering to x=0, we actually end up rendering
-                        // at x=outsets.getLeft(). Otherwise anything rendered to the left of the origin would be lost
-                        // Round up to the nearest pixel
-                        cacheGraphics.translate(outsetsLeft, outsetsTop);
-
-                        //rendering backgrounds to the cache
-                        renderBackgrounds(cacheGraphics, cacheWidth, cacheHeight);
-                    }
-                } else {
-                    // no cache, rendering backgrounds directly to graphics
-                    renderBackgrounds(g, width, height);
                 }
 
                 // cached might not be null if either there was a cached image, or we just created one.
                 // In either case, we need to now render from the cached texture to the graphics
                 if (cached != null) {
-                    final boolean sameWidth = cacheWidth == width;
-                    final boolean sameHeight = cacheHeight == height;
+                    final float dstWidth = outsetsLeft + width + outsetsRight;
+                    final float dstHeight = outsetsTop + height + outsetsBottom;
+                    final boolean sameWidth = rect.width == dstWidth;
+                    final boolean sameHeight = rect.height == dstHeight;
                     final float dstX1 = -outsetsLeft;
                     final float dstY1 = -outsetsTop;
                     final float dstX2 = width + outsetsRight;
                     final float dstY2 = height + outsetsBottom;
-                    final float srcX1 = 0f;
-                    final float srcY1 = 0f;
+                    final float srcX1 = rect.x;
+                    final float srcY1 = rect.y;
                     final float srcX2 = srcX1 + textureWidth;
                     final float srcY2 = srcY1 + textureHeight;
 
@@ -799,11 +722,14 @@
                                             srcLeftX, srcTopY, srcRightX, srcBottomY);
                     }
                     if (PulseLogger.PULSE_LOGGING_ENABLED) {
-                        PulseLogger.PULSE_LOGGER.renderIncrementCounter("Cached Region background image used");
+                        PulseLogger.PULSE_LOGGER.renderIncrementCounter("Cached region background image used");
                     }
-                    cached.unlock();
+                } else {
+                    // no cache, rendering backgrounds directly to graphics
+                    renderBackgrounds(g, width, height);
                 }
 
+
                 final List<BackgroundImage> images = background.getImages();
                 for (int i = 0, max = images.size(); i < max; i++) {
                     final BackgroundImage image = images.get(i);
@@ -1240,6 +1166,54 @@
         super.renderContent(g);
     }
 
+    private void renderBackgroundShape(Graphics g) {
+        // We first need to draw each background fill. We don't pay any attention
+        // to the radii of the BackgroundFill, but we do honor the insets and
+        // the fill paint itself.
+        final List<BackgroundFill> fills = background.getFills();
+        for (int i = 0, max = fills.size(); i < max; i++) {
+            final BackgroundFill fill = fills.get(i);
+            // Get the paint for this BackgroundFill. It should not be possible
+            // for it to ever be null
+            final Paint paint = getPlatformPaint(fill.getFill());
+            assert paint != null;
+            g.setPaint(paint);
+            // Adjust the box within which we will fit the shape based on the
+            // insets. The resize shape method will resize the shape to fit
+            final Insets insets = fill.getInsets();
+            g.fill(resizeShape((float) insets.getTop(), (float) insets.getRight(),
+                               (float) insets.getBottom(), (float) insets.getLeft()));
+        }
+        // We now need to draw each background image. Only the "cover" property
+        // of BackgroundImage, and the "image" property itself, have any impact
+        // on how the image is applied to a Shape.
+        final List<BackgroundImage> images = background.getImages();
+        for (int i = 0, max = images.size(); i < max; i++) {
+            final BackgroundImage image = images.get(i);
+            final Image prismImage = (Image) image.getImage().impl_getPlatformImage();
+            if (prismImage == null) {
+                // The prismImage might be null if the Image has not completed loading.
+                // In that case, we simply must skip rendering of that layer this
+                // time around.
+                continue;
+            }
+            // We need to translate the shape based on 0 insets. This will for example
+            // center and / or position the shape if necessary.
+            final Shape translatedShape = resizeShape(0, 0, 0, 0);
+            // Now ensure that the ImagePattern is based on the x/y position of the
+            // shape and not on the 0,0 position of the region.
+            final RectBounds bounds = translatedShape.getBounds();
+            ImagePattern pattern = image.getSize().isCover() ?
+                    new ImagePattern(prismImage, bounds.getMinX(), bounds.getMinY(),
+                                     bounds.getWidth(), bounds.getHeight(), false, false) :
+                    new ImagePattern(prismImage, bounds.getMinX(), bounds.getMinY(),
+                                     prismImage.getWidth(), prismImage.getHeight(), false, false);
+            g.setPaint(pattern);
+            // Go ahead and finally fill!
+            g.fill(translatedShape);
+        }
+    }
+
     private void renderBackgrounds(Graphics g, float width, float height) {
         final List<BackgroundFill> fills = background.getFills();
         for (int i = 0, max = fills.size(); i < max; i++) {
--- a/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGShape.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGShape.java	Tue Aug 27 09:36:40 2013 -0700
@@ -78,6 +78,7 @@
         {           
             this.fillPaint = (Paint) fillPaint;
             visualsChanged();
+            invalidateOpaqueRegion();
         }
     }
 
@@ -276,4 +277,13 @@
             cached3D = null;
         }
     }
+
+    @Override
+    protected boolean hasOpaqueRegion() {
+        final Mode mode = getMode();
+        final Paint fillPaint = getFillPaint();
+        return super.hasOpaqueRegion() &&
+                    (mode == Mode.FILL || mode == Mode.STROKE_FILL) &&
+                    (fillPaint != null && fillPaint.isOpaque());
+    }
 }
--- a/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGSubScene.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGSubScene.java	Tue Aug 27 09:36:40 2013 -0700
@@ -190,13 +190,26 @@
             int x1 = x0 + rtt.getContentWidth();
             int y1 = y0 + rtt.getContentHeight();
             if ((isOpaque || g.getCompositeMode() == CompositeMode.SRC)
-                    && g.getTransformNoClone().isTranslateOrIdentity()) {
+                    && g.getTransformNoClone().isTranslateOrIdentity() &&
+                    !g.isDepthTest()) {
                 // Round translation to closest pixel
                 int tx = (int)(g.getTransformNoClone().getMxt() + 0.5);
                 int ty = (int)(g.getTransformNoClone().getMyt() + 0.5);
                 // Blit SubScene directly to scene surface
-                g.blit(rtt, null, x0, y0, x1, y1,
-                            x0 + tx, y0 + ty, x1 + tx, y1 + ty);
+
+                // Intersect src and dst boundaries.
+                // On D3D if blit is called outside boundary it will draw
+                // nothing. Using intersect prevents that from occurring.
+                int dstX0 = x0 + tx;
+                int dstY0 = y0 + ty;
+                int dstX1 = x1 + tx;
+                int dstY1 = y1 + ty;
+                int dstW = g.getRenderTarget().getContentWidth();
+                int dstH = g.getRenderTarget().getContentHeight();
+                int dX = dstX1 > dstW ? dstW - dstX1 : 0;
+                int dY = dstY1 > dstH ? dstH - dstY1 : 0;
+                g.blit(rtt, null, x0, y0, x1 + dX, y1 + dY,
+                            dstX0, dstY0, dstX1 + dX, dstY1 + dY);
             } else {
                 if (resolveRTT != null &&
                         (resolveRTT.getContentWidth() < rtt.getContentWidth() ||
--- a/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NodePath.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NodePath.java	Tue Aug 27 09:36:40 2013 -0700
@@ -30,17 +30,17 @@
 
 /**
  * Simple a reusable storage for root-to-node path.
- * 
+ *
  */
 public class NodePath<N extends NGNode> {
     private List<N> path = new ArrayList<>();
     private int position;
-    
+
     public NodePath() {
     }
-    
+
     // ITERATION methods
-    
+
     public N getCurrentNode() {
         return path.get(position);
     }
@@ -55,33 +55,29 @@
         }
         position--;
     }
-    
+
     public void reset() {
         position = path.size() - 1;
     }
-    
+
     // MODIFICATION methods
-    
+
     public void clear() {
         position = -1;
         path.clear();
     }
-    
+
     public void add(N n) {
         path.add(n);
         position = path.size() - 1;
     }
-    
+
     public int size() {
         return path.size();
     }
-    
-    /*
-     * Remove root and set to beginning.
-     */
-    public void removeRoot() {
-        path.remove(path.size() - 1);
-        position = path.size() - 1;
+
+    public boolean isEmpty() {
+        return size() == 0;
     }
 
 }
--- a/modules/graphics/src/main/java/com/sun/javafx/sg/prism/RegionImageCache.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/sg/prism/RegionImageCache.java	Tue Aug 27 09:36:40 2013 -0700
@@ -25,16 +25,19 @@
 
 package com.sun.javafx.sg.prism;
 
-import java.lang.ref.ReferenceQueue;
-import java.lang.ref.SoftReference;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
+import com.sun.javafx.geom.Rectangle;
+import com.sun.javafx.geom.Shape;
 import com.sun.javafx.logging.PulseLogger;
+
+import java.util.HashMap;
+
+import javafx.scene.layout.Background;
+
+import com.sun.prism.Graphics;
 import com.sun.prism.RTTexture;
+import com.sun.prism.ResourceFactory;
+import com.sun.prism.Texture.WrapMode;
+import com.sun.prism.impl.packrect.RectanglePacker;
 
 /**
  * RegionImageCache - A fixed pixel count sized cache of Images keyed by arbitrary set of arguments. All images are held with
@@ -43,33 +46,31 @@
  *
  */
 class RegionImageCache {
-    // Ordered Map keyed by args hash, ordered by most recent accessed entry.
-    private final LinkedHashMap<Integer, PixelCountSoftReference> map =
-            new LinkedHashMap<Integer, PixelCountSoftReference>(16, 0.75f, true);
-    // Maximum number of pixels to cache, this is used if maxCount
-    private final int maxPixelCount;
+
     // Maximum cached image size in pixels
-    private final int maxSingleImagePixelSize;
-    // The current number of pixels stored in the cache
-    private int currentPixelCount = 0;
-    // Lock for concurrent access to map
-    private ReadWriteLock lock = new ReentrantReadWriteLock();
-    // Reference queue for tracking lost soft references to images in the cache
-    private ReferenceQueue<RTTexture> referenceQueue = new ReferenceQueue<RTTexture>();
+    private final static int MAX_SIZE = 300 * 300;
+    private static final int WIDTH = 1024;
+    private static final int HEIGHT = 1024;
 
-    RegionImageCache() {
-        this.maxPixelCount = (8 * 1024 * 1024) / 4; // 8Mb of pixels
-        this.maxSingleImagePixelSize = 300 * 300;
-    }
+    private HashMap<Integer, CachedImage> imageMap;
+    private RTTexture backingStore;
+    private RectanglePacker hPacker;
+    private RectanglePacker vPacker;
 
-    /** Clear the cache */
-    void flush() {
-        lock.readLock().lock();
-        try {
-            map.clear();
-        } finally {
-            lock.readLock().unlock();
-        }
+
+    RegionImageCache(Graphics g) {
+        imageMap = new HashMap<>();
+        ResourceFactory factory = g.getResourceFactory();
+
+        backingStore = factory.createRTTexture(WIDTH + WIDTH, HEIGHT, WrapMode.CLAMP_NOT_NEEDED);
+        backingStore.contentsUseful();
+        backingStore.makePermanent();
+        // Subdivide the texture in two halves where on half is used to store
+        // horizontal regions and the other vertical regions. Otherwise, mixing
+        // horizontal and vertical regions on the same area, would result in
+        // a lot of waste texture space.
+        hPacker = new RectanglePacker(backingStore, 0, 0, WIDTH, HEIGHT, false);
+        vPacker = new RectanglePacker(backingStore, WIDTH, 0, WIDTH, HEIGHT, true);
     }
 
     /**
@@ -80,139 +81,83 @@
      * @return True if the image size is less than max
      */
     boolean isImageCachable(int w, int h) {
-        return w > 0 && h > 0 && (w * h) < maxSingleImagePixelSize;
+        return 0 < w && w < WIDTH &&
+               0 < h && h < HEIGHT &&
+               (w * h) < MAX_SIZE;
+    }
+
+    RTTexture getBackingStore() {
+        return backingStore;
     }
 
     /**
-     * Get the cached image for given keys
+     * Search the cache for a background image representing the arguments.
+     * When this method succeeds the x and y coordinates in rect are adjust
+     * to the location in the backing store when the image is stored.
+     * If a failure occurred the rect is set to empty to indicate the caller
+     * to disable caching.
      *
-     * @param config The Screen used with the target Graphics. Used as part of cache key
-     * @param w      The image width, used as part of cache key
-     * @param h      The image height, used as part of cache key
-     * @param args   Other arguments to use as part of the cache key
-     * @return Returns the cached Image, or null there is no cached image for key
+     * @param key the hash key for the image
+     * @param rect the rect image. On input, width and height determine the requested
+     *        texture space. On ouput, the x and y the location in the texture
+     * @param background the background used to validated if the correct image was found
+     * @param shape the shape used to validated if the correct image was found
+     * @param g the graphics to flush if the texture needs to be restarted
+     * @return true means to caller needs to render to rect to initialize the content.
      */
-    RTTexture getImage(Object config, int w, int h, Object... args) {
-        lock.readLock().lock();
-        try {
-            final int hash = hash(config, w, h, args);
-            PixelCountSoftReference ref = map.get(hash);
-            // Check reference has not been lost and the key truly matches, in case of false positive hash match
-            if (ref != null && ref.equals(config, w, h, args)) {
-                RTTexture image = ref.get();
-                // If the image surface is lost, then we will remove it from the cache and report back
-                // to the caller that we have no cached image.
-                if (image != null && image.isSurfaceLost()) {
-                    if (PulseLogger.PULSE_LOGGING_ENABLED) {
-                        PulseLogger.PULSE_LOGGER.renderIncrementCounter("Region RTTexture surface lost");
-                    }
-                    currentPixelCount -= ref.pixelCount;
-                    map.remove(hash);
-                    return null;
-                }
-                return ref.get();
-            } else {
-                return null;
+    boolean getImageLocation(Integer key, Rectangle rect, Background background,
+                             Shape shape, Graphics g) {
+        CachedImage cache = imageMap.get(key);
+        if (cache != null) {
+            if (cache.equals(rect.width, rect.height, background, shape)) {
+                rect.x = cache.x;
+                rect.y = cache.y;
+                return false;
             }
-        } finally {
-            lock.readLock().unlock();
+            // hash collision, mark rectangle empty indicates the caller to
+            // disable caching
+            rect.width = rect.height = -1;
+            return false;
+        }
+        boolean vertical = rect.height > 64;
+        RectanglePacker packer = vertical ? vPacker : hPacker;
+
+        if (!packer.add(rect)) {
+            g.sync();
+
+            vPacker.clear();
+            hPacker.clear();
+            imageMap.clear();
+            packer.add(rect);
+            backingStore.createGraphics().clear();
+            if (PulseLogger.PULSE_LOGGING_ENABLED) {
+                PulseLogger.PULSE_LOGGER.renderIncrementCounter("Region image cache flushed");
+            }
+        }
+        imageMap.put(key, new CachedImage(rect, background, shape));
+        return true;
+    }
+
+    static class CachedImage {
+        Background background;
+        Shape shape;
+        int x, y, width, height;
+
+        CachedImage(Rectangle rect, Background background, Shape shape) {
+            this.x = rect.x;
+            this.y = rect.y;
+            this.width = rect.width;
+            this.height = rect.height;
+            this.background = background;
+            this.shape = shape;
+        }
+
+        public boolean equals(int width, int height, Background background, Shape shape) {
+            return this.width == width &&
+                   this.height == height &&
+                   (this.background == null ? background == null : this.background.equals(background)) &&
+                   (this.shape == null ? shape == null : this.shape.equals(shape));
         }
     }
 
-    /**
-     * Sets the cached image for the specified constraints.
-     *
-     * @param image  The image to store in cache
-     * @param config The Screen used with the target Graphics. Used as part of cache key
-     * @param w      The image width, used as part of cache key
-     * @param h      The image height, used as part of cache key
-     * @param args   Other arguments to use as part of the cache key
-     * @return true if the image could be cached or false if the image is too big
-     */
-    boolean setImage(RTTexture image, Object config, int w, int h, Object... args) {
-        if (!isImageCachable(w, h)) return false;
-        int hash = hash(config, w, h, args);
-        lock.writeLock().lock();
-        try {
-            PixelCountSoftReference ref = map.get(hash);
-            // check if currently in map
-            if (ref != null && ref.get() == image) {
-                return true;
-            }
-            // clear out old
-            if (ref != null) {
-                if (PulseLogger.PULSE_LOGGING_ENABLED) {
-                    PulseLogger.PULSE_LOGGER.renderIncrementCounter("Region RTTexture replaced in RegionImageCache");
-                }
-                currentPixelCount -= ref.pixelCount;
-                map.remove(hash);
-            }
-            // add new image to pixel count
-            int newPixelCount = image.getContentWidth() * image.getContentHeight();
-            currentPixelCount += newPixelCount;
-            // clean out lost references if not enough space
-            if (currentPixelCount > maxPixelCount) {
-                while ((ref = (PixelCountSoftReference)referenceQueue.poll()) != null){
-                    //reference lost
-                    map.remove(ref.hash);
-                    currentPixelCount -= ref.pixelCount;
-                }
-            }
-            // remove old items till there is enough free space
-            if (currentPixelCount > maxPixelCount) {
-                Iterator<Map.Entry<Integer, PixelCountSoftReference>> mapIter = map.entrySet().iterator();
-                while ((currentPixelCount > maxPixelCount) && mapIter.hasNext()) {
-                    Map.Entry<Integer, PixelCountSoftReference> entry = mapIter.next();
-                    mapIter.remove();
-                    RTTexture img = entry.getValue().get();
-//                    if (img != null) img.flush();
-                    currentPixelCount -= entry.getValue().pixelCount;
-                }
-            }
-            // finally put new in map
-            map.put(hash, new PixelCountSoftReference(image, referenceQueue, newPixelCount,hash, config, w, h, args));
-            return true;
-        } finally {
-            lock.writeLock().unlock();
-        }
-    }
-
-    /** Create a unique hash from all the input */
-    private int hash(Object config, int w, int h, Object ... args) {
-        int hash;
-        hash = (config != null ? config.hashCode() : 0);
-        hash = 31 * hash + w;
-        hash = 31 * hash + h;
-        hash = 31 * hash + Arrays.deepHashCode(args);
-        return hash;
-    }
-
-    /** Extended SoftReference that stores the pixel count even after the image is lost */
-    private static class PixelCountSoftReference extends SoftReference<RTTexture> {
-        private final int pixelCount;
-        private final int hash;
-        // key parts
-        private final Object config;
-        private final int w;
-        private final int h;
-        private final Object[] args;
-
-        public PixelCountSoftReference(RTTexture referent, ReferenceQueue<? super RTTexture> q, int pixelCount, int hash,
-                                       Object config, int w, int h, Object[] args) {
-            super(referent, q);
-            this.pixelCount = pixelCount;
-            this.hash = hash;
-            this.config = config;
-            this.w = w;
-            this.h = h;
-            this.args = args;
-        }
-
-        public boolean equals (Object config, int w, int h, Object[] args){
-            return config == this.config &&
-                            w == this.w &&
-                            h == this.h &&
-                            Arrays.equals(args, this.args);
-        }
-    }
 }
--- a/modules/graphics/src/main/java/com/sun/javafx/text/TextRun.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/text/TextRun.java	Tue Aug 27 09:36:40 2013 -0700
@@ -36,7 +36,6 @@
     int[] gids;
     float[] positions;
     int[] charIndices;
-    Object[] glyphData;
     int start, length;
     float width = -1;
     byte level;
@@ -256,23 +255,6 @@
         flags |= FLAGS_RIGHT_BEARING;
     }
 
-    /* This method can be used as a medium to allow the glyph layout to provided
-     * the rendered with additional data.
-     * For example, used by DirectWrite use this to transfer the glyph offsets.
-     *
-     * Should only be called after shape, and only for complex text.
-     */
-    public void setGlyphData(int index, Object data) {
-        if (glyphData == null) {
-            glyphData = new Object[glyphCount];
-        }
-        glyphData[index] = data;
-    }
-
-    public Object getGlyphData(int index) {
-        return glyphData != null ? glyphData[index] : null;
-    }
-
     public int getWrapIndex(float width) {
         if (glyphCount == 0) return 0;
         if (isLeftToRight()) {
@@ -452,7 +434,6 @@
         positions = null;
         charIndices = null;
         gids = null;
-        glyphData = null;
         width = -1;
         ascent = descent = leading = 0;
         glyphCount = 0;
@@ -527,7 +508,6 @@
         /* do not clear SPLIT here as it is still needed for merging */
         int mask = FLAGS_SOFTBREAK | FLAGS_NO_LINK_AFTER | FLAGS_NO_LINK_BEFORE;
         newRun.flags = flags & ~mask;
-        newRun.glyphData = glyphData;
         return newRun;
     }
 
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/PresentingPainter.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/PresentingPainter.java	Tue Aug 27 09:36:40 2013 -0700
@@ -70,17 +70,11 @@
                 return;
             }
 
-            boolean needsReset = (presentable == null) ||
-                                 (penWidth != viewWidth) || (penHeight != viewHeight);
-            if (presentable != null) {
-                needsReset = presentable.lockResources() || needsReset;
+            if (presentable != null && presentable.lockResources(sceneState)) {
+                disposePresentable();
             }
-            if (needsReset) {
-                if (presentable == null || presentable.recreateOnResize()) {
-                    disposePresentable();
-                    presentable = factory.createPresentable(sceneState);
-                    needsReset = false;
-                }
+            if (presentable == null) {
+                presentable = factory.createPresentable(sceneState);
                 penWidth  = viewWidth;
                 penHeight = viewHeight;
             }
@@ -90,9 +84,6 @@
 
                 ViewScene vs = (ViewScene) sceneState.getScene();
                 if (g != null) {
-                    if (needsReset) {
-                        g.reset();
-                    }
                     paintImpl(g);
                 }
                 
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/QuantumToolkit.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/QuantumToolkit.java	Tue Aug 27 09:36:40 2013 -0700
@@ -53,6 +53,7 @@
 import javafx.stage.FileChooser;
 import javafx.stage.Modality;
 import javafx.stage.StageStyle;
+import javafx.stage.Window;
 import java.io.File;
 import java.io.InputStream;
 import java.nio.ByteBuffer;
@@ -127,7 +128,6 @@
 import com.sun.scenario.effect.impl.prism.PrImage;
 import static com.sun.javafx.logging.PulseLogger.PULSE_LOGGER;
 import static com.sun.javafx.logging.PulseLogger.PULSE_LOGGING_ENABLED;
-import javafx.stage.Window;
 
 public final class QuantumToolkit extends Toolkit {
 
@@ -1030,7 +1030,7 @@
         int intX = (int)x + pImage.getMinX();
         int intY = (int)y + pImage.getMinY();
 
-        if (pImage.getPixelFormat().isOpaque()) {
+        if (pImage.isOpaque()) {
             return true;
         }
 
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/ViewPainter.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/ViewPainter.java	Tue Aug 27 09:36:40 2013 -0700
@@ -53,7 +53,7 @@
 import static com.sun.javafx.logging.PulseLogger.PULSE_LOGGER;
 
 abstract class ViewPainter implements Runnable {
-    private static final NodePath<NGNode> NODE_PATH = new NodePath<>();
+    private static NodePath<NGNode>[] ROOT_PATHS = new NodePath[PrismSettings.dirtyRegionCount];
 
     /*
      * This could be a per-scene lock but there is no guarantee that the
@@ -68,7 +68,7 @@
     protected int penHeight = -1;
     protected int viewWidth;
     protected int viewHeight;
-    
+
     protected final SceneState sceneState;
 
     protected Presentable presentable;
@@ -107,7 +107,7 @@
             dirtyRegionContainer = dirtyRegionPool.checkOut();
         }
     }
-        
+
     protected void setRoot(NGNode node) {
         root = node;
     }
@@ -163,12 +163,18 @@
         }
 
         if (!PrismSettings.showDirtyRegions && status == DirtyRegionContainer.DTR_OK) {
+            final int dirtyRegionSize = dirtyRegionContainer.size();
             g.setHasPreCullingBits(true);
-            if (PULSE_LOGGING_ENABLED && dirtyRegionContainer.size() > 1) {
-                PULSE_LOGGER.renderMessage(dirtyRegionContainer.size() + " different dirty regions to render");
+            if (PULSE_LOGGING_ENABLED && dirtyRegionSize > 1) {
+                PULSE_LOGGER.renderMessage(dirtyRegionSize + " different dirty regions to render");
             }
             float pixelScale = (presentable == null ? 1.0f : presentable.getPixelScaleFactor());
-            for (int i = 0; i < dirtyRegionContainer.size(); i++) {
+            if (!sceneState.getScene().getDepthBuffer() && PrismSettings.occlusionCullingEnabled) {
+                for (int i = 0; i < dirtyRegionSize; ++i) {
+                    root.getRenderRoot(getRootPath(i), dirtyRegionContainer.getDirtyRegion(i), i, tx, projTx);
+                }
+            }
+            for (int i = 0; i < dirtyRegionSize; ++i) {
                 final RectBounds dirtyRegion = dirtyRegionContainer.getDirtyRegion(i);
                 // make sure we are not trying to render in some invalid region
                 if (dirtyRegion.getWidth() > 0 && dirtyRegion.getHeight() > 0) {
@@ -187,11 +193,12 @@
                     g.setClipRectIndex(i);
 
                     // Disable occlusion culling if depth buffer is enabled for the scene.
-                    if (sceneState.getScene().getDepthBuffer()) {
+                    if (sceneState.getScene().getDepthBuffer() || !PrismSettings.occlusionCullingEnabled) {
                         doPaint(g, null);
                     } else {
-                        doPaint(g, root.getRenderRoot(NODE_PATH, dirtyRegion, i, tx, projTx));
-                        NODE_PATH.clear();
+                        final NodePath<NGNode> path = getRootPath(i);
+                        doPaint(g, path);
+                        path.clear();
                     }
                 }
             }
@@ -256,6 +263,13 @@
         }
     }
 
+    private static NodePath<NGNode> getRootPath(int i) {
+        if (ROOT_PATHS[i] == null) {
+            ROOT_PATHS[i] = new NodePath<>();
+        }
+        return ROOT_PATHS[i];
+    }
+
     protected void disposePresentable() {
         if (presentable instanceof GraphicsResource) {
             ((GraphicsResource)presentable).dispose();
@@ -265,8 +279,8 @@
 
     protected boolean validateStageGraphics() {
         if (!sceneState.isValid()) {
-            // indicates something happened between the scheduling of the 
-            // job and the running of this job. 
+            // indicates something happened between the scheduling of the
+            // job and the running of this job.
             return false;
         }
 
@@ -275,11 +289,22 @@
 
         return sceneState.isWindowVisible() && !sceneState.isWindowMinimized();
     }
-    
+
     private void doPaint(Graphics g, NodePath<NGNode> renderRootPath) {
         if (PrismSettings.showDirtyRegions) {
             g.setClipRect(null);
         }
+        // Null path indicates that occlusion culling is not used
+        if (renderRootPath != null) {
+            if (renderRootPath.isEmpty()) {
+                // empty render path indicates that no rendering is needed.
+                // There may be occluded dirty Nodes however, so we need to clear them
+                root.clearDirtyTree();
+                return;
+            }
+            // If the path is not empty, the first node must be the root node
+            assert(renderRootPath.getCurrentNode() == root);
+        }
         long start = PULSE_LOGGING_ENABLED ? System.currentTimeMillis() : 0;
         try {
             GlassScene scene = sceneState.getScene();
@@ -307,5 +332,5 @@
             }
         }
     }
-    
+
 }
--- a/modules/graphics/src/main/java/com/sun/pisces/PiscesRenderer.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/pisces/PiscesRenderer.java	Tue Aug 27 09:36:40 2013 -0700
@@ -346,6 +346,7 @@
     public void drawImage(int imageType, int imageMode, int data[],  int width, int height, int offset, int stride,
         Transform6 textureTransform, boolean repeat,
         int bboxX, int bboxY, int bboxW, int bboxH,
+        int lEdge, int rEdge, int tEdge, int bEdge,
         int interpolateMinX, int interpolateMinY, int interpolateMaxX, int interpolateMaxY,
         boolean hasAlpha)
     {
@@ -353,6 +354,7 @@
         this.drawImageImpl(imageType, imageMode, data, width, height, offset, stride,
             textureTransform, repeat,
             bboxX, bboxY, bboxW, bboxH,
+            lEdge, rEdge, tEdge, bEdge,
             interpolateMinX, interpolateMinY, interpolateMaxX, interpolateMaxY,
             hasAlpha);
     }
@@ -360,6 +362,7 @@
     private native void drawImageImpl(int imageType, int imageMode, int data[], int width, int height, int offset, int stride,
         Transform6 textureTransform, boolean repeat,
         int bboxX, int bboxY, int bboxW, int bboxH,
+        int lEdge, int rEdge, int tEdge, int bEdge,
         int interpolateMinX, int interpolateMinY, int interpolateMaxX, int interpolateMaxY,
         boolean hasAlpha);
 
--- a/modules/graphics/src/main/java/com/sun/pisces/RendererBase.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/pisces/RendererBase.java	Tue Aug 27 09:36:40 2013 -0700
@@ -72,4 +72,8 @@
 
     public static final int IMAGE_MODE_NORMAL = 1;
     public static final int IMAGE_MODE_MULTIPLY = 2;
+
+    public static final int IMAGE_FRAC_EDGE_KEEP = 0;
+    public static final int IMAGE_FRAC_EDGE_PAD  = 1;
+    public static final int IMAGE_FRAC_EDGE_TRIM = 2;
 }
--- a/modules/graphics/src/main/java/com/sun/prism/Graphics.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/Graphics.java	Tue Aug 27 09:36:40 2013 -0700
@@ -191,7 +191,6 @@
      * or "return to texture cache pool" operation.
      */
     public void sync();
-    public void reset();
 
     public Screen getAssociatedScreen();
     public ResourceFactory getResourceFactory();
--- a/modules/graphics/src/main/java/com/sun/prism/Image.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/Image.java	Tue Aug 27 09:36:40 2013 -0700
@@ -25,6 +25,12 @@
 
 package com.sun.prism;
 
+import javafx.scene.image.PixelReader;
+import javafx.scene.image.WritablePixelFormat;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
 import com.sun.javafx.iio.ImageFrame;
 import com.sun.javafx.iio.ImageStorage;
 import com.sun.javafx.image.BytePixelGetter;
@@ -48,12 +54,6 @@
 import com.sun.javafx.image.impl.ByteRgba;
 import com.sun.javafx.tk.PlatformImage;
 import com.sun.prism.impl.BufferUtil;
-import java.nio.Buffer;
-import java.nio.ByteBuffer;
-import java.nio.FloatBuffer;
-import java.nio.IntBuffer;
-import javafx.scene.image.PixelReader;
-import javafx.scene.image.WritablePixelFormat;
 
 public class Image implements PlatformImage {
     static final javafx.scene.image.WritablePixelFormat FX_ByteBgraPre_FORMAT =
@@ -439,7 +439,7 @@
      * in cases where having extra pixels at the end of a scanline is not
      * desirable.
      *
-     * @param pixel the buffer containing the pixels to copy
+     * @param pixels the buffer containing the pixels to copy
      * @param format the format of the given buffer
      * @param minX the x offset of the upper-left corner of the pixel region
      * @param minX the y offset of the upper-left corner of the pixel region
@@ -715,6 +715,10 @@
         serial[0]++;
     }
 
+    public boolean isOpaque() {
+        return pixelFormat.isOpaque();
+    }
+
     abstract class Accessor<I extends Buffer> {
         public abstract int getArgb(int x, int y);
 
--- a/modules/graphics/src/main/java/com/sun/prism/Presentable.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/Presentable.java	Tue Aug 27 09:36:40 2013 -0700
@@ -32,12 +32,17 @@
      * Locks any underlying resources needed for a createGraphics/prepare/present
      * sequence and returns a boolean indicating if the presentable needs to be
      * recreated.
+     * If the method returns true and the Presentable implements
+     * {@link GraphicsResource} then its {@code dispose()} method will be
+     * called prior to recreating a new {@code Presentable} object and
+     * so no resource should need to be locked in that case.
      * The resources will be unlocked in either {@link #prepare()} or
      * {@link #present()}.
      * 
+     * @param pState The presentation state for the upcoming pulse
      * @return true if the caller should recreate the Presentable
      */
-    public boolean lockResources();
+    public boolean lockResources(PresentableState pState);
 
     /**
      * display the indicated region to the user.
@@ -52,11 +57,5 @@
      */
     public boolean present();
 
-    /**
-     * query whether the presentable needs to be recreated on resize
-     * @return true if the presentable must be recreated on resize;
-     */
-    public boolean recreateOnResize();
-
     public float getPixelScaleFactor();
 }
--- a/modules/graphics/src/main/java/com/sun/prism/d3d/D3DContext.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/d3d/D3DContext.java	Tue Aug 27 09:36:40 2013 -0700
@@ -86,7 +86,6 @@
 
     NGCamera camera = null;
     private int targetWidth = 0, targetHeight = 0;
-    private boolean depthTest;
 
     private final D3DResourceFactory factory;
 
@@ -189,12 +188,11 @@
     protected State updateRenderTarget(RenderTarget target, NGCamera camera,
                                        boolean depthTest)  {
         long resourceHandle = ((D3DRenderTarget)target).getResourceHandle();
-        int res = nSetRenderTarget(pContext, resourceHandle);
+        int res = nSetRenderTarget(pContext, resourceHandle, depthTest, target.isAntiAliasing());
         validate(res);
         resetLastClip(state);
 
         this.camera = camera;
-        this.depthTest = depthTest;
         targetWidth = target.getPhysicalWidth();
         targetHeight = target.getPhysicalHeight();
 
@@ -329,7 +327,12 @@
         return nGetFrameStats(pContext, result, reset) ? result : null;
     }
 
-    private static native int nSetRenderTarget(long pContext, long pDest);
+    /*
+     * @param depthBuffer if true will create and attach a depthBuffer,
+     * if needed, of the same format as the render target. The depth test state
+     * is handled elsewhere.
+     */
+    private static native int nSetRenderTarget(long pContext, long pDest, boolean depthBuffer, boolean msaa);
     private static native int nSetTexture(long pContext, long pTex, int texUnit,
         boolean linear, int wrapMode);
     private static native int nResetTransform(long pContext);
@@ -384,6 +387,14 @@
     private static native void nRenderMeshView(long pContext, long nativeMeshView);
 
 
+    /*
+     * @param nSrcRTT must be valid native resource
+     * @param nDstRTT can be NULL if a valide render target is set
+     */
+    private static native void nBlit(long pContext, long nSrcRTT, long nDstRTT,
+            int srcX0, int srcY0, int srcX1, int srcY1,
+            int dstX0, int dstY0, int dstX1, int dstY1);
+
     private static native boolean nGetFrameStats(long pContext,
             D3DFrameStats returnValue, boolean bReset);
 
@@ -414,7 +425,7 @@
     }
 
     @Override
-    public void setDeviceParametersFor3D() {
+    protected void setDeviceParametersFor3D() {
         nSetDeviceParametersFor3D(pContext);
     }
 
@@ -506,6 +517,10 @@
     public void blit(RTTexture srcRTT, RTTexture dstRTT,
                      int srcX0, int srcY0, int srcX1, int srcY1,
                      int dstX0, int dstY0, int dstX1, int dstY1) {
-        throw new UnsupportedOperationException("Not supported yet.");
+        long dstNativeHandle = dstRTT == null ? 0L : ((D3DTexture)dstRTT).getNativeSourceHandle();
+        long srcNativeHandle = ((D3DTexture)srcRTT).getNativeSourceHandle();
+        nBlit(pContext, srcNativeHandle, dstNativeHandle,
+                          srcX0, srcY0, srcX1, srcY1,
+                          dstX0, dstY0, dstX1, dstY1);
     }
 }
--- a/modules/graphics/src/main/java/com/sun/prism/d3d/D3DDriverInformation.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/d3d/D3DDriverInformation.java	Tue Aug 27 09:36:40 2013 -0700
@@ -39,6 +39,7 @@
     // driver version information
     public int product, version, subVersion, buildID;
     public int psVersionMajor, psVersionMinor;
+    public int maxSamples = 0;
 
     public String getDriverVersion() {
         return String.format("%d.%d.%d.%d", product, version, subVersion, buildID);
--- a/modules/graphics/src/main/java/com/sun/prism/d3d/D3DGraphics.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/d3d/D3DGraphics.java	Tue Aug 27 09:36:40 2013 -0700
@@ -100,9 +100,4 @@
 
     private static native int nClear(long pContext, int colorArgbPre,
                                       boolean clearDepth, boolean ignoreScissor);
-
-    public void reset() {
-        throw new RuntimeException("Reset is unsupported for resize operation");
-    }
-
 }
--- a/modules/graphics/src/main/java/com/sun/prism/d3d/D3DPipeline.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/d3d/D3DPipeline.java	Tue Aug 27 09:36:40 2013 -0700
@@ -110,6 +110,7 @@
             System.out.println("\tDriver " + di.driverName + ", version " + di.getDriverVersion());
             System.out.println("\tPixel Shader version " + di.psVersionMajor + "." + di.psVersionMinor);
             System.out.println("\tDevice : " + di.getDeviceID());
+            System.out.println("\tMax Multisamples supported: " + di.maxSamples);
             if (di.warningMessage != null) {
                 System.out.println("\t *** " + di.warningMessage);
             }
@@ -152,6 +153,8 @@
     private static native D3DDriverInformation nGetDriverInformation(
             int adapterOrdinal, D3DDriverInformation object);
 
+    private static native int nGetMaxSampleSupport(int adapterOrdinal);
+
     @Override
     public void dispose() {
         if (creator != Thread.currentThread()) {
@@ -237,10 +240,22 @@
         return true;
     }
 
+    private int maxSamples = -1;
+
+    int getMaxSamples() {
+        if (maxSamples < 0) {
+            isAntiAliasingSupported();
+        }
+        return maxSamples;
+    }
+
     @Override
     public boolean isAntiAliasingSupported() {
-        //TODO: 3D - Add AA support for D3D
-        return false;
+        if (maxSamples < 0) {
+            //TODO: 3D - consider different adapters
+            maxSamples = nGetMaxSampleSupport(0);
+        }
+        return maxSamples > 0;
     }
 
     @Override
--- a/modules/graphics/src/main/java/com/sun/prism/d3d/D3DRTTexture.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/d3d/D3DRTTexture.java	Tue Aug 27 09:36:40 2013 -0700
@@ -56,11 +56,12 @@
     D3DRTTexture(D3DContext context, WrapMode wrapMode, long pResource,
                  int physicalWidth, int physicalHeight,
                  int contentX, int contentY,
-                 int contentWidth, int contentHeight)
+                 int contentWidth, int contentHeight,
+                 int samples)
     {
         super(context, PixelFormat.INT_ARGB_PRE, wrapMode, pResource,
               physicalWidth, physicalHeight,
-              contentX, contentY, contentWidth, contentHeight, true);
+              contentX, contentY, contentWidth, contentHeight, true, samples);
         this.opaque = false;
     }
 
@@ -161,7 +162,6 @@
     }
 
     public boolean isAntiAliasing() {
-        //TODO: 3D - Add AA support for D3D
-        return false;
+        return resource.getResource().getSamples() != 0;
     }
 }
\ No newline at end of file
--- a/modules/graphics/src/main/java/com/sun/prism/d3d/D3DResourceFactory.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/d3d/D3DResourceFactory.java	Tue Aug 27 09:36:40 2013 -0700
@@ -151,7 +151,7 @@
         }
         long pResource = nCreateTexture(context.getContextHandle(),
                                         format.ordinal(), usagehint.ordinal(),
-                                        false /*isRTT*/, allocw, alloch);
+                                        false /*isRTT*/, allocw, alloch, 0);
         if (pResource == 0L) {
             return null;
         }
@@ -210,7 +210,7 @@
             }
             long pResource = nCreateTexture(context.getContextHandle(),
                     texFormat.ordinal(), Usage.DYNAMIC.ordinal(),
-                    false, texWidth, texHeight);
+                    false, texWidth, texHeight, 0);
             if (0 == pResource) {
                 return null;
             }
@@ -270,6 +270,14 @@
             createh = nextPowerOfTwo(createh, Integer.MAX_VALUE);
         }
         D3DVramPool pool = D3DVramPool.instance;
+        int aaSamples;
+        if (antiAliasing) {
+            int maxSamples = D3DPipeline.getInstance().getMaxSamples();
+            aaSamples =  maxSamples < 2 ? 0 : (maxSamples < 4 ? 2 : 4);
+        } else {
+            aaSamples = 0;
+        }
+        // TODO: 3D - Improve estimate to include if multisample rtt
         long size = pool.estimateRTTextureSize(width, height, false);
         if (!pool.prepareForAllocation(size)) {
             return null;
@@ -278,7 +286,7 @@
         long pResource = nCreateTexture(context.getContextHandle(),
                                         PixelFormat.INT_ARGB_PRE.ordinal(),
                                         Usage.DEFAULT.ordinal(),
-                                        true /*isRTT*/, createw, createh);
+                                        true /*isRTT*/, createw, createh, aaSamples);
         if (pResource == 0L) {
             return null;
         }
@@ -286,7 +294,7 @@
         int texw = nGetTextureWidth(pResource);
         int texh = nGetTextureHeight(pResource);
         D3DRTTexture rtt = new D3DRTTexture(context, wrapMode, pResource, texw, texh,
-                                            cx, cy, width, height);
+                                            cx, cy, width, height, aaSamples);
         // ensure the RTTexture is cleared to all zeros before returning
         // (Decora relies on the Java2D behavior, where an image is expected
         // to be fully transparent after initialization)
@@ -473,7 +481,7 @@
     static native long nCreateTexture(long pContext,
                                       int format, int hint,
                                       boolean isRTT,
-                                      int width, int height);
+                                      int width, int height, int samples);
     static native long nCreateSwapChain(long pContext, long hwnd,
                                         boolean isVsyncEnabled);
     static native int nReleaseResource(long pContext, long resource);
--- a/modules/graphics/src/main/java/com/sun/prism/d3d/D3DSwapChain.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/d3d/D3DSwapChain.java	Tue Aug 27 09:36:40 2013 -0700
@@ -30,6 +30,7 @@
 import com.sun.prism.CompositeMode;
 import com.sun.prism.Graphics;
 import com.sun.prism.Presentable;
+import com.sun.prism.PresentableState;
 import com.sun.prism.RTTexture;
 
 class D3DSwapChain
@@ -56,8 +57,21 @@
         if (g == null) {
             return false;
         }
-        g.setCompositeMode(CompositeMode.SRC);
-        g.drawTexture(texBackBuffer, 0, 0, this.getContentWidth(), this.getContentHeight());
+        Rectangle rectDST = new Rectangle(0, 0, this.getContentWidth(), this.getContentHeight());
+        if (clip != null) {
+            rectDST.intersectWith(clip);
+        }
+        int x0 = rectDST.x;
+        int y0 = rectDST.y;
+        int x1 = x0 + rectDST.width;
+        int y1 = y0 + rectDST.height;
+        if (isAntiAliasing()) {
+            context.flushVertexBuffer();
+            g.blit(texBackBuffer, null, x0, y0, x1, y1, x0, y0, x1, y1);
+        } else {
+            g.setCompositeMode(CompositeMode.SRC);
+            g.drawTexture(texBackBuffer, x0, y0, x1, y1);
+        }
         context.flushVertexBuffer();
         texBackBuffer.unlock();
         return true;
@@ -103,7 +117,12 @@
         return d3dResRecord.getContext();
     }
 
-    public boolean lockResources() {
+    public boolean lockResources(PresentableState pState) {
+        if (pState.getWidth() != getPhysicalWidth() ||
+            pState.getHeight() != getPhysicalHeight())
+        {
+            return true;
+        }
         texBackBuffer.lock();
         return texBackBuffer.isSurfaceLost();
     }
@@ -120,10 +139,6 @@
         return getContext().getAssociatedScreen();
     }
 
-    public boolean recreateOnResize() {
-        return true;
-    }
-
     public float getPixelScaleFactor() {
         return 1.0f;
     }
@@ -137,7 +152,6 @@
     }
 
     public boolean isAntiAliasing() {
-        //TODO: 3D - Add AA support for D3D
-        return false;
+        return texBackBuffer != null ? texBackBuffer.isAntiAliasing() : false;
     }
 }
--- a/modules/graphics/src/main/java/com/sun/prism/d3d/D3DTexture.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/d3d/D3DTexture.java	Tue Aug 27 09:36:40 2013 -0700
@@ -53,23 +53,19 @@
                int physicalWidth, int physicalHeight,
                int contentWidth, int contentHeight, boolean isRTT)
     {
-        super(new D3DTextureResource(new D3DTextureData(context, pResource, isRTT,
-                                                        physicalWidth, physicalHeight,
-                                                        format)),
-              format, wrapMode,
-              physicalWidth, physicalHeight,
-              0, 0, contentWidth, contentHeight, physicalWidth, physicalHeight);
+        this(context, format, wrapMode, pResource, physicalWidth, physicalHeight,
+                0, 0, contentWidth, contentHeight, isRTT, 0);
     }
 
     D3DTexture(D3DContext context, PixelFormat format, WrapMode wrapMode,
                long pResource,
                int physicalWidth, int physicalHeight,
                int contentX, int contentY, int contentWidth, int contentHeight,
-               boolean isRTT)
+               boolean isRTT, int samples)
     {
         super(new D3DTextureResource(new D3DTextureData(context, pResource, isRTT,
                                                         physicalWidth, physicalHeight,
-                                                        format)),
+                                                        format, samples)),
               format, wrapMode,
               physicalWidth, physicalHeight,
               contentX, contentY, contentWidth, contentHeight, 
--- a/modules/graphics/src/main/java/com/sun/prism/d3d/D3DTextureData.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/d3d/D3DTextureData.java	Tue Aug 27 09:36:40 2013 -0700
@@ -31,6 +31,7 @@
 public class D3DTextureData extends D3DResource.D3DRecord {
     private final long size;
     private final boolean isRTT;
+    private final int samples;
 
     static long estimateSize(int physicalWidth, int physicalHeight,
                              PixelFormat format)
@@ -48,13 +49,18 @@
     D3DTextureData(D3DContext context,
                    long pResource, boolean isRTT,
                    int physicalWidth, int physicalHeight,
-                   PixelFormat format)
+                   PixelFormat format, int numberOfSamples)
     {
         super(context, pResource);
         this.size = isRTT
                ? estimateRTSize(physicalWidth, physicalHeight, false)
                : estimateSize(physicalWidth, physicalHeight, format);
         this.isRTT = isRTT;
+        this.samples = numberOfSamples;
+    }
+
+    int getSamples() {
+        return samples;
     }
 
     long getSize() {
--- a/modules/graphics/src/main/java/com/sun/prism/es2/EGLFBGLDrawable.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/es2/EGLFBGLDrawable.java	Tue Aug 27 09:36:40 2013 -0700
@@ -26,10 +26,20 @@
 package com.sun.prism.es2;
 
 import com.sun.prism.paint.Color;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 
 
 class EGLFBGLDrawable extends GLDrawable {
 
+    private static final boolean transparentFramebuffer =
+            AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
+                @Override
+                public Boolean run() {
+                    return Boolean.getBoolean("com.sun.javafx.transparentFramebuffer");
+                }
+            });
+
     private static native long nCreateDrawable(long nativeWindow, long nativeCtxInfo);
     private static native long nGetDummyDrawable(long nativeCtxInfo);
     private static native boolean nSwapBuffers(long nativeDInfo);
@@ -52,7 +62,9 @@
     @Override
     boolean swapBuffers(GLContext glCtx) {
         boolean retval = nSwapBuffers(getNativeDrawableInfo());
-        glCtx.clearBuffers(Color.BLACK, true, true, false);
+        glCtx.clearBuffers(
+                transparentFramebuffer ? Color.TRANSPARENT : Color.BLACK,
+                true, true, false);
         return retval;
     }
 }
--- a/modules/graphics/src/main/java/com/sun/prism/es2/ES2Context.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/es2/ES2Context.java	Tue Aug 27 09:36:40 2013 -0700
@@ -188,18 +188,6 @@
     }
 
     @Override
-    public boolean isEdgeSmoothingSupported(PixelFormat format) {
-        if (ES2Pipeline.isEmbededDevice) {
-            // on an embeded device, the smoothing trick only works if the texture
-            // contains an alpha channel
-            return !format.isOpaque() && format.isRGB();
-        } else {
-            // on desktop, the smoothing trick is supported for any rgb format
-            return format.isRGB();
-        }
-    }
-
-    @Override
     protected void releaseRenderTarget() {
         currentTarget = null;
         super.releaseRenderTarget();
@@ -466,13 +454,13 @@
     }
 
     @Override
-    public void blit(RTTexture rtt, RTTexture dstRTT,
+    public void blit(RTTexture srcRTT, RTTexture dstRTT,
                      int srcX0, int srcY0, int srcX1, int srcY1,
                      int dstX0, int dstY0, int dstX1, int dstY1)
     {
         // If dstRTT is null then will blit to currently bound fbo
         int dstFboID = dstRTT == null ? 0 : ((ES2RTTexture)dstRTT).getFboID();
-        int srcFboID = ((ES2RTTexture)rtt).getFboID();
+        int srcFboID = ((ES2RTTexture)srcRTT).getFboID();
         glContext.blitFBO(srcFboID, dstFboID,
                           srcX0, srcY0, srcX1, srcY1,
                           dstX0, dstY0, dstX1, dstY1);
--- a/modules/graphics/src/main/java/com/sun/prism/es2/ES2Graphics.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/es2/ES2Graphics.java	Tue Aug 27 09:36:40 2013 -0700
@@ -83,15 +83,6 @@
         context.getGLContext().finish();
     }
 
-    // glass bring up: need this for Glass window client, which has no intimate
-    // knowledge of the graphics mechansim
-    // (so we need public API)
-    // to force it to reset its viewport and matrices due to resize event of the
-    // window surface
-    public void reset() {
-        forceRenderTarget();
-    }
-
     /**
      * Called from ES2SwapChain to force the render target to be revalidated
      * (context made current, viewport and projection matrix updated, etc)
--- a/modules/graphics/src/main/java/com/sun/prism/es2/ES2Pipeline.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/es2/ES2Pipeline.java	Tue Aug 27 09:36:40 2013 -0700
@@ -38,14 +38,6 @@
 
 public class ES2Pipeline extends GraphicsPipeline {
 
-    // Currently there are certain restrictions when running on an actual
-    // OpenGL ES 2.0 device (for example, limited pbuffer support, issues
-    // with multiple/shared contexts), so for now certain codepaths may be
-    // disabled depending on whether isEmbededDevice is set or not.
-    // NOTE: For the Embedded Team: The above comment is no longer valid on the
-    //       new prism-es2 pipe. This new pipe do not use pbuffer nor shared
-    //       context on Linux.
-    public static final boolean isEmbededDevice = PrismSettings.isEmbededDevice;
     public static final GLFactory glFactory;
     public static final GLPixelFormat.Attributes
             pixelFormatAttributes = new GLPixelFormat.Attributes();
@@ -94,9 +86,6 @@
             theInstance = null;
         }
 
-        if (PrismSettings.verbose && isEmbededDevice) {
-            System.out.println("ES2Pipeline: OpenGL ES 2.0 embedded device detected");
-        }
         antiAliasingSupported = (glFactory.isGLExtensionSupported("GL_ARB_multisample"));
     }
     private static Thread creator;
@@ -197,7 +186,11 @@
 
     @Override
     public boolean is3DSupported() {
-        return true;
+        // It is okay to just returns true if we plan to support 3D on all
+        // ES2 platforms that are PS 3 capable. However we are not ready to
+        // support 3D on the embedded platform. Some of this platforms may be
+        // PS 3 capable but have other limitations such as NPOT. 
+        return PlatformUtil.isEmbedded() ? PlatformUtil.isEmbedded3DEnabled() : true;
     }
 
     @Override
--- a/modules/graphics/src/main/java/com/sun/prism/es2/ES2ResourceFactory.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/es2/ES2ResourceFactory.java	Tue Aug 27 09:36:40 2013 -0700
@@ -49,8 +49,6 @@
 import com.sun.prism.ps.ShaderFactory;
 import java.lang.reflect.Method;
 import java.util.HashMap;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
 
 public class ES2ResourceFactory extends BaseShaderFactory {
 
@@ -59,17 +57,8 @@
 
     ES2ResourceFactory(Screen screen) {
         context = new ES2Context(screen, this);
-        int max = Integer.valueOf(
-                AccessController.doPrivileged(new PrivilegedAction<String>() {
-                    public String run() {
-                        return System.getProperty("maxTextureSize", "0");
-                    }
-                }));
-        if (max == 0) {
-            maxTextureSize = computeMaxTextureSize();
-        } else {
-            maxTextureSize = max;
-        }
+        maxTextureSize = computeMaxTextureSize();
+
         if (PrismSettings.verbose) {
             System.out.println("Non power of two texture support = " + 
                     context.getGLContext().canCreateNonPowTwoTextures());
--- a/modules/graphics/src/main/java/com/sun/prism/es2/ES2SwapChain.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/es2/ES2SwapChain.java	Tue Aug 27 09:36:40 2013 -0700
@@ -68,10 +68,6 @@
     private RTTexture stableBackbuffer;
     private boolean copyFullBuffer;
 
-    public boolean recreateOnResize() {
-        return false;
-    }
-
     public boolean isOpaque() {
         if (stableBackbuffer != null) {
             return stableBackbuffer.isOpaque();
@@ -88,31 +84,26 @@
         }
     }
 
-    /**
-     * If needsResize is true, indicates that the underlying window has been
-     * resized and that the viewport and related state needs to be updated
-     * the next time that the hardware backbuffer is rendered to.
-     */
-    void setNeedsResize(boolean needsResize) {
-        this.needsResize = needsResize;
+    static float getScale(PresentableState pState) {
+        return PrismSettings.allowHiDPIScaling
+               ? pState.getScale() //TODO fix getScale
+               : 1.0f;
     }
 
     ES2SwapChain(ES2Context context, PresentableState pState) {
         this.context = context;
         this.pState = pState;
-        this.pixelScaleFactor = PrismSettings.allowHiDPIScaling
-                                ? pState.getScale() //TODO fix getScale
-                                : 1.0f;
+        this.pixelScaleFactor = getScale(pState);
         this.antiAliasing = pState.isAntiAliasing();
-        drawable = null;
-        if (pState != null) {
-            long nativeWindow = pState.getNativeWindow();
-            drawable = ES2Pipeline.glFactory.createGLDrawable(
-                    nativeWindow, context.getPixelFormat());
-        }
+        long nativeWindow = pState.getNativeWindow();
+        drawable = ES2Pipeline.glFactory.createGLDrawable(
+                nativeWindow, context.getPixelFormat());
     }
 
-    public boolean lockResources() {
+    public boolean lockResources(PresentableState pState) {
+        if (this.pState != pState || pixelScaleFactor != getScale(pState)) {
+            return true;
+        }
         needsResize = (w != getPhysicalWidth() || h != getPhysicalHeight());
         // the stableBackbuffer will be used as the render target
         if (stableBackbuffer != null && !needsResize) {
--- a/modules/graphics/src/main/java/com/sun/prism/es2/GLContext.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/es2/GLContext.java	Tue Aug 27 09:36:40 2013 -0700
@@ -25,6 +25,7 @@
 
 package com.sun.prism.es2;
 
+import com.sun.javafx.PlatformUtil;
 import com.sun.prism.MeshView;
 import com.sun.prism.PhongMaterial.MapType;
 import com.sun.prism.Texture.WrapMode;
@@ -112,6 +113,10 @@
     private boolean msaa = false;
     private int maxSampleSize = -1;
 
+    private static final int FBO_ID_UNSET = -1;
+    private static final int FBO_ID_NOCACHE = -2;
+    private int nativeFBOID = PlatformUtil.isMac() || PlatformUtil.isIOS() ? FBO_ID_NOCACHE : FBO_ID_UNSET;
+
     private static native void nActiveTexture(long nativeCtxInfo, int texUnit);
     private static native void nBindFBO(long nativeCtxInfo, int nativeFBOID);
     private static native void nBindTexture(long nativeCtxInfo, int texID);
@@ -122,9 +127,9 @@
     private static native int nCompileShader(long nativeCtxInfo, String src,
             boolean vertex);
     private static native int nCreateDepthBuffer(long nativeCtxInfo, int width,
-            int height, int msaaSamples);
+            int height, int msaa);
     private static native int nCreateRenderBuffer(long nativeCtxInfo, int width,
-            int height, int msaaSamples);
+            int height, int msaa);
     private static native int nCreateFBO(long nativeCtxInfo, int texID);
     private static native int nCreateProgram(long nativeCtxInfo,
             int vertexShaderID, int[] fragmentShaderID,
@@ -235,7 +240,7 @@
     private static native void nSetPointLight(long nativeCtxInfo, long nativeMeshViewInfo,
             int index, float x, float y, float z, float r, float g, float b, float w);
     private static native void nRenderMeshView(long nativeCtxInfo, long nativeMeshViewInfo);
-    private static native int  nBlit(long nativeCtxInfo, int srcFBO, int dstFBO,
+    private static native void nBlit(long nativeCtxInfo, int srcFBO, int dstFBO,
             int srcX0, int srcY0, int srcX1, int srcY1,
             int dstX0, int dstY0, int dstX1, int dstY1);
 
@@ -244,7 +249,21 @@
     }
 
     void bindFBO(int nativeFBOID) {
-        nBindFBO(nativeCtxInfo, nativeFBOID);
+        switch (this.nativeFBOID) {
+            case FBO_ID_UNSET:
+                this.nativeFBOID = nativeFBOID;
+                nBindFBO(nativeCtxInfo, nativeFBOID);
+                break;
+            case FBO_ID_NOCACHE:
+                nBindFBO(nativeCtxInfo, nativeFBOID);
+                break;
+            default:
+                if (this.nativeFBOID != nativeFBOID) {
+                    nBindFBO(nativeCtxInfo, nativeFBOID);
+                    this.nativeFBOID = nativeFBOID;
+                }
+                break;
+        }
     }
 
     void bindTexture(int texID) {
@@ -394,8 +413,16 @@
     }
 
     int getBoundFBO() {
-        return nGetFBO();
+        switch (nativeFBOID) {
+            case FBO_ID_UNSET:
+                nativeFBOID = nGetFBO();
+                return nativeFBOID;
+            case FBO_ID_NOCACHE:
+                return nGetFBO();
+            default:
+                return nativeFBOID;
         }
+    }
 
     int getBoundTextureID() {
         // return the single value param
--- a/modules/graphics/src/main/java/com/sun/prism/impl/BaseContext.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/impl/BaseContext.java	Tue Aug 27 09:36:40 2013 -0700
@@ -160,16 +160,6 @@
         return glyphCache;
     }
 
-    /**
-     * Returns true if texture edge smoothing trickery is supported on
-     * this device for the given {@code PixelFormat}; otherwise returns false.
-     * See BaseGraphics.drawTextureVO() for more details on how the texture
-     * edge smoothing techniques are implemented.
-     */
-    public boolean isEdgeSmoothingSupported(PixelFormat format) {
-        return true;
-    }
-
     public Texture getMaskTexture(MaskData maskData, boolean canScale) {
         int maskW = maskData.getWidth();
         int maskH = maskData.getHeight();
--- a/modules/graphics/src/main/java/com/sun/prism/impl/GlyphCache.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/impl/GlyphCache.java	Tue Aug 27 09:36:40 2013 -0700
@@ -273,7 +273,7 @@
 
         // Render the glyph and insert it in the cache
         GlyphData data = null;
-        Glyph glyph = strike.getGlyph(gl, gi);
+        Glyph glyph = strike.getGlyph(glyphCode);
         if (glyph != null) {
             if (glyph.getWidth() == 0 || glyph.getHeight() == 0) {
                 data = new GlyphData(0, 0, 0,
--- a/modules/graphics/src/main/java/com/sun/prism/impl/PrismSettings.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/impl/PrismSettings.java	Tue Aug 27 09:36:40 2013 -0700
@@ -58,7 +58,6 @@
     public static final boolean doNativePisces;
     public static final String refType;
     public static final boolean forceRepaint;
-    public static final boolean isEmbededDevice;
     public static final boolean noFallback;
     public static final boolean showDirtyRegions;
     public static final boolean showCull;
@@ -79,6 +78,7 @@
     public static final long targetVram;
     public static final boolean poolStats;
     public static final boolean poolDebug;
+    public static final boolean disableEffects;
 
     private PrismSettings() {
     }
@@ -243,8 +243,6 @@
         shutdownHook = getBoolean(systemProperties, "prism.shutdownHook",
                                   PlatformUtil.isUnix());
 
-        isEmbededDevice = getBoolean(systemProperties, "prism.device", false);
-
         forcePow2 = getBoolean(systemProperties, "prism.forcepowerof2", false);
         noClampToZero = getBoolean(systemProperties, "prism.noclamptozero", false);
 
@@ -304,19 +302,24 @@
          * This is a workaround for the bugs seen on device creating small textures (see TVP-256)
          * This value should not be set normally.
          */
-        minTextureSize = isEmbededDevice
-                             ? getInt(systemProperties, "prism.mintexturesize",
-                                      0, "Try -Dprism.mintexturesize=<number>")
-                             : 0;
+        minTextureSize = getInt(systemProperties, "prism.mintexturesize", 0,
+                "Try -Dprism.mintexturesize=<number>");
 
-        minRTTSize = getInt(systemProperties, "prism.minrttsize",
-                                      isEmbededDevice ? 16 : 0, "Try -Dprism.minrttsize=<number>");
+        /*
+         * Check minimum RTT size
+         * This is needed for some embedded platforms to avoid rendering artifacts
+         * when rendering into small RTT.
+         */
+       minRTTSize = getInt(systemProperties, "prism.minrttsize",                       
+               PlatformUtil.isEmbedded() ? 16 : 0, "Try -Dprism.minrttsize=<number>");
 
         disableRegionCaching = getBoolean(systemProperties,
                                           "prism.disableRegionCaching",
                                           false);
 
         disableD3D9Ex = getBoolean(systemProperties, "prism.disableD3D9Ex", true);
+        
+        disableEffects = getBoolean(systemProperties, "prism.disableEffects", false);
     }
 
     private static int parseInt(String s, int dflt, int trueDflt,
--- a/modules/graphics/src/main/java/com/sun/prism/impl/packrect/Level.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/impl/packrect/Level.java	Tue Aug 27 09:36:40 2013 -0700
@@ -27,32 +27,36 @@
 
 import com.sun.javafx.geom.Rectangle;
 
-import java.util.ArrayList;
-import java.util.List;
+class Level {
+    int length;
+    int size;
+    private int sizeOffset;
+    private int lengthOffset;
 
-class Level {
-    int width;
-    int height;
-    private int yPos;
-
-    private List<Rectangle> rectangles = new ArrayList<Rectangle>();
-    private int nextAddX;
-
-    Level(int width, int height, int yPos) {
-        this.width = width;
-        this.height = height;
-        this.yPos = yPos;
+    Level(int length, int size, int sizeOffset) {
+        this.length = length;
+        this.size = size;
+        this.sizeOffset = sizeOffset;
     }
 
     /**
      * Tries to add the given rectangle to this level.
      */
-    boolean add(Rectangle rect) {
+    boolean add(Rectangle rect, int x, int y, int requestedLength, int requestedSize, boolean vertical) {
         // See whether we can add at the end
-        if (nextAddX + rect.width <= width && rect.height <= height) {
-            rect.setBounds(nextAddX, yPos, rect.width, rect.height);
-            rectangles.add(rect);
-            nextAddX += rect.width;
+        if (lengthOffset + requestedLength <= length && requestedSize <= size) {
+            if (vertical) {
+                rect.x = sizeOffset;
+                rect.y = lengthOffset;
+            } else {
+                rect.x = lengthOffset;
+                rect.y = sizeOffset;
+            }
+            lengthOffset += requestedLength;
+
+            // this x,y location are external offsets and should not be flipped
+            rect.x += x;
+            rect.y += y;
             return true;
         }
         return false;
--- a/modules/graphics/src/main/java/com/sun/prism/impl/packrect/RectanglePacker.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/impl/packrect/RectanglePacker.java	Tue Aug 27 09:36:40 2013 -0700
@@ -48,12 +48,30 @@
      algorithm for the contained Rects. */
     // Maintained in sorted order by increasing Y coordinate
     private List<Level> levels = new ArrayList<Level>(150);
-    private static final int MIN_HEIGHT = 8; // The minimum height of level
+    private static final int MIN_SIZE = 8; // The minimum size of level
     private static final int ROUND_UP = 4; // Round up to multiple of 4
     private int recentUsedLevelIndex = 0;
-    private int nextAddY;
-    private int w;
-    private int h;
+    private int length;
+    private int size;
+    private int sizeOffset;
+    private int x;
+    private int y;
+    private boolean vertical;
+
+    public RectanglePacker(Texture backingStore, int x, int y,
+                           int width, int height, boolean vertical) {
+        this.backingStore = backingStore;
+        if (vertical) {
+            this.length = height;
+            this.size = width;
+        } else {
+            this.length = width;
+            this.size = height;
+        }
+        this.x = x;
+        this.y = y;
+        this.vertical = vertical;
+    }
 
     /**
      * Creates a new RectanglePacker. You must specify the texture used as the
@@ -65,9 +83,7 @@
      * @param height The height of the backing store, must be > 0 (typically > 512)
      */
     public RectanglePacker(Texture backingStore, int width, int height) {
-        this.backingStore = backingStore;
-        this.w = width;
-        this.h = height;
+        this(backingStore, 0, 0, width, height, false);
     }
 
     /**
@@ -85,25 +101,29 @@
      */
     public final boolean add(Rectangle rect) {
         // N need to continue if the rectangle simply won't fit.
-        if (rect.width > w) return false;
+        final int requestedLength = vertical ? rect.height : rect.width;
+        final int requestedSize = vertical ? rect.width : rect.height;
 
-        int newHeight = MIN_HEIGHT > rect.height ? MIN_HEIGHT : rect.height;
+        if (requestedLength > length) return false;
+        if (requestedSize > size) return false;
+
+        int newSize = MIN_SIZE > requestedSize ? MIN_SIZE : requestedSize;
 
         // Round up
-        newHeight = (newHeight + ROUND_UP - 1) - (newHeight - 1) % ROUND_UP;
+        newSize = (newSize + ROUND_UP - 1) - (newSize - 1) % ROUND_UP;
 
         int newIndex;
         // If it does not match recent used level, using binary search to find
         // the best fit level's index
-        if (recentUsedLevelIndex < levels.size()
-                && levels.get(recentUsedLevelIndex).height != newHeight) {
-            newIndex = binarySearch(levels, newHeight);
+        if (recentUsedLevelIndex < levels.size() &&
+            levels.get(recentUsedLevelIndex).size != newSize) {
+            newIndex = binarySearch(levels, newSize);
         } else {
             newIndex = recentUsedLevelIndex;
         }
 
-        // Can create a new level with newHeight
-        boolean newLevelFlag = nextAddY + newHeight <= h;
+        // Can create a new level with newSize
+        final boolean newLevelFlag = sizeOffset + newSize <= size;
 
         // Go through the levels check whether we can satisfy the allocation
         // request
@@ -111,9 +131,9 @@
             Level level = levels.get(i);
             // If level's height is more than (newHeight + ROUND_UP * 2) and
             // the cache still has some space left, go create a new level
-            if (level.height > (newHeight + ROUND_UP * 2) && newLevelFlag) {
+            if (level.size > (newSize + ROUND_UP * 2) && newLevelFlag) {
                 break;
-            } else if (level.add(rect)) {
+            } else if (level.add(rect, x, y, requestedLength, requestedSize, vertical)) {
                 recentUsedLevelIndex = i;
                 return true;
             }
@@ -124,19 +144,19 @@
             return false;
         }
 
-        Level newLevel = new Level(w, newHeight, nextAddY);
-        nextAddY += newHeight;
+        Level newLevel = new Level(length, newSize, sizeOffset);
+        sizeOffset += newSize;
 
         // For a rect that cannot fit into the existing level, create a new
         // level and add at the end of levels that have the same height
-        if (newIndex < levels.size() && levels.get(newIndex).height <= newHeight) {
+        if (newIndex < levels.size() && levels.get(newIndex).size <= newSize) {
             levels.add(newIndex + 1, newLevel);
             recentUsedLevelIndex = newIndex + 1;
         } else {
             levels.add(newIndex, newLevel);
             recentUsedLevelIndex = newIndex;
         }
-        return newLevel.add(rect);
+        return newLevel.add(rect, x, y, requestedLength, requestedSize, vertical);
     }
 
     /**
@@ -144,7 +164,7 @@
      */
     public void clear() {
         levels.clear();
-        nextAddY = 0;
+        sizeOffset = 0;
         recentUsedLevelIndex = 0;
     }
 
@@ -170,10 +190,13 @@
         // likely, there are a bunch of levels have the same height. But, we always keep adding levels and
         // rects at the end. k+1 is a trick to find the last index by finding the next greater value's index
         // and go back one.
+        // Note that since the sizes are quantized, k+1 is a special value that will not appear in the list
+        // of level sizes and so the search for it will find the gap between the size for k and the size
+        // for the next quantum.
         int key = k + 1;
         int from = 0, to = levels.size() - 1;
         int mid = 0;
-        int height = 0;
+        int midSize = 0;
 
         if (to < 0) {
             return 0;
@@ -181,17 +204,17 @@
 
         while (from <= to) {
             mid = (from + to) / 2;
-            height = levels.get(mid).height;
-            if (key < height) {
+            midSize = levels.get(mid).size;
+            if (key < midSize) {
                 to = mid - 1;
             } else {
                 from = mid + 1;
             }
         }
 
-        if (height < k) {
+        if (midSize < k) {
             return mid + 1;
-        } else if (height > k) {
+        } else if (midSize > k) {
             return mid > 0 ? mid - 1 : 0;
         } else {
             return mid;
--- a/modules/graphics/src/main/java/com/sun/prism/j2d/J2DPresentable.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/j2d/J2DPresentable.java	Tue Aug 27 09:36:40 2013 -0700
@@ -57,6 +57,7 @@
 
     private static class Glass extends J2DPresentable {
         private final PresentableState pState;
+        private final int theFormat;
         private Pixels pixels;
         private IntBuffer pixBuf;
         private final AtomicInteger uploadCount = new AtomicInteger(0);
@@ -65,19 +66,19 @@
         Glass(PresentableState pState, J2DResourceFactory factory) {
             super(null, factory);
             this.pState = pState;
-            setNeedsResize();
+            this.theFormat = pState.getPixelFormat();
+            needsResize = true;
         }
 
         @Override
         public BufferedImage createBuffer(int w, int h) {
             pixels = null;
             pixBuf = null;
-            int format = pState.getPixelFormat();
             if (PrismSettings.verbose) {
-                System.out.println("Glass native format: "+format);
+                System.out.println("Glass native format: "+theFormat);
             }
             ByteOrder byteorder = ByteOrder.nativeOrder();
-            switch (format) {
+            switch (theFormat) {
                 case Pixels.Format.BYTE_BGRA_PRE:
                     if (byteorder == ByteOrder.LITTLE_ENDIAN) {
                         return new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB_PRE);
@@ -93,12 +94,23 @@
                     }
                     /* NOTREACHED */
                 default:
-                    throw new UnsupportedOperationException("unrecognized pixel format: "+format);
+                    throw new UnsupportedOperationException("unrecognized pixel format: "+theFormat);
             }
         }
 
         private final Application app = Application.GetApplication();
 
+        @Override
+        public boolean lockResources(PresentableState pState) {
+            if (this.pState != pState || this.theFormat != pState.getPixelFormat()) {
+                return true;
+            }
+            needsResize = (buffer == null ||
+                           buffer.getWidth() != pState.getWidth() ||
+                           buffer.getHeight() != pState.getHeight());
+            return false;
+        }
+
         public boolean prepare(Rectangle dirty) {
             if (pState.isViewClosed() == false) {
                 /*
@@ -155,6 +167,11 @@
             throw new UnsupportedOperationException("cannot create new buffers for image");
         }
 
+        @Override
+        public boolean lockResources(PresentableState pState) {
+            return false;
+        }
+
         public boolean prepare(Rectangle dirtyregion) {
             throw new UnsupportedOperationException("cannot prepare/present on image");
         }
@@ -193,14 +210,6 @@
         this.factory = factory;
     }
 
-    public boolean lockResources() {
-        return false;
-    }
-
-    public void setNeedsResize() {
-        this.needsResize = true;
-    }
-
     ResourceFactory getResourceFactory() {
         return factory;
     }
@@ -208,27 +217,20 @@
     public abstract BufferedImage createBuffer(int w, int h);
 
     public Graphics createGraphics() {
-        // RT-27385
-        // TODO: Figure out why needsResize is not always set appropriately
-        if (true || needsResize) {
+        if (needsResize) {
             int w = getContentWidth();
             int h = getContentHeight();
             // TODO: Have Glass Pixels class relax its constraints
             // so we can use an oversized buffer if we want to...
-            if (buffer == null ||
-                buffer.getWidth() != w ||
-                buffer.getHeight() != h)
-            {
-                buffer = null;
-                readbackBuffer = null;
-                buffer = createBuffer(w, h);
-                java.awt.image.Raster r = buffer.getRaster();
-                java.awt.image.DataBuffer db = r.getDataBuffer();
-                java.awt.image.SinglePixelPackedSampleModel sppsm =
-                    (java.awt.image.SinglePixelPackedSampleModel) r.getSampleModel();
-                int pixels[] = ((java.awt.image.DataBufferInt) db).getData();
-                ib = IntBuffer.wrap(pixels, db.getOffset(), db.getSize());
-            }
+            buffer = null;
+            readbackBuffer = null;
+            buffer = createBuffer(w, h);
+            java.awt.image.Raster r = buffer.getRaster();
+            java.awt.image.DataBuffer db = r.getDataBuffer();
+            java.awt.image.SinglePixelPackedSampleModel sppsm =
+                (java.awt.image.SinglePixelPackedSampleModel) r.getSampleModel();
+            int pixels[] = ((java.awt.image.DataBufferInt) db).getData();
+            ib = IntBuffer.wrap(pixels, db.getOffset(), db.getSize());
             needsResize = false;
         }
         Graphics2D g2d = (Graphics2D) buffer.getGraphics();
@@ -279,10 +281,6 @@
         return (buffer == null) ? getContentHeight() : buffer.getHeight();
     }
 
-    public boolean recreateOnResize() {
-        return false;
-    }
-
     @Override public boolean isAntiAliasing() {
         return false;
     }
--- a/modules/graphics/src/main/java/com/sun/prism/j2d/PrismPrintGraphics.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/j2d/PrismPrintGraphics.java	Tue Aug 27 09:36:40 2013 -0700
@@ -26,6 +26,7 @@
 package com.sun.prism.j2d;
 
 import com.sun.javafx.geom.Rectangle;
+import com.sun.prism.PresentableState;
 import com.sun.prism.PrinterGraphics;
 
 public final class PrismPrintGraphics
@@ -49,6 +50,11 @@
             throw new UnsupportedOperationException("cannot create new buffers for image");
         }
 
+        @Override
+        public boolean lockResources(PresentableState pState) {
+            return false;
+        }
+
         public boolean prepare(Rectangle dirtyregion) {
             throw new UnsupportedOperationException("Cannot prepare an image");
         }
--- a/modules/graphics/src/main/java/com/sun/prism/j2d/print/J2DPrinterJob.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/j2d/print/J2DPrinterJob.java	Tue Aug 27 09:36:40 2013 -0700
@@ -66,6 +66,7 @@
 import java.awt.print.PageFormat;
 import java.awt.print.Pageable;
 import java.awt.print.Printable;
+import java.awt.print.PrinterException;
 import java.util.ArrayList;
 import java.util.Set;
 import com.sun.glass.ui.Application;
@@ -83,7 +84,7 @@
     java.awt.print.PrinterJob pJob2D;
     javafx.print.Printer fxPrinter;
     J2DPrinter j2dPrinter;
-
+    
     private JobSettings settings;
     private PrintRequestAttributeSet printReqAttrSet;
 
@@ -94,6 +95,10 @@
         j2dPrinter = getJ2DPrinter(fxPrinter);
         settings = fxPrinterJob.getJobSettings();
         pJob2D = java.awt.print.PrinterJob.getPrinterJob();
+        try {
+            pJob2D.setPrintService(j2dPrinter.getService());
+        } catch (PrinterException pe) {
+        }
         printReqAttrSet = new HashPrintRequestAttributeSet();
         // dialog selection is a JDK 1.7 attribute.
         // We expect to run on 1.8 and above so this should be fine.
@@ -437,6 +442,10 @@
     public void setPrinterImpl(PrinterImpl impl) {
         j2dPrinter = (J2DPrinter)impl;
         fxPrinter = j2dPrinter.getPrinter();
+        try {
+            pJob2D.setPrintService(j2dPrinter.getService());
+        } catch (PrinterException pe) {
+        }
     }
 
     public PrinterImpl getPrinterImpl() {
@@ -454,6 +463,10 @@
     public void setPrinter(Printer printer) {
         fxPrinter = printer;
         j2dPrinter = getJ2DPrinter(printer);
+        try {
+            pJob2D.setPrintService(j2dPrinter.getService());
+        } catch (PrinterException pe) {
+        }
     }
 
     private void updatePrinter() {
--- a/modules/graphics/src/main/java/com/sun/prism/null3d/DummyGraphics.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/null3d/DummyGraphics.java	Tue Aug 27 09:36:40 2013 -0700
@@ -49,9 +49,6 @@
     public void sync() {
     }
 
-    public void reset() {
-    }
-
     @Override
     public void setState3D(boolean flag) {
     }
--- a/modules/graphics/src/main/java/com/sun/prism/null3d/DummySwapChain.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/null3d/DummySwapChain.java	Tue Aug 27 09:36:40 2013 -0700
@@ -52,7 +52,7 @@
         super.dispose();
     }
 
-    public boolean lockResources() {
+    public boolean lockResources(PresentableState pState) {
         texBackBuffer.lock();
         return false;
     }
@@ -102,10 +102,6 @@
         return context.getAssociatedScreen();
     }
 
-    public boolean recreateOnResize() {
-        return false;
-    }
-
     public boolean isOpaque() {
         return opaque;
     }
--- a/modules/graphics/src/main/java/com/sun/prism/paint/ImagePattern.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/paint/ImagePattern.java	Tue Aug 27 09:36:40 2013 -0700
@@ -26,7 +26,6 @@
 package com.sun.prism.paint;
 
 import com.sun.prism.Image;
-import com.sun.prism.paint.Paint.Type;
 
 public final class ImagePattern extends Paint {
 
@@ -72,6 +71,6 @@
     }
 
     public boolean isOpaque() {
-        return image.getPixelFormat().isOpaque();
+        return image.isOpaque();
     }
 }
--- a/modules/graphics/src/main/java/com/sun/prism/sw/SWArgbPreTexture.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/sw/SWArgbPreTexture.java	Tue Aug 27 09:36:40 2013 -0700
@@ -137,6 +137,9 @@
             frame = f;
         }
 
+        this.offset = frame.offsetForPlane(0) / 4;
+        this.stride = frame.strideForPlane(0) / 4;
+
         IntBuffer ib = frame.getBuffer().asIntBuffer();
         if (ib.hasArray()) {
             this.allocated = false;
@@ -145,8 +148,6 @@
             this.allocate();
             ib.get(this.data);
         }
-        this.offset = frame.offsetForPlane(0) / 4;
-        this.stride = frame.strideForPlane(0) / 4;
 
         frame.releaseFrame();
     }
@@ -180,7 +181,10 @@
     }
 
     void allocateBuffer() {
-        this.data = new int[width * height];
+        if (stride < width) {
+            throw new IllegalArgumentException("STRIDE must be equal or greater than WIDTH");
+        }
+        this.data = new int[stride * height];
     }
 
     Texture createSharedLockedTexture(WrapMode altMode) {
--- a/modules/graphics/src/main/java/com/sun/prism/sw/SWGraphics.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/sw/SWGraphics.java	Tue Aug 27 09:36:40 2013 -0700
@@ -130,10 +130,6 @@
     public void sync() {
     }
 
-    public void reset() {
-        throw new UnsupportedOperationException("unimp: SWG.reset");
-    }
-
     private static void convertToPiscesTransform(BaseTransform prismTx, Transform6 piscesTx) {
         piscesTx.m00 = (int) (TO_PISCES * prismTx.getMxx());
         piscesTx.m10 = (int) (TO_PISCES * prismTx.getMyx());
@@ -817,6 +813,15 @@
                             float dx1, float dy1, float dx2, float dy2,
                             float sx1, float sy1, float sx2, float sy2)
     {
+        this.drawTexture(tex, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2,
+                RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP,
+                RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP);
+    }
+
+    private void drawTexture(Texture tex,
+                             float dx1, float dy1, float dx2, float dy2,
+                             float sx1, float sy1, float sx2, float sy2,
+                             int lEdge, int rEdge, int tEdge, int bEdge) {
         final int imageMode;
         if (compositeAlpha == 1f) {
             imageMode = RendererBase.IMAGE_MODE_NORMAL;
@@ -824,12 +829,13 @@
             imageMode = RendererBase.IMAGE_MODE_MULTIPLY;
             this.pr.setColor(255, 255, 255, (int)(255 * compositeAlpha));
         }
-        this.drawTexture(tex, imageMode, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2);
+        this.drawTexture(tex, imageMode, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, lEdge, rEdge, tEdge, bEdge);
     }
 
     private void drawTexture(Texture tex, int imageMode,
                             float dx1, float dy1, float dx2, float dy2,
-                            float sx1, float sy1, float sx2, float sy2) {
+                            float sx1, float sy1, float sx2, float sy2,
+                            int lEdge, int rEdge, int tEdge, int bEdge) {
         if (PrismSettings.debug) {
             System.out.println("+ drawTexture: " + tex + ", imageMode: " + imageMode +
                     ", tex.w: " + tex.getPhysicalWidth() + ", tex.h: " + tex.getPhysicalHeight());
@@ -894,6 +900,7 @@
                 piscesTx, false,
                 (int)(TO_PISCES * dstBBox.getMinX()), (int)(TO_PISCES * dstBBox.getMinY()),
                 (int)(TO_PISCES * dstBBox.getWidth()), (int)(TO_PISCES * dstBBox.getHeight()),
+                lEdge, rEdge, tEdge, bEdge,
                 interpolateMinX, interpolateMinY, interpolateMaxX, interpolateMaxY,
                 swTex.hasAlpha());
 
@@ -908,9 +915,15 @@
                                    float sx1, float sy1, float sx2, float sy2,
                                    float dh1, float dh2, float sh1, float sh2)
     {
-        drawTexture(tex, dx1, dy1, dh1, dy2, sx1, sy1, sh1, sy2);
-        drawTexture(tex, dh1, dy1, dh2, dy2, sh1, sy1, sh2, sy2);
-        drawTexture(tex, dh2, dy1, dx2, dy2, sh2, sy1, sx2, sy2);
+        drawTexture(tex, dx1, dy1, dh1, dy2, sx1, sy1, sh1, sy2,
+                RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_PAD,
+                RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP);
+        drawTexture(tex, dh1, dy1, dh2, dy2, sh1, sy1, sh2, sy2,
+                RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_PAD,
+                RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP);
+        drawTexture(tex, dh2, dy1, dx2, dy2, sh2, sy1, sx2, sy2,
+                RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_KEEP,
+                RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP);
     }
 
     @Override
@@ -919,9 +932,15 @@
                                    float sx1, float sy1, float sx2, float sy2,
                                    float dv1, float dv2, float sv1, float sv2)
     {
-        drawTexture(tex, dx1, dy1, dx2, dv1, sx1, sy1, sx2, sv1);
-        drawTexture(tex, dx1, dv1, dx2, dv2, sx1, sv1, sx2, sv2);
-        drawTexture(tex, dx1, dv2, dx2, dy2, sx1, sv2, sx2, sy2);
+        drawTexture(tex, dx1, dy1, dx2, dv1, sx1, sy1, sx2, sv1,
+                RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP,
+                RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_PAD);
+        drawTexture(tex, dx1, dv1, dx2, dv2, sx1, sv1, sx2, sv2,
+                RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP,
+                RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_PAD);
+        drawTexture(tex, dx1, dv2, dx2, dy2, sx1, sv2, sx2, sy2,
+                RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP,
+                RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_KEEP);
     }
 
     @Override
@@ -931,17 +950,35 @@
                                   float dh1, float dv1, float dh2, float dv2,
                                   float sh1, float sv1, float sh2, float sv2)
     {
-        drawTexture(tex, dx1, dy1, dh1, dv1, sx1, sy1, sh1, sv1);
-        drawTexture(tex, dh1, dy1, dh2, dv1, sh1, sy1, sh2, sv1);
-        drawTexture(tex, dh2, dy1, dx2, dv1, sh2, sy1, sx2, sv1);
+        drawTexture(tex, dx1, dy1, dh1, dv1, sx1, sy1, sh1, sv1,
+                RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_PAD,
+                RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_PAD);
+        drawTexture(tex, dh1, dy1, dh2, dv1, sh1, sy1, sh2, sv1,
+                RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_PAD,
+                RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_PAD);
+        drawTexture(tex, dh2, dy1, dx2, dv1, sh2, sy1, sx2, sv1,
+                RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_KEEP,
+                RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_PAD);
 
-        drawTexture(tex, dx1, dv1, dh1, dv2, sx1, sv1, sh1, sv2);
-        drawTexture(tex, dh1, dv1, dh2, dv2, sh1, sv1, sh2, sv2);
-        drawTexture(tex, dh2, dv1, dx2, dv2, sh2, sv1, sx2, sv2);
+        drawTexture(tex, dx1, dv1, dh1, dv2, sx1, sv1, sh1, sv2,
+                RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_PAD,
+                RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_PAD);
+        drawTexture(tex, dh1, dv1, dh2, dv2, sh1, sv1, sh2, sv2,
+                RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_PAD,
+                RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_PAD);
+        drawTexture(tex, dh2, dv1, dx2, dv2, sh2, sv1, sx2, sv2,
+                RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_KEEP,
+                RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_PAD);
 
-        drawTexture(tex, dx1, dv2, dh1, dy2, sx1, sv2, sh1, sy2);
-        drawTexture(tex, dh1, dv2, dh2, dy2, sh1, sv2, sh2, sy2);
-        drawTexture(tex, dh2, dv2, dx2, dy2, sh2, sv2, sx2, sy2);
+        drawTexture(tex, dx1, dv2, dh1, dy2, sx1, sv2, sh1, sy2,
+                RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_PAD,
+                RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_KEEP);
+        drawTexture(tex, dh1, dv2, dh2, dy2, sh1, sv2, sh2, sy2,
+                RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_PAD,
+                RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_KEEP);
+        drawTexture(tex, dh2, dv2, dx2, dy2, sh2, sv2, sx2, sy2,
+                RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_KEEP,
+                RendererBase.IMAGE_FRAC_EDGE_TRIM, RendererBase.IMAGE_FRAC_EDGE_KEEP);
     }
 
     private void computeScaleAndPixelCorrection(float[] target, float dv1, float dv2, float sv1, float sv2) {
@@ -979,7 +1016,9 @@
         convertToPiscesTransform(this.tx, t6);
         this.pr.setLinearGradient(0, (int)(TO_PISCES * dy1), 0, (int)(TO_PISCES * dy2), fractions, argb,
                                   GradientColorMap.CYCLE_NONE, t6);
-        this.drawTexture(tex, RendererBase.IMAGE_MODE_MULTIPLY, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2);
+        this.drawTexture(tex, RendererBase.IMAGE_MODE_MULTIPLY, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2,
+                RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP,
+                RendererBase.IMAGE_FRAC_EDGE_KEEP, RendererBase.IMAGE_FRAC_EDGE_KEEP);
     }
 
     public void drawTextureRaw(Texture tex,
--- a/modules/graphics/src/main/java/com/sun/prism/sw/SWPresentable.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/prism/sw/SWPresentable.java	Tue Aug 27 09:36:40 2013 -0700
@@ -46,8 +46,9 @@
         this.pState = pState;
     }
 
-    public boolean lockResources() {
-        return false;
+    public boolean lockResources(PresentableState pState) {
+        return (getPhysicalWidth() != pState.getWidth() ||
+                getPhysicalHeight() != pState.getHeight());
     }
 
     public boolean prepare(Rectangle dirtyregion) {
@@ -82,10 +83,6 @@
         return 1.0f;
     }
 
-    public boolean recreateOnResize() {
-        return true;
-    }
-
     public int getContentWidth() {
         return pState.getWidth();
     }
--- a/modules/graphics/src/main/java/com/sun/scenario/effect/BoxBlur.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/scenario/effect/BoxBlur.java	Tue Aug 27 09:36:40 2013 -0700
@@ -88,7 +88,7 @@
      *
      * @param hsize the horizontal size of the BoxBlur kernel
      * @param vsize the vertical size of the BoxBlur kernel
-     * @param numpasses the number of blur passes to execute
+     * @param passes the number of blur passes to execute
      * @throws IllegalArgumentException if either {@code hsize}
      * or {@code vsize} or {@code passes}
      * is outside the allowable range
@@ -105,7 +105,7 @@
      *
      * @param hsize the horizontal size of the BoxBlur kernel
      * @param vsize the vertical size of the BoxBlur kernel
-     * @param numpasses the number of blur passes to execute
+     * @param passes the number of blur passes to execute
      * @param input the single input {@code Effect}
      * @throws IllegalArgumentException if either {@code hsize}
      * or {@code vsize} or {@code passes}
@@ -220,8 +220,8 @@
      * A setting of 1 creates a low quality blur.  A setting of 3 creates
      * a blur that is very close to a Gaussian blur.
      *
-     * @param radius the radius of the effect kernel
-     * @throws IllegalArgumentException if {@code radius} is outside the
+     * @param passes
+     * @throws IllegalArgumentException if {@code passes} is outside the
      * allowable range
      */
     public void setPasses(int passes) {
--- a/modules/graphics/src/main/java/com/sun/scenario/effect/BoxShadow.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/scenario/effect/BoxShadow.java	Tue Aug 27 09:36:40 2013 -0700
@@ -88,7 +88,7 @@
      *
      * @param hsize the horizontal size of the BoxShadow kernel
      * @param vsize the vertical size of the BoxShadow kernel
-     * @param numpasses the number of blur passes to execute
+     * @param passes the number of blur passes to execute
      * @throws IllegalArgumentException if either {@code hsize}
      * or {@code vsize} or {@code passes}
      * is outside the allowable range
@@ -105,7 +105,7 @@
      *
      * @param hsize the horizontal size of the BoxShadow kernel
      * @param vsize the vertical size of the BoxShadow kernel
-     * @param numpasses the number of blur passes to execute
+     * @param passes the number of blur passes to execute
      * @param input the single input {@code Effect}
      * @throws IllegalArgumentException if either {@code hsize}
      * or {@code vsize} or {@code passes}
@@ -222,8 +222,8 @@
      * A setting of 1 creates a low quality blur.  A setting of 3 creates
      * a blur that is very close to a Gaussian blur.
      *
-     * @param radius the radius of the effect kernel
-     * @throws IllegalArgumentException if {@code radius} is outside the
+     * @param passes
+     * @throws IllegalArgumentException if {@code passes} is outside the
      * allowable range
      */
     public void setPasses(int passes) {
--- a/modules/graphics/src/main/java/com/sun/scenario/effect/GeneralShadow.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/scenario/effect/GeneralShadow.java	Tue Aug 27 09:36:40 2013 -0700
@@ -72,7 +72,7 @@
     }
 
     protected Effect getDelegate() {
-        return (Effect) shadow;
+        return shadow;
     }
 
     /**
--- a/modules/graphics/src/main/java/com/sun/scenario/effect/ImageData.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/scenario/effect/ImageData.java	Tue Aug 27 09:36:40 2013 -0700
@@ -82,8 +82,8 @@
         this(fctx, image, bounds, BaseTransform.IDENTITY_TRANSFORM);
     }
 
-    private ImageData(FilterContext fctx, Filterable image, Rectangle bounds,
-                      BaseTransform transform)
+    public ImageData(FilterContext fctx, Filterable image, Rectangle bounds,
+                     BaseTransform transform)
     {
         this.fctx = fctx;
         this.refcount = 1;
@@ -117,6 +117,9 @@
     }
 
     public void setReusable(boolean reusable) {
+        if (sharedOwner != null) {
+            throw new InternalError("cannot make a shared ImageData reusable");
+        }
         this.reusable = reusable;
     }
 
--- a/modules/graphics/src/main/java/com/sun/scenario/effect/impl/prism/ps/PPSRenderer.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/com/sun/scenario/effect/impl/prism/ps/PPSRenderer.java	Tue Aug 27 09:36:40 2013 -0700
@@ -318,12 +318,15 @@
         // depend on that texture...
         g.sync();
         tex.dispose();
-        ImageData id = new ImageData(fctx, dst, new Rectangle(w, h));
+        BaseTransform tx;
         float ps = img.getPixelScale();
         if (ps != 1.0f) {
             ps = 1.0f / ps;
-            id = id.transform(BaseTransform.getScaleInstance(ps, ps));
+            tx = BaseTransform.getScaleInstance(ps, ps);
+        } else {
+            tx = BaseTransform.IDENTITY_TRANSFORM;
         }
+        ImageData id = new ImageData(fctx, dst, new Rectangle(w, h), tx);
         return id;
     }
 
--- a/modules/graphics/src/main/java/javafx/application/Application.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/javafx/application/Application.java	Tue Aug 27 09:36:40 2013 -0700
@@ -244,6 +244,12 @@
     }
 
     /**
+     * Constructs a new {@code Application} instance.
+     */
+    public Application() {
+    }
+
+    /**
      * The application initialization method. This method is called immediately
      * after the Application class is loaded and constructed. An application may
      * override this method to perform initialization prior to the actual starting
@@ -359,6 +365,12 @@
     public static abstract class Parameters {
 
         /**
+         * Constructs a new {@code Parameters} instance.
+         */
+        public Parameters() {
+        }
+
+        /**
          * Retrieves a read-only list of the raw arguments. This list
          * may be empty, but is never null. In the case of a standalone
          * application, it is the ordered list of arguments specified on the
--- a/modules/graphics/src/main/java/javafx/print/PrinterJob.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/javafx/print/PrinterJob.java	Tue Aug 27 09:36:40 2013 -0700
@@ -119,7 +119,7 @@
         if (printer == null) {
             return null;
         } else {
-            return new PrinterJob(printer, null);
+            return new PrinterJob(printer);
         }
     }
 
@@ -138,29 +138,13 @@
         if (security != null) {
             security.checkPrintJobAccess();
         }
-        return new PrinterJob(printer, null);
+        return new PrinterJob(printer);
     }
 
-    private PrinterJob(Printer printer, JobSettings jobSettings) {
-        this.printer = new SimpleObjectProperty<Printer>(printer) {
+    private PrinterJob(Printer printer) {
 
-            @Override
-            public void bind(ObservableValue<? extends Printer> rawObservable)
-            {
-                throw new RuntimeException("Printer property cannot be bound");
-            }
-
-            @Override
-            public void bindBidirectional(Property<Printer> other) {
-                throw new RuntimeException("Printer property cannot be bound");
-            }
-        };
-        if (jobSettings == null) {
-            jobSettings = printer.getDefaultJobSettings();
-        } else {
-            jobSettings.updateForPrinter(printer);
-        }
-        settings = jobSettings;
+        this.printer = createPrinterProperty(printer);
+        settings = printer.getDefaultJobSettings();
         settings.setPrinterJob(this);
         createImplJob(printer, settings);
     }
@@ -175,7 +159,7 @@
 
     /**
      * Updating settings or printer is only allowed on a new job,
-     * meaning beforee you start printing or cancel etc.
+     * meaning before you start printing or cancel etc.
      * The implementation needs to check this wherever job state
      * updates are received.
      */
@@ -183,37 +167,53 @@
         return getJobStatus() == JobStatus.NOT_STARTED;
     }
 
+    private ObjectProperty<Printer> createPrinterProperty(Printer printer) {
+        
+        return new SimpleObjectProperty<Printer>(printer) {
+   
+            @Override
+            public void set(Printer value) {
+                if (value == get() || !isJobNew()) {
+                    return;
+                }
+                if (value == null) {
+                    value = Printer.getDefaultPrinter();
+                }
+                super.set(value);
+                jobImpl.setPrinterImpl(value.getPrinterImpl());
+                settings.updateForPrinter(value);
+            }
+
+            @Override
+            public void bind(ObservableValue<? extends Printer> rawObservable) {
+                throw new RuntimeException("Printer property cannot be bound");
+            }
+
+            @Override
+            public void bindBidirectional(Property<Printer> other) {
+                throw new RuntimeException("Printer property cannot be bound");
+            }
+
+            @Override
+            public Object getBean() {
+                return PrinterJob.this;
+            }
+
+            @Override
+            public String getName() {
+                return "printer";
+            }
+        };
+    }
+ 
     /**
-     * Property representing the <code>Printer</code> for this job.
+     * Property representing the
+     * <code>Printer</code> for this job.
      */
     public final ObjectProperty<Printer> printerProperty() {
-        if (printer == null) {
-            printer = new SimpleObjectProperty<Printer>() {
-
-                @Override
-                public void set(Printer value) {
-                    if (value == get() || !isJobNew()) {
-                        return;
-                    }
-                    if (value == null) {
-                        value = Printer.getDefaultPrinter();
-                    }
-                    super.set(value);
-                    jobImpl.setPrinterImpl(value.getPrinterImpl());
-                    settings.updateForPrinter(value);
-                }
-
-                @Override
-                public Object getBean() {
-                    return PrinterJob.this;
-                }
-
-                @Override
-                public String getName() {
-                    return "printer";
-                }
-            };
-        }
+        /* The PrinterJob constructor always creates this property,
+         * so it can be returned directly.
+         */
         return printer;
     }
 
@@ -222,7 +222,7 @@
      * @return printer for the job.
      */
     public synchronized Printer getPrinter() {
-        return printer.get();
+        return printerProperty().get();
     }
 
     /**
@@ -238,7 +238,8 @@
      * this method, or as a side-effect of user interaction with a print
      * dialog.
      * <p>
-     * Setting a null printer or the current printer is ignored.
+     * Setting a null value for printer will install the default printer.
+     * Setting the current printer has no effect.
      * @param printer to be used for this print job.
      */
     public synchronized void setPrinter(Printer printer) {
--- a/modules/graphics/src/main/java/javafx/scene/Node.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/javafx/scene/Node.java	Tue Aug 27 09:36:40 2013 -0700
@@ -3666,16 +3666,15 @@
      * clipParent) that this child Node's bounds have changed.
      */
     void transformedBoundsChanged() {
-        if (txBoundsInvalid) {
-            return;
-        }
-        txBounds.makeEmpty();
-        txBoundsInvalid = true;
-        invalidateBoundsInParent();
+        if (!txBoundsInvalid) {
+            txBounds.makeEmpty();
+            txBoundsInvalid = true;
+            invalidateBoundsInParent();
+            impl_markDirty(DirtyBits.NODE_TRANSFORMED_BOUNDS);
+        }
         if (isVisible()) {
             notifyParentOfBoundsChange();
         }
-        impl_markDirty(DirtyBits.NODE_TRANSFORMED_BOUNDS);
     }
 
     /**
--- a/modules/graphics/src/main/java/javafx/scene/layout/Background.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/javafx/scene/layout/Background.java	Tue Aug 27 09:36:40 2013 -0700
@@ -25,16 +25,17 @@
 
 package javafx.scene.layout;
 
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
+import javafx.css.CssMetaData;
+import javafx.css.Styleable;
 import javafx.geometry.Insets;
 import javafx.scene.Node;
 import javafx.scene.image.Image;
 import javafx.scene.paint.Color;
 import javafx.scene.paint.Paint;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 import com.sun.javafx.UnmodifiableArrayList;
-import javafx.css.CssMetaData;
 import com.sun.javafx.css.SubCssMetaData;
 import com.sun.javafx.css.converters.InsetsConverter;
 import com.sun.javafx.css.converters.PaintConverter;
@@ -43,7 +44,7 @@
 import com.sun.javafx.scene.layout.region.LayeredBackgroundSizeConverter;
 import com.sun.javafx.scene.layout.region.RepeatStruct;
 import com.sun.javafx.scene.layout.region.RepeatStructConverter;
-import javafx.css.Styleable;
+import com.sun.javafx.tk.Toolkit;
 
 /**
  * The Background of a {@link Region}. A Background is an immutable object which
@@ -165,14 +166,14 @@
     /**
      * Specifies whether the Background has at least one opaque fill.
      */
-    final boolean hasOpaqueFill;
+    private final boolean hasOpaqueFill;
 
     /**
      * Package-private immutable fields referring to the opaque insets
      * of this Background.
      */
-    private final double opaqueTop, opaqueRight, opaqueBottom, opaqueLeft;
-    final boolean hasPercentageBasedOpaqueInsets;
+    private final double opaqueFillTop, opaqueFillRight, opaqueFillBottom, opaqueFillLeft;
+    final boolean hasPercentageBasedOpaqueFills;
 
     /**
      * The cached hash code computation for the Background. One very big
@@ -286,25 +287,9 @@
                     }
                 }
             }
-            this.fills = new UnmodifiableArrayList<BackgroundFill>(noNulls, size);
+            this.fills = new UnmodifiableArrayList<>(noNulls, size);
         }
 
-        hasOpaqueFill = opaqueFill;
-        if (hasPercentOpaqueInsets) {
-            opaqueTop = Double.NaN;
-            opaqueRight = Double.NaN;
-            opaqueBottom = Double.NaN;
-            opaqueLeft = Double.NaN;
-        } else {
-            double[] trbl = new double[4];
-            computeOpaqueInsets(1, 1, true, trbl);
-            opaqueTop = trbl[0];
-            opaqueRight = trbl[1];
-            opaqueBottom = trbl[2];
-            opaqueLeft = trbl[3];
-        }
-        hasPercentageBasedOpaqueInsets = hasPercentOpaqueInsets;
-
         // This ensures that we either have outsets of 0, if all the insets were positive,
         // or a value greater than zero if they were negative.
         outsets = new Insets(
@@ -324,9 +309,25 @@
                 final BackgroundImage image = images[i];
                 if (image != null) noNulls[size++] = image;
             }
-            this.images = new UnmodifiableArrayList<BackgroundImage>(noNulls, size);
+            this.images = new UnmodifiableArrayList<>(noNulls, size);
         }
 
+        hasOpaqueFill = opaqueFill;
+        if (hasPercentOpaqueInsets) {
+            opaqueFillTop = Double.NaN;
+            opaqueFillRight = Double.NaN;
+            opaqueFillBottom = Double.NaN;
+            opaqueFillLeft = Double.NaN;
+        } else {
+            double[] trbl = new double[4];
+            computeOpaqueInsets(1, 1, true, trbl);
+            opaqueFillTop = trbl[0];
+            opaqueFillRight = trbl[1];
+            opaqueFillBottom = trbl[2];
+            opaqueFillLeft = trbl[3];
+        }
+        hasPercentageBasedOpaqueFills = hasPercentOpaqueInsets;
+
         // Pre-compute the hash code. NOTE: all variables are prefixed with "this" so that we
         // do not accidentally compute the hash based on the constructor arguments rather than
         // based on the fields themselves!
@@ -359,117 +360,222 @@
      * computeOpaqueInsets method with "firstTime" set to false, such that if we have
      * percentage based insets, then we will bail early.
      *
+     * This method takes into account both fills and images. Because images can be
+     * lazy loaded, we cannot pre-compute a bunch of things in the constructor for images
+     * the way we can with fills. Instead, each time the method is called, we have to
+     * inspect the images. However, we do have fast paths for cases where fills are used
+     * and not images.
+     *
      * @param width        The width of the region
      * @param height       The height of the region
      * @param firstTime    Whether this is being called from the constructor
      * @param trbl         A four-element array of doubles in order: top, right, bottom, left.
      */
     private void computeOpaqueInsets(double width, double height, boolean firstTime, double[] trbl) {
-        // If during object construction we determined that there are no opaque
-        // fills, then we will simple return the "I don't know" answer for
-        // the opaque insets.
-        if (!hasOpaqueFill) {
-            trbl[0] = Double.NaN;
-            trbl[1] = Double.NaN;
-            trbl[2] = Double.NaN;
-            trbl[3] = Double.NaN;
-            return;
+        double opaqueRegionTop = Double.NaN,
+               opaqueRegionRight = Double.NaN,
+               opaqueRegionBottom = Double.NaN,
+               opaqueRegionLeft = Double.NaN;
+
+        // If during object construction we determined that there is an opaque fill, then we need
+        // to visit the fills and figure out which ones contribute to the opaque insets
+        if (hasOpaqueFill) {
+            // If during construction time we determined that none of the fills had a percentage based
+            // opaque inset, then we can just use the pre-computed values. This is worth doing since
+            // at this time all CSS based radii for BackgroundFills are literal values!
+            if (!firstTime && !hasPercentageBasedOpaqueFills) {
+                opaqueRegionTop = opaqueFillTop;
+                opaqueRegionRight = opaqueFillRight;
+                opaqueRegionBottom = opaqueFillBottom;
+                opaqueRegionLeft = opaqueFillLeft;
+            } else {
+                // NOTE: We know at this point that there is an opaque fill, and that at least one
+                // of them uses a percentage for at least one corner radius. Iterate over each
+                // BackgroundFill. If the fill is opaque, then we will compute the largest rectangle
+                // which will fit within its opaque area, taking the corner radii into account.
+                // Initialize them to the "I Don't Know" answer.
+
+                for (int i=0, max=fills.size(); i<max; i++) {
+                    final BackgroundFill fill = fills.get(i);
+                    final Insets fillInsets = fill.getInsets();
+                    final double fillTop = fillInsets.getTop();
+                    final double fillRight = fillInsets.getRight();
+                    final double fillBottom = fillInsets.getBottom();
+                    final double fillLeft = fillInsets.getLeft();
+
+                    if (fill.fill.isOpaque()) {
+                        // Some possible configurations:
+                        //     (a) rect1 is completely contained by rect2
+                        //     (b) rect2 is completely contained by rect1
+                        //     (c) rect1 is the same height as rect 2 and they overlap on the left or right
+                        //     (d) rect1 is the same width as rect 2 and they overlap on the top or bottom
+                        //     (e) they are disjoint or overlap in an unsupported manner.
+                        final CornerRadii radii = fill.getRadii();
+                        final double topLeftHorizontalRadius = radii.isTopLeftHorizontalRadiusAsPercentage() ?
+                                width * radii.getTopLeftHorizontalRadius() : radii.getTopLeftHorizontalRadius();
+                        final double topLeftVerticalRadius = radii.isTopLeftVerticalRadiusAsPercentage() ?
+                                height * radii.getTopLeftVerticalRadius() : radii.getTopLeftVerticalRadius();
+                        final double topRightVerticalRadius = radii.isTopRightVerticalRadiusAsPercentage() ?
+                                height * radii.getTopRightVerticalRadius() : radii.getTopRightVerticalRadius();
+                        final double topRightHorizontalRadius = radii.isTopRightHorizontalRadiusAsPercentage() ?
+                                width * radii.getTopRightHorizontalRadius() : radii.getTopRightHorizontalRadius();
+                        final double bottomRightHorizontalRadius = radii.isBottomRightHorizontalRadiusAsPercentage() ?
+                                width * radii.getBottomRightHorizontalRadius() : radii.getBottomRightHorizontalRadius();
+                        final double bottomRightVerticalRadius = radii.isBottomRightVerticalRadiusAsPercentage() ?
+                                height * radii.getBottomRightVerticalRadius() : radii.getBottomRightVerticalRadius();
+                        final double bottomLeftVerticalRadius = radii.isBottomLeftVerticalRadiusAsPercentage() ?
+                                height * radii.getBottomLeftVerticalRadius() : radii.getBottomLeftVerticalRadius();
+                        final double bottomLeftHorizontalRadius = radii.isBottomLeftHorizontalRadiusAsPercentage() ?
+                                width * radii.getBottomLeftHorizontalRadius() : radii.getBottomLeftHorizontalRadius();
+
+                        final double t = fillTop + (Math.max(topLeftVerticalRadius, topRightVerticalRadius) / 2);
+                        final double r = fillRight + (Math.max(topRightHorizontalRadius, bottomRightHorizontalRadius) / 2);
+                        final double b = fillBottom + (Math.max(bottomLeftVerticalRadius, bottomRightVerticalRadius) / 2);
+                        final double l = fillLeft + (Math.max(topLeftHorizontalRadius, bottomLeftHorizontalRadius) / 2);
+                        if (Double.isNaN(opaqueRegionTop)) {
+                            // This only happens for the first opaque fill we encounter
+                            opaqueRegionTop = t;
+                            opaqueRegionRight = r;
+                            opaqueRegionBottom = b;
+                            opaqueRegionLeft = l;
+                        } else {
+                            final boolean largerTop = t >= opaqueRegionTop;
+                            final boolean largerRight = r >= opaqueRegionRight;
+                            final boolean largerBottom = b >= opaqueRegionBottom;
+                            final boolean largerLeft = l >= opaqueRegionLeft;
+                            if (largerTop && largerRight && largerBottom && largerLeft) {
+                                // The new fill is completely contained within the existing rect, so no change
+                                continue;
+                            } else if (!largerTop && !largerRight && !largerBottom && !largerLeft) {
+                                // The new fill completely contains the existing rect, so use these
+                                // new values for our opaque region
+                                opaqueRegionTop = fillTop;
+                                opaqueRegionRight = fillRight;
+                                opaqueRegionBottom = fillBottom;
+                                opaqueRegionLeft = fillLeft;
+                            } else if (l == opaqueRegionLeft && r == opaqueRegionRight) {
+                                // The left and right insets are the same between the two rects, so just pick
+                                // the smallest top and bottom
+                                opaqueRegionTop = Math.min(t, opaqueRegionTop);
+                                opaqueRegionBottom = Math.min(b, opaqueRegionBottom);
+                            } else if (t == opaqueRegionTop && b == opaqueRegionBottom) {
+                                // The top and bottom are the same between the two rects so just pick
+                                // the smallest left and right
+                                opaqueRegionLeft = Math.min(l, opaqueRegionLeft);
+                                opaqueRegionRight = Math.min(r, opaqueRegionRight);
+                            } else {
+                                // They are disjoint or overlap in some other manner. So we will just
+                                // ignore this region.
+                                continue;
+                            }
+                        }
+                    }
+                }
+            }
         }
 
-        // If during construction time we determined that none of the fills had a percentage based
-        // opaque inset, then we can return the pre-computed values. This is worth doing since
-        // at this time all CSS based radii for BackgroundFills are literal values!
-        if (!firstTime && !hasPercentageBasedOpaqueInsets) {
-            trbl[0] = opaqueTop;
-            trbl[1] = opaqueRight;
-            trbl[2] = opaqueBottom;
-            trbl[3] = opaqueLeft;
-            return;
-        }
+        // Check the background images. Since the image of a BackgroundImage might load asynchronously
+        // and since we must inspect the image to check for opacity, we just have to visit all the
+        // images each time this method is called rather than pre-computing results. With some work
+        // we could end up caching the result eventually.
+        final Toolkit.ImageAccessor acc = Toolkit.getImageAccessor();
+        for (BackgroundImage bi : images) {
+            if (bi.opaque == null) {
+                // If the image is not yet loaded, just skip it
+                final com.sun.prism.Image platformImage = (com.sun.prism.Image) acc.getImageProperty(bi.image).get();
+                if (platformImage == null) continue;
 
-        // NOTE: We know at this point that there is an opaque fill, and that at least one
-        // of them uses a percentage for at least one corner radius. Iterate over each
-        // BackgroundFill. If the fill is opaque, then we will compute the largest rectangle
-        // which will fit within its opaque area, taking the corner radii into account.
-        // Initialize them to the "I Don't Know" answer.
-        double opaqueRegionLeft = Double.NaN,
-                opaqueRegionTop = Double.NaN,
-                opaqueRegionRight = Double.NaN,
-                opaqueRegionBottom = Double.NaN;
+                // The image has been loaded, so update the opaque flag
+                assert platformImage != null;
+                bi.opaque = platformImage.isOpaque();
+            }
 
-        for (int i=0, max=fills.size(); i<max; i++) {
-            final BackgroundFill fill = fills.get(i);
-            final Insets fillInsets = fill.getInsets();
-            final double fillTop = fillInsets.getTop();
-            final double fillRight = fillInsets.getRight();
-            final double fillBottom = fillInsets.getBottom();
-            final double fillLeft = fillInsets.getLeft();
+            // At this point we know that we're processing an image which has already been resolved
+            // and we know whether it is opaque or not. Of course, we only care about processing
+            // opaque images.
+            if (bi.opaque) {
+                if (bi.size.cover ||
+                        (bi.size.height == BackgroundSize.AUTO && bi.size.width == BackgroundSize.AUTO &&
+                        bi.size.widthAsPercentage && bi.size.heightAsPercentage)) {
+                    // If the size mode is "cover" or AUTO, AUTO, and percentage based, then we're done -- we can simply
+                    // accumulate insets of "0"
+                    opaqueRegionTop = Double.isNaN(opaqueRegionTop) ? 0 : Math.min(0, opaqueRegionTop);
+                    opaqueRegionRight = Double.isNaN(opaqueRegionRight) ? 0 : Math.min(0, opaqueRegionRight);
+                    opaqueRegionBottom = Double.isNaN(opaqueRegionBottom) ? 0 : Math.min(0, opaqueRegionBottom);
+                    opaqueRegionLeft = Double.isNaN(opaqueRegionLeft) ? 0 : Math.min(0, opaqueRegionLeft);
+                    break;
+                } else {
+                    // Here we are taking into account all potential tiling cases including "contain". Basically,
+                    // as long as the repeat is *not* SPACE, we know that we'll be touching every pixel, and we
+                    // don't really care how big the tiles end up being. The only case where we care about the
+                    // actual tile size is in the NO_REPEAT modes.
 
-            if (fill.fill.isOpaque()) {
-                // Some possible configurations:
-                //     (a) rect1 is completely contained by rect2
-                //     (b) rect2 is completely contained by rect1
-                //     (c) rect1 is the same height as rect 2 and they overlap on the left or right
-                //     (d) rect1 is the same width as rect 2 and they overlap on the top or bottom
-                //     (e) they are disjoint or overlap in an unsupported manner.
-                final CornerRadii radii = fill.getRadii();
-                final double topLeftHorizontalRadius = radii.isTopLeftHorizontalRadiusAsPercentage() ?
-                        width * radii.getTopLeftHorizontalRadius() : radii.getTopLeftHorizontalRadius();
-                final double topLeftVerticalRadius = radii.isTopLeftVerticalRadiusAsPercentage() ?
-                        height * radii.getTopLeftVerticalRadius() : radii.getTopLeftVerticalRadius();
-                final double topRightVerticalRadius = radii.isTopRightVerticalRadiusAsPercentage() ?
-                        height * radii.getTopRightVerticalRadius() : radii.getTopRightVerticalRadius();
-                final double topRightHorizontalRadius = radii.isTopRightHorizontalRadiusAsPercentage() ?
-                        width * radii.getTopRightHorizontalRadius() : radii.getTopRightHorizontalRadius();
-                final double bottomRightHorizontalRadius = radii.isBottomRightHorizontalRadiusAsPercentage() ?
-                        width * radii.getBottomRightHorizontalRadius() : radii.getBottomRightHorizontalRadius();
-                final double bottomRightVerticalRadius = radii.isBottomRightVerticalRadiusAsPercentage() ?
-                        height * radii.getBottomRightVerticalRadius() : radii.getBottomRightVerticalRadius();
-                final double bottomLeftVerticalRadius = radii.isBottomLeftVerticalRadiusAsPercentage() ?
-                        height * radii.getBottomLeftVerticalRadius() : radii.getBottomLeftVerticalRadius();
-                final double bottomLeftHorizontalRadius = radii.isBottomLeftHorizontalRadiusAsPercentage() ?
-                        width * radii.getBottomLeftHorizontalRadius() : radii.getBottomLeftHorizontalRadius();
-
-                final double t = fillTop + (Math.max(topLeftVerticalRadius, topRightVerticalRadius) / 2);
-                final double r = fillRight + (Math.max(topRightHorizontalRadius, bottomRightHorizontalRadius) / 2);
-                final double b = fillBottom + (Math.max(bottomLeftVerticalRadius, bottomRightVerticalRadius) / 2);
-                final double l = fillLeft + (Math.max(topLeftHorizontalRadius, bottomLeftHorizontalRadius) / 2);
-                if (Double.isNaN(opaqueRegionTop)) {
-                    // This only happens for the first opaque fill we encounter
-                    opaqueRegionTop = t;
-                    opaqueRegionRight = r;
-                    opaqueRegionBottom = b;
-                    opaqueRegionLeft = l;
-                } else {
-                    final boolean largerTop = t >= opaqueRegionTop;
-                    final boolean largerRight = r >= opaqueRegionRight;
-                    final boolean largerBottom = b >= opaqueRegionBottom;
-                    final boolean largerLeft = l >= opaqueRegionLeft;
-                    if (largerTop && largerRight && largerBottom && largerLeft) {
-                        // The new fill is completely contained within the existing rect, so no change
-                        continue;
-                    } else if (!largerTop && !largerRight && !largerBottom && !largerLeft) {
-                        // The new fill completely contains the existing rect, so use these
-                        // new values for our opaque region
-                        opaqueRegionTop = fillTop;
-                        opaqueRegionRight = fillRight;
-                        opaqueRegionBottom = fillBottom;
-                        opaqueRegionLeft = fillLeft;
-                    } else if (l == opaqueRegionLeft && r == opaqueRegionRight) {
-                        // The left and right insets are the same between the two rects, so just pick
-                        // the smallest top and bottom
-                        opaqueRegionTop = Math.min(t, opaqueRegionTop);
-                        opaqueRegionBottom = Math.min(b, opaqueRegionBottom);
-                    } else if (t == opaqueRegionTop && b == opaqueRegionBottom) {
-                        // The top and bottom are the same between the two rects so just pick
-                        // the smallest left and right
-                        opaqueRegionLeft = Math.min(l, opaqueRegionLeft);
-                        opaqueRegionRight = Math.min(r, opaqueRegionRight);
-                    } else {
-                        // They are disjoint or overlap in some other manner. So we will just
-                        // ignore this region.
+                    // If the repeatX or repeatY includes "SPACE" Then we bail, because we can't be happy about
+                    // spaces strewn about within the region.
+                    if (bi.repeatX == BackgroundRepeat.SPACE || bi.repeatY == BackgroundRepeat.SPACE) {
+                        bi.opaque = false; // We'll treat it as false in the future
                         continue;
                     }
+
+                    // If the repeatX and repeatY are "REPEAT" and/or "ROUND" (any combination thereof) then
+                    // we know all pixels within the region width / height are being touched, so we can just
+                    // set the opaqueRegion variables and we're done.
+                    final boolean filledX = bi.repeatX == BackgroundRepeat.REPEAT || bi.repeatX == BackgroundRepeat.ROUND;
+                    final boolean filledY = bi.repeatY == BackgroundRepeat.REPEAT || bi.repeatY == BackgroundRepeat.ROUND;
+                    if (filledX && filledY) {
+                        opaqueRegionTop = Double.isNaN(opaqueRegionTop) ? 0 : Math.min(0, opaqueRegionTop);
+                        opaqueRegionRight = Double.isNaN(opaqueRegionRight) ? 0 : Math.min(0, opaqueRegionRight);
+                        opaqueRegionBottom = Double.isNaN(opaqueRegionBottom) ? 0 : Math.min(0, opaqueRegionBottom);
+                        opaqueRegionLeft = Double.isNaN(opaqueRegionLeft) ? 0 : Math.min(0, opaqueRegionLeft);
+                        break;
+                    }
+
+                    // We know that one or the other dimension is not filled, so we have to compute the right
+                    // width / height. This is basically a big copy/paste from NGRegion! Blah!
+                    final double w = bi.size.widthAsPercentage ? bi.size.width * width : bi.size.width;
+                    final double h = bi.size.heightAsPercentage ? bi.size.height * height : bi.size.height;
+                    final double imgUnscaledWidth = bi.image.getWidth();
+                    final double imgUnscaledHeight = bi.image.getHeight();
+
+                    // Now figure out the width and height of each tile to be drawn. The actual image
+                    // dimensions may be one thing, but we need to figure out what the size of the image
+                    // in the destination is going to be.
+                    final double tileWidth, tileHeight;
+                    if (bi.size.contain) {
+                        // In the case of "contain", we compute the destination size based on the largest
+                        // possible scale such that the aspect ratio is maintained, yet one side of the
+                        // region is completely filled.
+                        final double scaleX = width / imgUnscaledWidth;
+                        final double scaleY = height / imgUnscaledHeight;
+                        final double scale = Math.min(scaleX, scaleY);
+                        tileWidth = Math.ceil(scale * imgUnscaledWidth);
+                        tileHeight = Math.ceil(scale * imgUnscaledHeight);
+                    } else if (bi.size.width >= 0 && bi.size.height >= 0) {
+                        // The width and height have been expressly defined. Note that AUTO is -1,
+                        // and all other negative values are disallowed, so by checking >= 0, we
+                        // are essentially saying "if neither is AUTO"
+                        tileWidth = w;
+                        tileHeight = h;
+                    } else if (w >= 0) {
+                        // In this case, the width is specified, but the height is AUTO
+                        tileWidth = w;
+                        final double scale = tileWidth / imgUnscaledWidth;
+                        tileHeight = imgUnscaledHeight * scale;
+                    } else if (h >= 0) {
+                        // Here the height is specified and the width is AUTO
+                        tileHeight = h;
+                        final double scale = tileHeight / imgUnscaledHeight;
+                        tileWidth = imgUnscaledWidth * scale;
+                    } else {
+                        // Both are auto.
+                        tileWidth = imgUnscaledWidth;
+                        tileHeight = imgUnscaledHeight;
+                    }
+
+                    opaqueRegionTop = Double.isNaN(opaqueRegionTop) ? 0 : Math.min(0, opaqueRegionTop);
+                    opaqueRegionRight = Double.isNaN(opaqueRegionRight) ? (width - tileWidth) : Math.min(width - tileWidth, opaqueRegionRight);
+                    opaqueRegionBottom = Double.isNaN(opaqueRegionBottom) ? (height - tileHeight) : Math.min(height - tileHeight, opaqueRegionBottom);
+                    opaqueRegionLeft = Double.isNaN(opaqueRegionLeft) ? 0 : Math.min(0, opaqueRegionLeft);
                 }
             }
         }
--- a/modules/graphics/src/main/java/javafx/scene/layout/BackgroundImage.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/javafx/scene/layout/BackgroundImage.java	Tue Aug 27 09:36:40 2013 -0700
@@ -85,6 +85,14 @@
     final BackgroundSize size;
 
     /**
+     * The Background will cache here whether this BackgroundImage is opaque. If this
+     * value is null, then it means we don't yet know. If it is non null, then we
+     * know for certain it either is, or is not, opaque. Opaque in this case means
+     * that the BackgroundImage's image is opaque.
+     */
+    Boolean opaque = null;
+
+    /**
      * A cached hash code for faster secondary usage. It is expected
      * that BackgroundImage will be pulled from a cache in many cases.
      */
--- a/modules/graphics/src/main/java/javafx/scene/layout/Region.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/javafx/scene/layout/Region.java	Tue Aug 27 09:36:40 2013 -0700
@@ -25,6 +25,34 @@
 
 package javafx.scene.layout;
 
+import javafx.beans.InvalidationListener;
+import javafx.beans.property.BooleanProperty;
+import javafx.beans.property.DoubleProperty;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.ReadOnlyDoubleProperty;
+import javafx.beans.property.ReadOnlyDoubleWrapper;
+import javafx.beans.property.ReadOnlyObjectProperty;
+import javafx.beans.value.ChangeListener;
+import javafx.collections.ObservableList;
+import javafx.css.CssMetaData;
+import javafx.css.Styleable;
+import javafx.css.StyleableBooleanProperty;
+import javafx.css.StyleableDoubleProperty;
+import javafx.css.StyleableObjectProperty;
+import javafx.css.StyleableProperty;
+import javafx.geometry.BoundingBox;
+import javafx.geometry.Bounds;
+import javafx.geometry.HPos;
+import javafx.geometry.Insets;
+import javafx.geometry.Orientation;
+import javafx.geometry.VPos;
+import javafx.scene.Node;
+import javafx.scene.Parent;
+import javafx.scene.shape.Shape;
+import javafx.util.Callback;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import com.sun.javafx.Logging;
 import com.sun.javafx.TempState;
 import com.sun.javafx.binding.ExpressionHelper;
@@ -40,23 +68,9 @@
 import com.sun.javafx.scene.input.PickResultChooser;
 import com.sun.javafx.sg.prism.NGNode;
 import com.sun.javafx.sg.prism.NGRegion;
-import javafx.beans.InvalidationListener;
-import javafx.beans.property.*;
-import javafx.beans.value.ChangeListener;
-import javafx.collections.ObservableList;
-import javafx.css.*;
-import javafx.geometry.*;
-import javafx.scene.Node;
-import javafx.scene.Parent;
-import javafx.scene.shape.Shape;
-import javafx.util.Callback;
 import sun.util.logging.PlatformLogger;
 import sun.util.logging.PlatformLogger.Level;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
 /**
  * Region is the base class for all JavaFX Node-based UI Controls, and all layout containers.
  * It is a resizable Parent node which can be styled from CSS. It can have multiple backgrounds
@@ -2046,6 +2060,10 @@
 
     /** @treatAsPrivate */
     @Override public void impl_updatePeer() {
+        // TODO I think we have a bug, where if you create a Region with an Image that hasn't
+        // been loaded, we have no listeners on that image so as to cause a pulse & repaint
+        // to happen once the image is loaded. We just assume the image has been loaded
+        // (since when the image is created using new Image(url) or CSS it happens eagerly).
         super.impl_updatePeer();
         if (_shape != null) _shape.impl_syncPeer();
         NGRegion pg = impl_getPeer();
@@ -2073,12 +2091,23 @@
             pg.updateBorder(getBorder());
         }
 
+        // TODO given the note above, this *must* be called when an image which makes up the
+        // background images and border images changes (is loaded) if it was being loaded asynchronously
+        // Also note, one day we can add support for automatic opaque insets determination for border images.
+        // However right now it is impractical because the image pixel format is almost undoubtedly going
+        // to have alpha, and so without inspecting the source image's actual pixels for the filled center
+        // we can't automatically determine whether the interior is filled.
         if (sizeChanged || backgroundChanged || shapeChanged) {
-            // TODO Make sure there is a test ensuring that stroke borders do not contribute to insets or opaque insets
-            // If the background is determined by a shape, then we don't care (for now) what the opaque insets
-            // of the Background are. If the developer specified opaque insets, we will use them, otherwise
+            // These are the opaque insets, as specified by the developer in code or CSS. If null,
+            // then we must compute the opaque insets. If not null, then we will still compute the
+            // opaque insets and combine them with these insets, as appropriate. We do ignore these
+            // developer specified insets in cases where we know without a doubt that the developer
+            // gave us bad data.
+            final Insets i = getOpaqueInsets();
+
+            // If the background is determined by a shape, then we don't attempt to calculate the
+            // opaque insets. If the developer specified opaque insets, we will use them, otherwise
             // we will make sure the opaque insets are cleared
-            final Insets i = getOpaqueInsets();
             if (_shape != null) {
                 if (i != null) {
                     pg.setOpaqueInsets((float) i.getTop(), (float) i.getRight(),
@@ -2086,25 +2115,36 @@
                 } else {
                     pg.setOpaqueInsets(Float.NaN, Float.NaN, Float.NaN, Float.NaN);
                 }
-            } else if (bg == null || bg.isEmpty() || !bg.hasOpaqueFill) {
-                // If the background is null or empty or has no opaque fills, then we will forbear
-                // computing the opaque insets, and just send null down.
-                pg.setOpaqueInsets(Float.NaN, Float.NaN, Float.NaN, Float.NaN);
-            } else if (i == null) {
-                // There are no opaqueInsets specified by the developer (the most common case), so
-                // I will have to compute them.
-                // TODO If I could determine whether an Image were opaque, I could also compute
-                // the opaqueInsets for a BackgroundImage and BorderImage.
-                final double[] trbl = new double[4];
-                bg.computeOpaqueInsets(getWidth(), getHeight(), trbl);
-                pg.setOpaqueInsets((float) trbl[0], (float) trbl[1], (float) trbl[2], (float) trbl[3]);
             } else {
-                // TODO For now, I'm just going to honor the opaqueInsets. Really I would want
-                // to check to see if the computed opaqueTop, right, etc on the Background is
-                // broader than the supplied opaque insets and adjust accordingly, but for now
-                // I won't bother.
-                pg.setOpaqueInsets((float) i.getTop(), (float) i.getRight(),
-                                   (float) i.getBottom(), (float) i.getLeft());
+                // This is a rectangle (not shape) region. The opaque insets must be calculated,
+                // even if the developer has supplied their own opaque insets. The first (and cheapest)
+                // check is whether the region has any backgrounds at all. If not, then
+                // we will ignore the developer supplied insets because they are clearly wrong.
+                if (bg == null || bg.isEmpty()) {
+                    pg.setOpaqueInsets(Float.NaN, Float.NaN, Float.NaN, Float.NaN);
+                } else {
+                    // There is a background, so it is conceivable that there are
+                    // opaque insets. From this point on, we have to honor the developer's supplied
+                    // insets, only expanding them if we know for certain the opaque insets are
+                    // bigger than what was supplied by the developer. Start by defining our initial
+                    // values for top, right, bottom, and left. If the developer supplied us
+                    // insets, use those. Otherwise initialize to NaN. Note that the developer may
+                    // also have given us NaN values (so we'd have to check for these anyway). We use
+                    // NaN to mean "not defined".
+                    final double[] trbl = new double[4];
+                    bg.computeOpaqueInsets(getWidth(), getHeight(), trbl);
+
+                    if (i != null) {
+                        trbl[0] = Double.isNaN(trbl[0]) ? i.getTop() : Double.isNaN(i.getTop()) ? trbl[0] : Math.min(trbl[0], i.getTop());
+                        trbl[1] = Double.isNaN(trbl[1]) ? i.getRight() : Double.isNaN(i.getRight()) ? trbl[1] : Math.min(trbl[1], i.getRight());
+                        trbl[2] = Double.isNaN(trbl[2]) ? i.getBottom() : Double.isNaN(i.getBottom()) ? trbl[2] : Math.min(trbl[2], i.getBottom());
+                        trbl[3] = Double.isNaN(trbl[3]) ? i.getLeft() : Double.isNaN(i.getLeft()) ? trbl[3] : Math.min(trbl[3], i.getLeft());
+                    }
+
+                    // Now set the insets onto the peer. Passing NaN here is perfectly
+                    // acceptable (even encouraged, to mean "unknown" or "disabled").
+                    pg.setOpaqueInsets((float) trbl[0], (float) trbl[1], (float) trbl[2], (float) trbl[3]);
+                }
             }
         }
     }
--- a/modules/graphics/src/main/java/javafx/scene/paint/ImagePattern.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/javafx/scene/paint/ImagePattern.java	Tue Aug 27 09:36:40 2013 -0700
@@ -25,9 +25,9 @@
 
 package javafx.scene.paint;
 
+import javafx.scene.image.Image;
 import com.sun.javafx.beans.event.AbstractNotifyListener;
 import com.sun.javafx.tk.Toolkit;
-import javafx.scene.image.Image;
 
 /**
  * <p>The {@code ImagePattern} class fills a shape with an image pattern. The
@@ -211,9 +211,11 @@
     }
 
     @Override public final boolean isOpaque() {
-        // RT-24827: isOpaque should return true if the image doesn't have an alpha.
-        // We haven't implemented this support yet, but should!
-        return false;
+        // We only ever have Prism as our painting system these days, so we can just
+        // cast this platformPaint to a prism paint type and check for isOpaque.
+        // It would be better to change the type on platformPaint accordingly and
+        // ditch the cast.
+        return ((com.sun.prism.paint.ImagePattern)acc_getPlatformPaint()).isOpaque();
     }
 
     private Object platformPaint;
@@ -286,6 +288,7 @@
     @Override Object acc_getPlatformPaint() {
         if (acc_isMutable() || platformPaint == null) {
             platformPaint = Toolkit.getToolkit().getPaint(this);
+            assert platformPaint != null;
         }
         return platformPaint;
     }
--- a/modules/graphics/src/main/java/javafx/stage/PopupWindow.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/javafx/stage/PopupWindow.java	Tue Aug 27 09:36:40 2013 -0700
@@ -244,7 +244,22 @@
      * @defaultValue false
      */
     private BooleanProperty autoHide =
-            new SimpleBooleanProperty(this, "autoHide");
+            new BooleanPropertyBase() {
+                @Override
+                protected void invalidated() {
+                    handleAutohideActivation(isShowing(), get());
+                }
+
+                @Override
+                public Object getBean() {
+                    return PopupWindow.this;
+                }
+
+                @Override
+                public String getName() {
+                    return "autoHide";
+                }
+            };
     public final void setAutoHide(boolean value) { autoHide.set(value); }
     public final boolean isAutoHide() { return autoHide.get(); }
     public final BooleanProperty autoHideProperty() { return autoHide; }
@@ -460,13 +475,13 @@
             bindOwnerFocusedProperty(ownerWindowValue);
             setFocused(ownerWindowValue.isFocused());
             handleAutofixActivation(true, isAutoFix());
-            rootWindow.increaseFocusGrabCounter();
+            handleAutohideActivation(true, isAutoHide());
         } else {
             stopMonitorOwnerEvents(ownerWindowValue);
             unbindOwnerFocusedProperty(ownerWindowValue);
             setFocused(false);
             handleAutofixActivation(false, isAutoFix());
-            rootWindow.decreaseFocusGrabCounter();
+            handleAutohideActivation(false, isAutoHide());
             rootWindow = null;
         }
 
@@ -663,6 +678,21 @@
         }
     }
 
+    private boolean autohideActive;
+    private void handleAutohideActivation(final boolean visible,
+                                          final boolean autohide) {
+        final boolean newAutohideActive = visible && autohide;
+        if (autohideActive != newAutohideActive) {
+            // assert rootWindow != null;
+            autohideActive = newAutohideActive;
+            if (newAutohideActive) {
+                rootWindow.increaseFocusGrabCounter();
+            } else {
+                rootWindow.decreaseFocusGrabCounter();
+            }
+        }
+    }
+
     private void validateOwnerWindow(final Window owner) {
         if (owner == null) {
             throw new NullPointerException("Owner window must not be null");
--- a/modules/graphics/src/main/java/javafx/stage/Window.java	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/java/javafx/stage/Window.java	Tue Aug 27 09:36:40 2013 -0700
@@ -179,6 +179,11 @@
     }
 
     /**
+     * Indicates if a user requested the window to be sized to match the scene
+     * size.
+     */
+    private boolean sizeToScene = false;
+    /**
      * Set the width and height of this Window to match the size of the content
      * of this Window's Scene.
      */
@@ -186,6 +191,9 @@
         if (getScene() != null && impl_peer != null) {
             getScene().impl_preferredSize();
             adjustSize(false);
+        } else {
+            // Remember the request to reapply it later if needed
+            sizeToScene = true;
         }
     }
 
@@ -782,6 +790,18 @@
                 tk.requestNextPulse();
             }
             impl_visibleChanged(newVisible);
+
+            if (sizeToScene) {
+                if (newVisible) {
+                    // Now that the visibleChanged has completed, the insets of the window
+                    // might have changed (e.g. due to setResizable(false)). Reapply the
+                    // sizeToScene() request if needed to account for the new insets.
+                    sizeToScene();
+                }
+
+                // Reset the flag unconditionally upon visibility changes
+                sizeToScene = false;
+            }
         }
 
         @Override
--- a/modules/graphics/src/main/native-font/directwrite.cpp	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/native-font/directwrite.cpp	Tue Aug 27 09:36:40 2013 -0700
@@ -204,6 +204,7 @@
     lpStruct->fontFace = (IDWriteFontFace *)env->GetLongField(lpObject, DWRITE_GLYPH_RUNFc.fontFace);
     lpStruct->fontEmSize = env->GetFloatField(lpObject, DWRITE_GLYPH_RUNFc.fontEmSize);
     ((jshort*)lpStruct->glyphIndices)[0] = env->GetShortField(lpObject, DWRITE_GLYPH_RUNFc.glyphIndices);
+    ((float*)lpStruct->glyphAdvances)[0] = env->GetShortField(lpObject, DWRITE_GLYPH_RUNFc.glyphAdvances);
     ((float)lpStruct->glyphOffsets[0].advanceOffset) = env->GetFloatField(lpObject, DWRITE_GLYPH_RUNFc.advanceOffset);
     ((float)lpStruct->glyphOffsets[0].ascenderOffset) = env->GetFloatField(lpObject, DWRITE_GLYPH_RUNFc.ascenderOffset);
     lpStruct->isSideways = env->GetBooleanField(lpObject, DWRITE_GLYPH_RUNFc.isSideways);
--- a/modules/graphics/src/main/native-glass/lens/LensApplication.c	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/native-glass/lens/LensApplication.c	Tue Aug 27 09:36:40 2013 -0700
@@ -450,8 +450,10 @@
         }
 
     } else {
-        GLASS_LOG_FINE("Window %d[%p] is disabled - sending FOCUS_DISABLED event",
-                       window->id, window);
+        GLASS_LOG_FINE("Window %d[%p] is disabled, can't send event %d - "
+                       "sending FOCUS_DISABLED event",
+                       window->id, window, eventType);
+
         glass_application_notifyWindowEvent(env,
                                             window,
                                             com_sun_glass_events_WindowEvent_FOCUS_DISABLED);
--- a/modules/graphics/src/main/native-glass/lens/LensView.c	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/native-glass/lens/LensView.c	Tue Aug 27 09:36:40 2013 -0700
@@ -308,6 +308,11 @@
     NativeWindow parent = (NativeWindow) jlong_to_ptr(nativeWindowPtr);
     // window can be NULL if being removed
 
-    GLASS_LOG_FINE("set parent of view %p to window %p old window %p", view, parent, view->parent);
+    GLASS_LOG_FINE("set parent of view %p to window %d[%p] old window %d[%p]", 
+                   view, 
+                   parent?parent->id:-1,
+                   parent,
+                   view->parent?view->parent->id:-1,
+                   view->parent);
     glass_view_setParent(env, parent, view);
 }
--- a/modules/graphics/src/main/native-glass/lens/LensWindow.c	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/native-glass/lens/LensWindow.c	Tue Aug 27 09:36:40 2013 -0700
@@ -131,8 +131,11 @@
 
         window->lensWindow = (*env)->NewGlobalRef(env, jWindow);
 
-        GLASS_LOG_FINE("Allocated NativeWindow window = %p, owner = %p lensWindow=%p", 
-                window,owner,window->lensWindow);
+        GLASS_LOG_FINE("Allocated NativeWindow window = %p, owner = %d[%p] lensWindow=%p", 
+                       window,
+                       owner?owner->id:-1,
+                       owner,
+                       window->lensWindow);
 
         if (window->lensWindow) {
             // set the default NativeWindow values
@@ -420,7 +423,9 @@
             env, glass_NullPointerException, "Window handle is null");
     } else {
 
-        GLASS_LOG_FINE("request focus on window %p", window);
+        GLASS_LOG_FINE("request focus on window %d[%p]",
+                       window?window->id:-1,
+                       window);
         result = glass_window_requestFocus(env, window, focusEventType);
     }
 
@@ -441,8 +446,14 @@
         glass_throw_exception_by_name(
             env, glass_NullPointerException, "Window handle is null");
     } else {
-        GLASS_LOG_FINE("set focusable=%i on window %p", (int) isFocusable, window),
-        (void) glass_window_setFocusable(env, window, isFocusable);
+        GLASS_LOG_FINE("set focusable=%i on window %d[%p]", (int) isFocusable,
+                       window->id,
+                       window);
+        jboolean result = glass_window_setFocusable(env, window, isFocusable);
+        GLASS_LOG_FINE("setFocusable(window %d, %s) returned %s",
+                       window->id,
+                       isFocusable?"true":"false",
+                       result?"true":"false");
     }
 }
 
@@ -551,13 +562,11 @@
                        enabled?"true":"false",
                        window->id, window);
 
-        window->isEnabled = enabled;
-
         GLASS_LOG_FINE("glass_window_setFocusable(%s)", enabled?"true":"false");
         glass_window_setFocusable(env, window, enabled);
 
         //syntheticlly notify view for mouse exit
-        if (!enabled && window->view) {
+        if (!enabled && window->view && window == lens_wm_getMouseWindow()) {
             glass_application_notifyMouseEvent(env,
                                                window,
                                                com_sun_glass_events_MouseEvent_EXIT, 
@@ -565,6 +574,8 @@
                                                com_sun_glass_events_MouseEvent_BUTTON_NONE);
 
         }
+
+        window->isEnabled = enabled;
     }
 }
 
@@ -609,8 +620,11 @@
             env, glass_NullPointerException, "Window handle is null");
     } else {
 
-        GLASS_LOG_FINE("set window %p maximum size to %ix%i",
-                       window, width, height);
+        GLASS_LOG_FINE("set window %d[%p] maximum size to %ix%i",
+                       window->id,
+                       window,
+                       width,
+                       height);
         result = glass_window_setMaximumSize(env, window, width, height);
     }
 
@@ -677,7 +691,9 @@
             env, glass_NullPointerException, "Window handle is null");
     } else {
 
-        GLASS_LOG_FINE("grab focus on window %p", window);
+        GLASS_LOG_FINE("grab focus request on window %d[%p]",
+                       window?window->id:-1,
+                       window);
         result = glass_window_grabFocus(env, window);
     }
 
@@ -693,7 +709,9 @@
             env, glass_NullPointerException, "Window handle is null");
     } else {
 
-        GLASS_LOG_FINE("ungrab focus on window %p", window);
+        GLASS_LOG_FINE("ungrab focus request on window %d[%p]",
+                       window?window->id:-1,
+                       window);
         glass_window_ungrabFocus(env, window);
     }
 }
--- a/modules/graphics/src/main/native-glass/lens/input/udev/udevInput.c	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/native-glass/lens/input/udev/udevInput.c	Tue Aug 27 09:36:40 2013 -0700
@@ -371,7 +371,9 @@
         GLASS_LOG_SEVERE("Could not find %s", className);
     }
 
-    lens_wm_setPointerPosition(screenWidth / 2, screenHeight / 2);
+    mousePosX = screenWidth / 2;
+    mousePosY = screenHeight / 2;
+    lens_wm_setPointerPosition(mousePosX, mousePosY);
 
     glass_application_request_native_event_loop(env, &lens_input_eventLoop, NULL);
 
--- a/modules/graphics/src/main/native-glass/lens/wm/LensWindowManager.c	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/native-glass/lens/wm/LensWindowManager.c	Tue Aug 27 09:36:40 2013 -0700
@@ -523,14 +523,7 @@
     }
 
     if (!windowHasBeenUpdated) {
-        //if function got the same sizes as the current ones, it means that
-        //window have been restored.
-        //happens when swapping stages with same params, for example.
-        GLASS_LOG_FINE("Notifying window restore");
-        glass_application_notifyWindowEvent_resize(env,window,
-                                                   com_sun_glass_events_WindowEvent_RESTORE,
-                                                   window->currentBounds.width,
-                                                   window->currentBounds.height);
+        GLASS_LOG_FINE("Nothing to do");
     }
 }
 
@@ -554,18 +547,13 @@
         //lose focus and grab
         lens_wm_unsetFocusedWindow(env, window);        
     } else {
-        if (!window->owner) {
-            //window become visible, grant it the focus if not a pop-up
+        if (window->isFocusable && window->isEnabled) {
+            //window become visible, grant it the focus
             lens_wm_setFocusedWindow(env, window);
         }
+    }
 
-        GLASS_LOG_FINE("notify window it has been restored");
-        glass_application_notifyWindowEvent_resize(env,
-                                                   window,
-                                                   com_sun_glass_events_WindowEvent_RESTORE,
-                                                   window->currentBounds.width,
-                                                   window->currentBounds.height);
-    }
+    //no need to send an event to confirm window is visible
 
     return JNI_TRUE;
 }
@@ -583,38 +571,40 @@
 
 jboolean glass_window_requestFocus(JNIEnv *env, NativeWindow window, jint focusType) {
 
-    jboolean result;
+    NativeWindow focusWindow = glass_window_getFocusedWindow();
 
-    NativeWindow focusWindow;
-
-    if (lens_wm_getGrabbedWindow()) {
-        // no changing focus in a grab
-        return JNI_FALSE;
-    }
-
-    focusWindow = glass_window_getFocusedWindow();
-
+    GLASS_LOG_FINE("requestFocus on window %d[%p], event %d",
+                   window?window->id:-1,
+                   window,
+                   focusType);
+    
     if (!window) {
-        GLASS_LOG_WARNING("null window passes the glass_window_requestFocus");
+        GLASS_LOG_WARNING("requestFocus on a null window");
         return JNI_FALSE;
     }
 
     if (window == focusWindow) {
         // no change, no notification ?
-        GLASS_LOG_WARNING("Focus requested on current focus window");
+        GLASS_LOG_FINE("Focus requested on current focus window - ignore");
         return JNI_TRUE;
     }
 
     if (!window->isFocusable) {
-        GLASS_LOG_WARNING("Focus requested on isFocusable=false");
+        GLASS_LOG_WARNING("Focus requested on isFocusable=false - ignore");
         return JNI_FALSE;
     }
 
     if (!window->isEnabled) {
-        GLASS_LOG_WARNING("Focus requested on isEnabled=false");
+        GLASS_LOG_WARNING("Focus requested on isEnabled=false - ignore");
         return JNI_FALSE;
     }
 
+    if (!window->isVisible) {
+        GLASS_LOG_WARNING("Focus requested on isVisible=false - ignore");
+        return JNI_FALSE;
+    }
+
+    //this function will release the grab if someone holds it
     lens_wm_setFocusedWindow(env, window);
 
     return JNI_TRUE;
@@ -666,20 +656,30 @@
 
     if (window == lens_wm_getGrabbedWindow()) {
         //this is OK per spec
-        GLASS_LOG_FINE("RE-GRAB on %p root %p\n", window, window->root);
+        GLASS_LOG_FINE("RE-GRAB on %d[%p] root %d[%p]",
+                       window?window->id:-1,
+                       window,
+                       window->root?window->root->id:-1,
+                       window->root);
         return JNI_TRUE;
     }
     
     if (NULL == lens_wm_getGrabbedWindow() &&
             window == glass_window_getFocusedWindow()) {
         // we allow the grab, note: focus is also checked in Java.
-        GLASS_LOG_FINE("GRAB on %p root %p\n", window, window->root);
+        GLASS_LOG_FINE("GRAB on %d[%p] (root %d[%p])", 
+                       window?window->id:-1,
+                       window,
+                       window->root?window->root->id:-1,
+                       window->root);
         lens_wm_setGrabbedWindow(window);
         return JNI_TRUE;
     }
 
     // should not be able to happen
-    GLASS_LOG_FINE("ERROR NO-GRAB on %p\n", window);
+    GLASS_LOG_SEVERE("ERROR NO-GRAB on %d[%p]\n",
+                     window?window->id:-1,
+                     window);
     return JNI_FALSE;
 }
 
@@ -690,13 +690,22 @@
  */
 void glass_window_ungrabFocus(JNIEnv *env, NativeWindow window) {
 
+    NativeWindow grabbedWindow = lens_wm_getGrabbedWindow();
+
+    GLASS_LOG_FINE("ungrab request on window %i[%p], current grabbed window %i[%p]",
+                   window?window->id:-1,
+                   window,
+                   grabbedWindow?grabbedWindow->id:-1,
+                   grabbedWindow );
     if (window == NULL) {
-        GLASS_LOG_FINER("window=NULL - Nothing to do");
+        GLASS_LOG_FINE("window=NULL - Nothing to do");
         return;
     }
 
-    if (window != lens_wm_getGrabbedWindow()) {
-        GLASS_LOG_FINE("Given window is not grabbed, ignore");
+    if (window != grabbedWindow) {
+        GLASS_LOG_FINE("Window %d[%p] doesn't hold the grab, ignore",
+                       window?window->id:-1,
+                       window);
         return;
     }
 
@@ -1280,9 +1289,9 @@
              window);
 
         if (_focusedWindow) {
-
-            //Release the grab if window holds it
-            glass_window_ungrabFocus(env, window); /* function will print the result*/
+                        
+            //Release the grab if the focused window holds it
+            glass_window_ungrabFocus(env, _focusedWindow); /* function will print the result*/
 
             GLASS_LOG_FINE("Notifying window %i[%p] focus lost ",
                            _focusedWindow->id,
--- a/modules/graphics/src/main/native-glass/mac/GlassView3D.m	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/native-glass/mac/GlassView3D.m	Tue Aug 27 09:36:40 2013 -0700
@@ -235,6 +235,9 @@
     [self removeTrackingArea: self->_trackingArea];
     [self->_trackingArea release];
     self->_trackingArea = nil;
+
+    [self->nsAttrBuffer release];
+    self->nsAttrBuffer = nil;
     
     [super dealloc];
 }
@@ -750,8 +753,11 @@
 - (NSRect) firstRectForCharacterRange:(NSRange)theRange actualRange:(NSRangePointer)actualRange
 {
     IMLOG("firstRectForCharacterRange called %lu %lu", 
-            (unsigned long)theRange.location, (unsigned long)theRange.length);
-    return [self->_delegate getInputMethodCandidatePosRequest:(int)theRange.length];
+            (unsigned long)theRange.location, (unsigned long)theRange.length);    
+    NSRect result = [self->_delegate getInputMethodCandidatePosRequest:(int)theRange.length];
+    NSRect screenFrame = [[NSScreen mainScreen] frame];
+    result.origin.y = screenFrame.size.height - result.origin.y;
+    return result;
 }
 
 - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
--- a/modules/graphics/src/main/native-glass/mac/GlassViewDelegate.m	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/native-glass/mac/GlassViewDelegate.m	Tue Aug 27 09:36:40 2013 -0700
@@ -981,10 +981,7 @@
             if (n == 2) {
                 jboolean isCopy;
                 jdouble *elems = (*env)->GetDoubleArrayElements(env, theArray, &isCopy);
-                // We get the screen coordinates of the cursor, to make some room
-                // to avoid suggestion window overlapping the next symbol we
-                // create rectangle 20x20 pixels as a placeholder for the next glyph.
-                retVal = NSMakeRect((CGFloat)elems[0], (CGFloat)elems[1], 20.0, 20.0);
+                retVal = NSMakeRect((CGFloat)elems[0], (CGFloat)elems[1], 0, 0);
                 (*env)->ReleaseDoubleArrayElements(env, theArray, elems, 0);
                 (*env)->DeleteLocalRef(env, theArray);
             }
--- a/modules/graphics/src/main/native-glass/mac/GlassWindow.m	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/native-glass/mac/GlassWindow.m	Tue Aug 27 09:36:40 2013 -0700
@@ -108,6 +108,13 @@
     return self;                                                                        \
 }                                                                                       \
                                                                                         \
+- (void)dealloc                                                                         \
+{                                                                                       \
+    id window = self->gWindow;                                                          \
+    [super dealloc];                                                                    \
+    [window release];                                                                   \
+}                                                                                       \
+                                                                                        \
 - (void)close                                                                           \
 {                                                                                       \
     self->gWindow->isClosed = YES;                                                      \
@@ -930,8 +937,8 @@
         // this call will always close the window
         // without calling the windowShouldClose
         [window->nsWindow close];
-        // The nsWindow is released automatically since we don't retain it
-        // The window is released in the nsWindow -close override method
+        // The NSWindow will be automatically released after closing
+        // The GlassWindow is released in the [NSWindow dealloc] override        
     }
     GLASS_POOL_EXIT;
     GLASS_CHECK_EXCEPTION(env);
--- a/modules/graphics/src/main/native-prism-d3d/D3DContext.cc	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/native-prism-d3d/D3DContext.cc	Tue Aug 27 09:36:40 2013 -0700
@@ -385,6 +385,35 @@
 
 /*
  * Class:     com_sun_prism_d3d_D3DContext
+ * Method:    nBlit
+ * Signature: (JJJIIIIIIII)V
+ */
+JNIEXPORT void JNICALL Java_com_sun_prism_d3d_D3DContext_nBlit
+  (JNIEnv *env, jclass, jlong ctx, jlong nSrcRTT, jlong nDstRTT,
+            jint srcX0, jint srcY0, jint srcX1, jint srcY1,
+            jint dstX0, jint dstY0, jint dstX1, jint dstY1)
+{
+    TraceLn(NWT_TRACE_INFO, "D3DContext_nBlit");
+    D3DContext *pCtx = (D3DContext*) jlong_to_ptr(ctx);
+    D3DResource *srcRes = (D3DResource*) jlong_to_ptr(nSrcRTT);
+    D3DResource *dstRes = (D3DResource*) jlong_to_ptr(nDstRTT);
+    if (srcRes == NULL) {
+        TraceLn(NWT_TRACE_INFO, "   error srcRes NULL");
+        return;
+    }
+    IDirect3DSurface9 *pSrcSurface = srcRes->GetSurface();
+    if (pSrcSurface == NULL) {
+        TraceLn(NWT_TRACE_INFO, "   error pSrcSurface NULL");
+        return;
+    }
+    IDirect3DSurface9 *pDstSurface = (dstRes == NULL) ? NULL : dstRes->GetSurface();
+
+    pCtx->stretchRect(pSrcSurface, srcX0, srcY0, srcX1, srcY1,
+                      pDstSurface, dstX0, dstY0, dstX1, dstY1);
+}
+
+/*
+ * Class:     com_sun_prism_d3d_D3DContext
  * Method:    nSetMaterial
  * Signature: (JJJ)V
  */
@@ -696,6 +725,12 @@
         }
     }
     if (clearDepth) {
+        // Must ensure that there is a depth buffer before attempting to clear it
+        IDirect3DSurface9 *pCurrentDepth = NULL;
+        pd3dDevice->GetDepthStencilSurface(&pCurrentDepth);
+        clearDepth = pCurrentDepth == NULL ? FALSE : clearDepth;
+    }
+    if (clearDepth) {
         flags |= D3DCLEAR_ZBUFFER;
         // also make sure depth writes are enabled for the clear operation
         pd3dDevice->GetRenderState(D3DRS_ZWRITEENABLE, &bDE);
@@ -716,40 +751,32 @@
     return res;
 }
 
-BOOL D3DContext::IsDepthStencilBufferOk(D3DSURFACE_DESC *pTargetDesc)
+BOOL D3DContext::IsDepthStencilBufferOk(D3DSURFACE_DESC *pTargetDesc, IDirect3DSurface9 *pTargetDepth)
 {
-    IDirect3DSurface9 *pStencil;
     TraceLn(NWT_TRACE_INFO, "D3DContext::IsDepthStencilBufferOk");
+    if (pTargetDepth == NULL) { return true; } // NOP
 
-    if (SUCCEEDED(pd3dDevice->GetDepthStencilSurface(&pStencil))) {
-        D3DSURFACE_DESC descStencil;
-        pStencil->GetDesc(&descStencil);
-        pStencil->Release();
+    D3DSURFACE_DESC descStencil;
+    pTargetDepth->GetDesc(&descStencil);
 
-        D3DDISPLAYMODE dm;
-        return
-            (SUCCEEDED(pd3dDevice->GetDisplayMode(0, &dm)) &&
-             pTargetDesc->Width <= descStencil.Width &&
-             pTargetDesc->Height <= descStencil.Height &&
-             pTargetDesc->MultiSampleType == descStencil.MultiSampleType &&
-             pTargetDesc->MultiSampleQuality == descStencil.MultiSampleQuality &&
-             SUCCEEDED(pd3dObject->CheckDepthStencilMatch(
-                   adapterOrdinal,
-                   devCaps.DeviceType,
-                   dm.Format, pTargetDesc->Format,
-                   descStencil.Format)));
-    }
-    TraceLn(NWT_TRACE_VERBOSE,
-        "  current stencil buffer is not compatible with new Render Target");
-
-    return false;
+    D3DDISPLAYMODE dm;
+    return
+        (SUCCEEDED(pd3dDevice->GetDisplayMode(0, &dm)) &&
+         pTargetDesc->Width <= descStencil.Width &&
+         pTargetDesc->Height <= descStencil.Height &&
+         pTargetDesc->MultiSampleType == descStencil.MultiSampleType &&
+         pTargetDesc->MultiSampleQuality == descStencil.MultiSampleQuality &&
+         SUCCEEDED(pd3dObject->CheckDepthStencilMatch(
+               adapterOrdinal,
+               devCaps.DeviceType,
+               dm.Format, pTargetDesc->Format,
+               descStencil.Format)));
 }
 
 HRESULT
-D3DContext::InitDepthStencilBuffer(D3DSURFACE_DESC *pTargetDesc)
+D3DContext::InitDepthStencilBuffer(D3DSURFACE_DESC *pTargetDesc, IDirect3DSurface9 **ppDepthSSurface)
 {
     HRESULT res;
-    IDirect3DSurface9 *pBB;
     D3DDISPLAYMODE dm;
 
     TraceLn(NWT_TRACE_INFO, "D3DContext::InitDepthStencilBuffer");
@@ -764,12 +791,7 @@
 
     res = pd3dDevice->CreateDepthStencilSurface(
         pTargetDesc->Width, pTargetDesc->Height, newFormat,
-        pTargetDesc->MultiSampleType, pTargetDesc->MultiSampleQuality, false, &pBB, 0);
-
-    if (SUCCEEDED(res)) {
-        res = pd3dDevice->SetDepthStencilSurface(pBB);
-        pBB->Release();
-    }
+        pTargetDesc->MultiSampleType, pTargetDesc->MultiSampleQuality, false, ppDepthSSurface, 0);
 
     return res;
 }
@@ -801,7 +823,9 @@
 }
 
 HRESULT
-D3DContext::SetRenderTarget(IDirect3DSurface9 *pSurface)
+D3DContext::SetRenderTarget(IDirect3DSurface9 *pSurface,
+        IDirect3DSurface9 **ppTargetDepthSurface,
+        BOOL depthBuffer, BOOL msaa)
 {
     HRESULT res;
     D3DSURFACE_DESC descNew;
@@ -818,7 +842,6 @@
 
     if (SUCCEEDED(res = pd3dDevice->GetRenderTarget(0, &pCurrentTarget))) {
         if (pCurrentTarget != pSurface) {
-
 #if defined PERF_COUNTERS
             getStats().numRenderTargetSwitch++;
 #endif
@@ -830,18 +853,48 @@
                 return res;
             }
 
-            if (!IsDepthStencilBufferOk(&descNew)) {
-                if (FAILED(res = InitDepthStencilBuffer(&descNew))) {
-                    SAFE_RELEASE(pCurrentTarget);
-                    return res;
+            currentSurface = pSurface;
+            SAFE_RELEASE(pCurrentTarget);
+        }
+
+        IDirect3DSurface9 *pCurrentDepth;
+        res = pd3dDevice->GetDepthStencilSurface(&pCurrentDepth);
+        if (res == D3DERR_NOTFOUND) {
+            pCurrentDepth = NULL;
+            res = D3D_OK;
+        } else if (FAILED(res)) {
+            return res;
+        }
+
+        if (!IsDepthStencilBufferOk(&descNew, *ppTargetDepthSurface)) {
+            *ppTargetDepthSurface = NULL;
+        }
+        bool depthIsNew = false;
+        if (depthBuffer && (*ppTargetDepthSurface) == NULL) {
+            if (FAILED(res = InitDepthStencilBuffer(&descNew, ppTargetDepthSurface))) {
+                DebugPrintD3DError(res, "D3DContext::SetRenderTarget: error creating new depth buffer");
+                return res;
+            }
+            depthIsNew = true;
+        }
+        if (pCurrentDepth != (*ppTargetDepthSurface)) {
+            res = pd3dDevice->SetDepthStencilSurface(*ppTargetDepthSurface);
+            SAFE_RELEASE(pCurrentDepth);
+            if ((*ppTargetDepthSurface) != NULL && depthIsNew) {
+                // Depth buffer must be cleared after it is created, also
+                // if depth buffer was not attached when render target was
+                // cleared, then the depth buffer will contain garbage
+                pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, D3DZB_TRUE);
+                res = pd3dDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, NULL , 1.0f, 0x0L);
+                if (FAILED(res)) {
+                    DebugPrintD3DError(res,
+                            "D3DContext::SetRenderTarget: error clearing depth buffer");
                 }
             }
-            SAFE_RELEASE(pCurrentTarget);
-            // z-buffer will be cleared on setting of projview matrix
-        } else {
-            SAFE_RELEASE(pCurrentTarget);
-            return D3D_OK;
+        } else if (pCurrentTarget == pSurface) {
+            return res; // Render target has not changed
         }
+        pd3dDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, msaa);
     }
     // NOTE PRISM: changed to only recalculate the matrix if current target is
     // different for now
--- a/modules/graphics/src/main/native-prism-d3d/D3DContext.h	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/native-prism-d3d/D3DContext.h	Tue Aug 27 09:36:40 2013 -0700
@@ -83,6 +83,10 @@
 public:
 
     HRESULT drawIndexedQuads(struct PrismSourceVertex const *pSrcFloats, BYTE const *pSrcColors, int numVerts);
+    void D3DContext::stretchRect(IDirect3DSurface9* pSrcSurface,
+                                int srcX0, int srcY0, int srcX1, int srcY1,
+                                IDirect3DSurface9* pDstSurface,
+                                int dstX0, int dstY0, int dstX1, int dstY1);
 
     HRESULT drawTriangleList(struct PrismSourceVertex const *pSrcFloats, BYTE const *pSrcColors, int numTriangles);
 
@@ -139,7 +143,7 @@
 
     D3DPOOL getResourcePool() { return defaulResourcePool; }
 
-    HRESULT SetRenderTarget(IDirect3DSurface9 *pSurface);
+    HRESULT SetRenderTarget(IDirect3DSurface9 *pSurface, IDirect3DSurface9 **ppTargetDepthSurface, BOOL depthBuffer, BOOL msaa);
     HRESULT SetCameraPosition(jdouble camPosX, jdouble camPosY, jdouble camPosZ);
     HRESULT SetProjViewMatrix(BOOL isOrtho,
                               jdouble m00, jdouble m01, jdouble m02, jdouble m03,
@@ -251,10 +255,10 @@
 
     // finds appropriate to the target surface depth format,
     // creates the depth buffer and installs it onto the device
-    HRESULT InitDepthStencilBuffer(D3DSURFACE_DESC *pTargetDesc);
+    HRESULT InitDepthStencilBuffer(D3DSURFACE_DESC *pTargetDesc, IDirect3DSurface9 **ppDepthSSurfaceTarget);
     // returns true if the current depth buffer is compatible
     // with the new target, and the dimensions fit, false otherwise
-    BOOL IsDepthStencilBufferOk(D3DSURFACE_DESC *pTargetDesc);
+    BOOL IsDepthStencilBufferOk(D3DSURFACE_DESC *pTargetDesc, IDirect3DSurface9 *pTargetDepth);
 
     HRESULT UpdateVertexShaderTX();
 
@@ -263,6 +267,7 @@
     HRESULT InitContextCaps();
     IDirect3DDevice9        *pd3dDevice;
     IDirect3DDevice9Ex      *pd3dDeviceEx;
+    IDirect3DSurface9       *currentSurface;
     HWND                     deviceWindow;
     IDirect3D9              *pd3dObject;
     IDirect3D9Ex            *pd3dObjectEx;
--- a/modules/graphics/src/main/native-prism-d3d/D3DGraphics.cc	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/native-prism-d3d/D3DGraphics.cc	Tue Aug 27 09:36:40 2013 -0700
@@ -177,6 +177,21 @@
     return (x+3) & ~3;
 }
 
+void D3DContext::stretchRect(IDirect3DSurface9* pSrcSurface,
+                               int srcX0, int srcY0, int srcX1, int srcY1,
+                               IDirect3DSurface9* pDstSurface,
+                               int dstX0, int dstY0, int dstX1, int dstY1)
+{
+    HRESULT res;
+    IDirect3DSurface9* pDst = (pDstSurface == NULL) ? currentSurface : pDstSurface;
+    RECT srcRect = {srcX0, srcY0, srcX1, srcY1};
+    RECT dstRect = {dstX0, dstY0, dstX1, dstY1};
+    res = pd3dDevice->StretchRect(pSrcSurface, &srcRect, pDst, &dstRect, D3DTEXF_NONE);
+    if (FAILED(res)) {
+        DebugPrintD3DError(res, "D3DContext::strechRect: error StretchRect");
+    }
+}
+
 HRESULT D3DContext::drawIndexedQuads(PrismSourceVertex const *pSrcFloats, BYTE const *pSrcColors, int numVerts) {
 
     // pVertexBufferRes and pVertexBuffer is never null
@@ -356,7 +371,7 @@
  * Method:    nSetRenderTarget
  */
 JNIEXPORT jint JNICALL Java_com_sun_prism_d3d_D3DContext_nSetRenderTarget
-  (JNIEnv *, jclass, jlong ctx, jlong targetRes)
+  (JNIEnv *, jclass, jlong ctx, jlong targetRes, jboolean depthBuffer, jboolean msaa)
 {
     D3DContext *pCtx = (D3DContext*)jlong_to_ptr(ctx);
     D3DResource *pRes = (D3DResource *)jlong_to_ptr(targetRes);
@@ -366,7 +381,11 @@
     IDirect3DSurface9 *pRenderTarget = pRes->GetSurface();
     RETURN_STATUS_IF_NULL(pRenderTarget, E_FAIL);
 
-    return pCtx->SetRenderTarget(pRenderTarget);
+    IDirect3DSurface9 *pDepthBuffer = pRes->GetDepthSurface();
+
+    HRESULT res = pCtx->SetRenderTarget(pRenderTarget, &pDepthBuffer, depthBuffer, msaa);
+    pRes->SetDepthSurface(pDepthBuffer);
+    return res;
 }
 
 /*
--- a/modules/graphics/src/main/native-prism-d3d/D3DLight.cc	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/native-prism-d3d/D3DLight.cc	Tue Aug 27 09:36:40 2013 -0700
@@ -41,6 +41,7 @@
     position[0] = 0;
     position[1] = 0;
     position[2] = 0;
+    position[3] = 0; // padding since SetPixelShaderConstantF only takes vec4f; position[3] is unused
     w = 0;
 }
 
--- a/modules/graphics/src/main/native-prism-d3d/D3DLight.h	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/native-prism-d3d/D3DLight.h	Tue Aug 27 09:36:40 2013 -0700
@@ -39,7 +39,7 @@
     virtual ~D3DLight();
     void setColor(float r, float g, float b);
     void setPosition(float x, float y, float z);
-    float position[3];
+    float position[4]; // Only need x, y, z. The last float is needed for padding when upload to shader.
     float color[3];
     float w;
 
--- a/modules/graphics/src/main/native-prism-d3d/D3DMeshView.cc	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/native-prism-d3d/D3DMeshView.cc	Tue Aug 27 09:36:40 2013 -0700
@@ -146,7 +146,7 @@
     sortLights();
     // We only support up to 3 point lights at the present
     for (int i = 0; i < 3; i++) {
-            status = SUCCEEDED(device->SetVertexShaderConstantF(VSR_LIGHTS + i*2, lights[lightsOrder[i]].position, 2));
+            status = SUCCEEDED(device->SetVertexShaderConstantF(VSR_LIGHTS + i*2, lights[lightsOrder[i]].position, 1));
     }
 
     status = SUCCEEDED(device->SetVertexShaderConstantF(VSR_AMBIENTCOLOR, ambientLightColor, 1));
--- a/modules/graphics/src/main/native-prism-d3d/D3DPipeline.cc	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/native-prism-d3d/D3DPipeline.cc	Tue Aug 27 09:36:40 2013 -0700
@@ -178,6 +178,10 @@
     env->SetIntField(object, id, value);
 }
 
+void fillMSAASupportInformation(JNIEnv *env, jobject object, jclass clazz, int max) {
+    setIntField(env, object, clazz, "maxSamples", max);
+}
+
 void fillDriverInformation(JNIEnv *env, jobject object, jclass clazz, D3DADAPTER_IDENTIFIER9 &did, D3DCAPS9 &caps) {
     setStringField(env, object, clazz, "deviceDescription", did.Description);
     setStringField(env, object, clazz, "deviceName", did.DeviceName);
@@ -213,6 +217,29 @@
     return i;
 }
 
+int getMaxSampleSupport(IDirect3D9 *d3d9, UINT adapter) {
+    int maxSamples = 0;
+    if (SUCCEEDED(d3d9->CheckDeviceMultiSampleType(adapter,
+					D3DDEVTYPE_HAL , D3DFMT_X8R8G8B8, FALSE,
+					D3DMULTISAMPLE_2_SAMPLES, NULL))) {
+        const int MAX_SAMPLES_SEARCH = D3DMULTISAMPLE_16_SAMPLES;
+        maxSamples = D3DMULTISAMPLE_2_SAMPLES;
+        // Typically even samples are used, thus checking only even samples to
+        // save time
+        for (int i = maxSamples; i <= MAX_SAMPLES_SEARCH; i += 2) {
+            D3DMULTISAMPLE_TYPE msType = static_cast<D3DMULTISAMPLE_TYPE>(i);
+            if (SUCCEEDED(d3d9->CheckDeviceMultiSampleType(adapter,
+					D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, FALSE,
+					msType, NULL))) {
+                maxSamples = i;
+            } else {
+                break;
+            }
+        }
+    }
+    return maxSamples;
+}
+
 JNIEXPORT jobject JNICALL Java_com_sun_prism_d3d_D3DPipeline_nGetDriverInformation(JNIEnv *env, jclass, jint adapter, jobject obj) {
 
     if (!obj) {
@@ -240,11 +267,35 @@
         return 0;
     }
 
+    int maxSamples = getMaxSampleSupport(d3d9, adapter);
+
     if (jclass cls = env->GetObjectClass(obj)) {
         fillDriverInformation(env, obj, cls, d_id, caps);
+        fillMSAASupportInformation(env, obj, cls, maxSamples);
         fillOsVersionInformation(env, obj, cls);
     }
 
     d3d9->Release();
     return obj;
 }
+
+JNIEXPORT jint JNICALL Java_com_sun_prism_d3d_D3DPipeline_nGetMaxSampleSupport(JNIEnv *env, jclass, jint adapter) {
+
+    // if there is D3DPipelineManager take ready D3D9 object, otherwise create new
+    IDirect3D9 * d3d9 = D3DPipelineManager::GetInstance() ?
+        addRef(D3DPipelineManager::GetInstance()->GetD3DObject()) : Direct3DCreate9();
+
+    if (!d3d9) {
+        return 0;
+    }
+
+    if (unsigned(adapter) >= d3d9->GetAdapterCount()) {
+        d3d9->Release();
+        return 0;
+    }
+
+    int maxSamples = getMaxSampleSupport(d3d9, adapter);
+
+    d3d9->Release();
+    return maxSamples;
+}
--- a/modules/graphics/src/main/native-prism-d3d/D3DPipeline.h	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/native-prism-d3d/D3DPipeline.h	Tue Aug 27 09:36:40 2013 -0700
@@ -123,6 +123,9 @@
         return (status);                   \
     } else do { } while (0)
 
+// d3d9 must be valid and tested
+int getMaxSampleSupport(IDirect3D9 *d3d9, UINT adapter);
+
 inline void logD3DSurfaceDesc(D3DSURFACE_DESC const & dsk) {
     RlsTrace5(NWT_TRACE_INFO, "w=%d, h=%d, Format = %d, Pool=%d, Usage=%d\n",
         dsk.Width, dsk.Height, dsk.Format, dsk.Pool, dsk.Usage);
--- a/modules/graphics/src/main/native-prism-d3d/D3DResourceFactory.cc	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/native-prism-d3d/D3DResourceFactory.cc	Tue Aug 27 09:36:40 2013 -0700
@@ -67,7 +67,8 @@
 JNIEXPORT jlong JNICALL
 Java_com_sun_prism_d3d_D3DResourceFactory_nCreateTexture
   (JNIEnv *env, jclass klass,
-   jlong ctx, jint formatHint, jint usageHint, jboolean isRTT, jint width, jint height)
+        jlong ctx, jint formatHint, jint usageHint, jboolean isRTT,
+        jint width, jint height, jint samples)
 {
     HRESULT res;
 
@@ -114,9 +115,15 @@
             break;
     }
 
-    res = pMgr->CreateTexture(width, height, isRTT, isOpaque,
-            &format, dwUsage, &pTexResource);
-
+    if (samples) {
+        // assert isRTT == true
+        D3DMULTISAMPLE_TYPE msType = static_cast<D3DMULTISAMPLE_TYPE>(samples);
+        res = pMgr->CreateRenderTarget(width, height, isOpaque,
+                &format, msType, &pTexResource);
+    } else {
+        res = pMgr->CreateTexture(width, height, isRTT, isOpaque,
+                &format, dwUsage, &pTexResource);
+    }
     if (SUCCEEDED(res)) {
         return ptr_to_jlong(pTexResource);
     }
--- a/modules/graphics/src/main/native-prism-d3d/D3DResourceManager.cc	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/native-prism-d3d/D3DResourceManager.cc	Tue Aug 27 09:36:40 2013 -0700
@@ -38,6 +38,7 @@
 {
     TraceLn(NWT_TRACE_INFO, "D3DResource::Init");
 
+    pDepthSurface = NULL;
     pResource  = NULL;
     pSwapChain = pSC;
     pSurface   = NULL;
@@ -76,7 +77,6 @@
     if (pSurface != NULL) {
         pSurface->GetDesc(&desc);
     }
-
     SAFE_PRINTLN(pResource);
     SAFE_PRINTLN(pSurface);
     SAFE_PRINTLN(pTexture);
@@ -401,6 +401,96 @@
     return res;
 }
 
+HRESULT D3DResourceManager::CreateRenderTarget(UINT width, UINT height,
+                                               BOOL isOpaque,
+                                               D3DFORMAT *pFormat,
+                                               D3DMULTISAMPLE_TYPE msType,
+                                               D3DResource **ppSurfaceResource)
+{
+    TraceLn(NWT_TRACE_INFO, "D3DRM::CreateRenderTarget");
+
+    IDirect3DDevice9 *pd3dDevice = pCtx->Get3DDevice();
+
+    if (pd3dDevice == NULL) {
+        return E_FAIL;
+    }
+
+    D3DFORMAT format;
+    if (pFormat != NULL && *pFormat != D3DFMT_UNKNOWN) {
+        format = *pFormat;
+    } else {
+        if (isOpaque) {
+            format = D3DFMT_X8R8G8B8;
+        } else {
+            format = D3DFMT_A8R8G8B8;
+        }
+    }
+
+    DWORD totalSamples = 0;
+    IDirect3D9 *pd3dObject = pCtx->Get3DObject();
+    HRESULT res;
+    if(FAILED(res = pd3dObject->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT,
+                                    D3DDEVTYPE_HAL, format, false,
+                                    msType, &totalSamples))) {
+        DebugPrintD3DError(res, "D3DRM::CreateRenderTarget failed D3DMULTISAMPLE_"/
+                + (int)msType +"_SAMPLES not supported");
+        return res;
+    }
+
+    if (pCtx->IsPow2TexturesOnly()) {
+          UINT w, h;
+          for (w = 1; width  > w; w <<= 1);
+          for (h = 1; height > h; h <<= 1);
+          width = w;
+          height = h;
+    }
+    if (pCtx->IsSquareTexturesOnly()) {
+        if (width > height) {
+            height = width;
+        } else {
+            width = height;
+        }
+    }
+
+    BOOL lockable = false;
+    DWORD multisampleQuality = totalSamples - 1;
+    IDirect3DSurface9 *pSurface = NULL;
+
+    res = pd3dDevice->CreateRenderTarget(width, height, format,
+            msType, multisampleQuality, lockable, &pSurface, NULL);
+
+    if (SUCCEEDED(res)) {
+        TraceLn1(NWT_TRACE_VERBOSE, "  created render target surface: 0x%x", pSurface);
+        *ppSurfaceResource = new D3DResource((IDirect3DResource9*)pSurface);
+        res = AddResource(*ppSurfaceResource);
+    } else {
+        DebugPrintD3DError(res, "D3DRM::CreateRenderTarget failed");
+
+        switch(res) {
+            case D3DERR_NOTAVAILABLE:
+                DebugPrintD3DError(res, "   D3DERR_NOTAVAILABLE ");
+                break;
+            case D3DERR_INVALIDCALL:
+                DebugPrintD3DError(res, "   D3DERR_INVALIDCALL ");
+                break;
+            case D3DERR_OUTOFVIDEOMEMORY:
+                DebugPrintD3DError(res, "   D3DERR_OUTOFVIDEOMEMORY ");
+                break;
+            case E_OUTOFMEMORY:
+                DebugPrintD3DError(res, "   E_OUTOFMEMORY ");
+                break;
+            default: break;
+        }
+        *ppSurfaceResource = NULL;
+        format = D3DFMT_UNKNOWN;
+    }
+
+    if (pFormat != NULL) {
+        *pFormat = format;
+    }
+
+    return res;
+}
 
 HRESULT D3DResourceManager::CreateOSPSurface(UINT width, UINT height,
                                          D3DFORMAT fmt,
@@ -436,7 +526,7 @@
         res = AddResource(*ppSurfaceResource);
     } else {
         DebugPrintD3DError(res, "D3DRM::CreateOSPSurface failed");
-        ppSurfaceResource = NULL;
+        *ppSurfaceResource = NULL;
     }
     return res;
 }
--- a/modules/graphics/src/main/native-prism-d3d/D3DResourceManager.h	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/native-prism-d3d/D3DResourceManager.h	Tue Aug 27 09:36:40 2013 -0700
@@ -97,6 +97,8 @@
     IDirect3DResource9*  GetResource() { return pResource; }
     IDirect3DTexture9*   GetTexture() { return pTexture; }
     IDirect3DSurface9*   GetSurface() { return pSurface; }
+    IDirect3DSurface9*   GetDepthSurface() { return pDepthSurface; }
+    void                 SetDepthSurface(IDirect3DSurface9* pDB) { pDepthSurface = pDB; }
     IDirect3DSwapChain9* GetSwapChain() { return pSwapChain; }
     D3DSURFACE_DESC*     GetDesc() { return &desc; }
     virtual BOOL         IsDefaultPool();
@@ -116,6 +118,7 @@
     IDirect3DResource9*  pResource;
     IDirect3DSwapChain9* pSwapChain;
     IDirect3DSurface9*   pSurface;
+    IDirect3DSurface9*   pDepthSurface;
     IDirect3DTexture9*   pTexture;
 
     D3DSURFACE_DESC      desc;
@@ -194,6 +197,12 @@
                           DWORD dwUsage,
                           D3DResource **ppTextureResource/*out*/);
 
+    HRESULT D3DResourceManager::CreateRenderTarget(UINT width, UINT height,
+                                  BOOL isOpaque,
+                                  D3DFORMAT *pFormat,
+                                  D3DMULTISAMPLE_TYPE msType,
+                                  D3DResource **ppSurfaceResource);
+
     HRESULT CreateSwapChain(HWND hWnd, UINT numBuffers, UINT width, UINT height,
                             D3DSWAPEFFECT swapEffect, UINT presentationInterval,
                             D3DResource ** ppSwapChainResource/*out*/);
--- a/modules/graphics/src/main/native-prism-d3d/hlsl/vsMath.h	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/native-prism-d3d/hlsl/vsMath.h	Tue Aug 27 09:36:40 2013 -0700
@@ -74,7 +74,7 @@
 
     for (int k=0; k<LocalBump::nLights; ++k) {
         float3 L = sLights[k].pos.xyz - pos;
-        r.lBump.lights[k] = float4( getLocalVector(L, n)*sLights[k].pos.w, 1);
+        r.lBump.lights[k] = float4(getLocalVector(L, n), 1);
     }
 
     r.pos  = mul(float4(pos,1), mViewProj);
--- a/modules/graphics/src/main/native-prism-es2/GLContext.c	Tue Aug 27 09:59:24 2013 -0400
+++ b/modules/graphics/src/main/native-prism-es2/GLContext.c	Tue Aug 27 09:36:40 2013 -0700
@@ -360,17 +360,17 @@
 /*
  * Class:     com_sun_prism_es2_GLContext
  * Method:    nBlit
- * Signature: (JIIIIIIIIII)I
+ * Signature: (JIIIIIIIIII)V
  */
-JNIEXPORT jint JNICALL Java_com_sun_prism_es2_GLContext_nBlit
+JNIEXPORT void JNICALL Java_com_sun_prism_es2_GLContext_nBlit
 (JNIEnv *env, jclass class, jlong nativeCtxInfo, jint srcFBO, jint dstFBO,
-            int jsrcX0, int jsrcY0, jint srcX1, jint srcY1,
-            int jdstX0, int jdstY0, jint dstX1, jint dstY1) {
+            jint jsrcX0, jint jsrcY0, jint srcX1, jint srcY1,
+            jint jdstX0, jint jdstY0, jint dstX1, jint dstY1) {
     ContextInfo *ctxInfo = (ContextInfo *) jlong_to_ptr(nativeCtxInfo);
     if ((ctxInfo == NULL) || (ctxInfo->glGenFramebuffers == NULL)
             || (ctxInfo->glBindFramebuffer == NULL)
             || (ctxInfo->glBlitFramebuffer == NULL)) {
-        return 0;
+        return;
     }
 
     if (dstFBO == 0) {
@@ -392,7 +392,6 @@