changeset 5744:91c3424ab464

Automated merge with ssh://jfxsrc.us.oracle.com//javafx/8.0/MASTER/jfx/rt
author kcr
date Mon, 18 Nov 2013 22:06:51 -0800
parents dae901206261 267dbc0bb8a4
children 099371bc2630
files build.properties modules/graphics/src/main/java/com/sun/javafx/embed/EmbeddedSceneDragSourceInterface.java modules/graphics/src/main/java/com/sun/javafx/embed/EmbeddedSceneDragStartListenerInterface.java modules/graphics/src/main/java/com/sun/javafx/embed/EmbeddedSceneDropTargetInterface.java modules/graphics/src/main/java/com/sun/javafx/tk/quantum/AbstractEventLoop.java modules/graphics/src/main/java/com/sun/javafx/tk/quantum/EmbeddedSceneDragSource.java modules/graphics/src/main/java/com/sun/javafx/tk/quantum/EmbeddedSceneDropTarget.java modules/graphics/src/main/java/com/sun/javafx/tk/quantum/FxEventLoop.java
diffstat 95 files changed, 1853 insertions(+), 2972 deletions(-) [+]
line wrap: on
line diff
--- a/apps/samples/Ensemble8/src/app/java/ensemble/EnsembleApp.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/apps/samples/Ensemble8/src/app/java/ensemble/EnsembleApp.java	Mon Nov 18 22:06:51 2013 -0800
@@ -36,8 +36,6 @@
 import ensemble.control.SearchBox;
 import ensemble.control.TitledToolBar;
 import ensemble.generated.Samples;
-import java.util.ArrayList;
-import java.util.List;
 import javafx.application.Application;
 import javafx.event.ActionEvent;
 import javafx.event.EventHandler;
@@ -53,7 +51,6 @@
 import javafx.scene.layout.Pane;
 import javafx.scene.layout.Region;
 import javafx.scene.paint.Color;
-import javafx.scene.text.Font;
 import javafx.scene.transform.Scale;
 import javafx.stage.Screen;
 import javafx.stage.Stage;
@@ -72,7 +69,7 @@
     public static final boolean IS_MAC = OS_NAME.startsWith("Mac");
     public static final boolean PRELOAD_PREVIEW_IMAGES = true;
     public static final boolean SHOW_HIGHLIGHTS = IS_DESKTOP;
-    public static final boolean SHOW_MENU = IS_DESKTOP;
+    public static final boolean SHOW_MENU = false;
     public static final boolean SELECT_IOS_THEME = false;
     private static final int TOOL_BAR_BUTTON_SIZE = 30;
     private Scene scene;
--- a/apps/samples/Ensemble8/src/samples/java/ensemble/samples/graphics/shapes/ellipse/EllipseApp.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/apps/samples/Ensemble8/src/samples/java/ensemble/samples/graphics/shapes/ellipse/EllipseApp.java	Mon Nov 18 22:06:51 2013 -0800
@@ -66,7 +66,7 @@
 
     public Parent createContent() {
         Pane root = new Pane();
-        root.setPrefSize(245, 100);
+        root.setPrefSize(200, 100);
         root.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
         root.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
         // Red ellipse
--- a/apps/samples/Ensemble8/src/samples/java/ensemble/samples/graphics/shapes/path/PathApp.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/apps/samples/Ensemble8/src/samples/java/ensemble/samples/graphics/shapes/path/PathApp.java	Mon Nov 18 22:06:51 2013 -0800
@@ -98,6 +98,7 @@
         path2.setFill(null);
         path2.setStroke(Color.DODGERBLUE);
         path2.setStrokeWidth(2);
+        path2.setTranslateY(36);
         root.getChildren().addAll(path1, path2);
         return root;
     }
--- a/apps/samples/Ensemble8/src/samples/java/ensemble/samples/graphics/shapes/polygon/PolygonApp.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/apps/samples/Ensemble8/src/samples/java/ensemble/samples/graphics/shapes/polygon/PolygonApp.java	Mon Nov 18 22:06:51 2013 -0800
@@ -72,7 +72,7 @@
 
     public Parent createContent() {
         Pane root = new Pane();
-        root.setPrefSize(245, 100);
+        root.setPrefSize(180, 100);
         root.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
         root.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
         polygon1.setFill(Color.RED);
--- a/apps/samples/Ensemble8/src/samples/java/ensemble/samples/graphics/shapes/polyline/PolylineApp.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/apps/samples/Ensemble8/src/samples/java/ensemble/samples/graphics/shapes/polyline/PolylineApp.java	Mon Nov 18 22:06:51 2013 -0800
@@ -69,7 +69,7 @@
 
     public Parent createContent() {
         Pane root = new Pane();
-        root.setPrefSize(245, 100);
+        root.setPrefSize(184, 100);
         root.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
         root.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
         polyline1.setFill(Color.TRANSPARENT);
--- a/apps/samples/Ensemble8/src/samples/java/ensemble/samples/graphics/shapes/quadcurve/QuadCurveApp.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/apps/samples/Ensemble8/src/samples/java/ensemble/samples/graphics/shapes/quadcurve/QuadCurveApp.java	Mon Nov 18 22:06:51 2013 -0800
@@ -31,14 +31,12 @@
  */
 package ensemble.samples.graphics.shapes.quadcurve;
 
-import ensemble.samples.graphics.shapes.polyline.*;
 import javafx.application.Application;
 import javafx.scene.Parent;
 import javafx.scene.Scene;
 import javafx.scene.layout.Pane;
 import javafx.scene.layout.Region;
 import javafx.scene.paint.Color;
-import javafx.scene.shape.Polyline;
 import javafx.scene.shape.QuadCurve;
 import javafx.stage.Stage;
 
@@ -66,7 +64,7 @@
 
     public Parent createContent() {
         Pane root = new Pane();
-        root.setPrefSize(245, 100);
+        root.setPrefSize(184, 100);
         root.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
         root.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
         quadCurve.setStartX(0);
--- a/apps/samples/Ensemble8/src/samples/java/ensemble/samples/graphics/shapes/rectangle/RectangleApp.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/apps/samples/Ensemble8/src/samples/java/ensemble/samples/graphics/shapes/rectangle/RectangleApp.java	Mon Nov 18 22:06:51 2013 -0800
@@ -31,14 +31,12 @@
  */
 package ensemble.samples.graphics.shapes.rectangle;
 
-import ensemble.samples.graphics.shapes.polygon.*;
 import javafx.application.Application;
 import javafx.scene.Parent;
 import javafx.scene.Scene;
 import javafx.scene.layout.Pane;
 import javafx.scene.layout.Region;
 import javafx.scene.paint.Color;
-import javafx.scene.shape.Polygon;
 import javafx.scene.shape.Rectangle;
 import javafx.stage.Stage;
 
@@ -71,7 +69,7 @@
 
     public Parent createContent() {
         Pane root = new Pane();
-        root.setPrefSize(245, 100);
+        root.setPrefSize(200, 100);
         root.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
         root.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
         // Make the simple rectangle red
--- a/apps/samples/Ensemble8/src/samples/java/ensemble/samples/language/beans/changelistener/ChangeListenerApp.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/apps/samples/Ensemble8/src/samples/java/ensemble/samples/language/beans/changelistener/ChangeListenerApp.java	Mon Nov 18 22:06:51 2013 -0800
@@ -36,6 +36,7 @@
 import javafx.beans.Observable;
 import javafx.event.ActionEvent;
 import javafx.event.EventHandler;
+import javafx.geometry.Insets;
 import javafx.geometry.Pos;
 import javafx.geometry.VPos;
 import javafx.scene.Parent;
@@ -119,6 +120,7 @@
         // show all nodes
         vbox.getChildren().addAll(text, buttonAdd, buttonRemove);
         outerHbox.getChildren().addAll(vbox, rect);
+        outerHbox.setPadding(new Insets(5,5,5,5));
         return outerHbox;
     }
     
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apps/toys/FX8-3DFeatures/src/fx83dfeatures/TwoBoxes.java	Mon Nov 18 22:06:51 2013 -0800
@@ -0,0 +1,116 @@
+/*
+ * 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 fx83dfeatures;
+
+import javafx.application.Application;
+import javafx.event.EventHandler;
+import javafx.scene.Group;
+import javafx.scene.PerspectiveCamera;
+import javafx.scene.PointLight;
+import javafx.scene.Scene;
+import javafx.scene.input.MouseEvent;
+import javafx.scene.paint.Color;
+import javafx.scene.paint.PhongMaterial;
+import javafx.scene.shape.Box;
+import javafx.scene.transform.Rotate;
+import javafx.stage.Stage;
+
+public class TwoBoxes extends Application {
+
+    double anchorX, anchorY, anchorAngle;
+
+    private PerspectiveCamera addCamera(Scene scene) {
+        PerspectiveCamera perspectiveCamera = new PerspectiveCamera(false);
+        scene.setCamera(perspectiveCamera);
+        return perspectiveCamera;
+    }
+
+    /**
+     * @param args the command line arguments
+     */
+    public static void main(String[] args) {
+        launch(args);
+    }
+
+    @Override
+    public void start(Stage primaryStage) {
+        System.out.println("javafx.runtime.version: " + System.getProperties().get("javafx.runtime.version"));
+        primaryStage.setTitle("2 Boxes");
+
+        final PhongMaterial redMaterial = new PhongMaterial();
+        redMaterial.setSpecularColor(Color.ORANGE);
+        redMaterial.setDiffuseColor(Color.RED);
+
+        final Box box1 = new Box(400, 400, 400);
+        box1.setMaterial(redMaterial);
+
+        final Box box2 = new Box(400, 400, 400);
+
+        box2.setMaterial(redMaterial);
+
+        box2.setTranslateX(250);
+        box2.setTranslateY(250);
+        box2.setTranslateZ(50);
+        box1.setTranslateX(250);
+        box1.setTranslateY(250);
+        box1.setTranslateZ(450);
+
+        final Group parent = new Group(box1, box2);
+        parent.setTranslateZ(500);
+        parent.setRotationAxis(Rotate.Y_AXIS);
+
+
+        final Group root = new Group(parent);
+
+        final Scene scene = new Scene(root, 500, 500, true);
+
+        scene.setOnMousePressed(new EventHandler<MouseEvent>() {
+            @Override
+            public void handle(MouseEvent event) {
+                anchorX = event.getSceneX();
+                anchorY = event.getSceneY();
+                anchorAngle = parent.getRotate();
+            }
+        });
+
+        scene.setOnMouseDragged(new EventHandler<MouseEvent>() {
+            @Override
+            public void handle(MouseEvent event) {
+                parent.setRotate(anchorAngle + anchorX - event.getSceneX());
+            }
+        });
+
+        PointLight pointLight = new PointLight(Color.ANTIQUEWHITE);
+        pointLight.setTranslateX(15);
+        pointLight.setTranslateY(-10);
+        pointLight.setTranslateZ(-100);
+
+        root.getChildren().add(pointLight);
+
+        addCamera(scene);
+        primaryStage.setScene(scene);
+        primaryStage.show();
+    }
+}
--- a/build.properties	Thu Nov 14 10:49:15 2013 -0800
+++ b/build.properties	Mon Nov 18 22:06:51 2013 -0800
@@ -63,4 +63,4 @@
 
 jfx.build.jdk.version=1.8.0
 jfx.build.jdk.buildnum=116
-jfx.build.jdk.buildnum.min=113
+jfx.build.jdk.buildnum.min=115
--- a/buildSrc/android.gradle	Thu Nov 14 10:49:15 2013 -0800
+++ b/buildSrc/android.gradle	Mon Nov 18 22:06:51 2013 -0800
@@ -562,10 +562,9 @@
     ANDROID.fontT2K.javahInclude = ["com/sun/javafx/font/t2k/**/*"]
     ANDROID.fontT2K.nativeSource = [
         file("$closedDir/javafx-font-t2k-native/src"),
-        file("$closedDir/javafx-font-t2k-native/src/layout"),
-        file("$closedDir/javafx-font-t2k-native/src/layoutfx")]
+        file("$closedDir/javafx-font-t2k-native/src/layout")]
     ANDROID.fontT2K.compiler = compiler
-    ANDROID.fontT2K.ccFlags = [ccFlags, "-fno-exceptions", "-fno-rtti", ccWarnFlags,
+    ANDROID.fontT2K.ccFlags = [ccFlags, "-DLE_STANDALONE", "-fno-exceptions", "-fno-rtti", ccWarnFlags,
         ccArchFlags, ccOptFlags, ccDebugFlags, ccDefaultIncludeFlags].flatten()
     ANDROID.fontT2K.linker = linker
     ANDROID.fontT2K.linkFlags = [linkFlags, "-lstdc++"].flatten()
--- a/buildSrc/armv6hf.gradle	Thu Nov 14 10:49:15 2013 -0800
+++ b/buildSrc/armv6hf.gradle	Mon Nov 18 22:06:51 2013 -0800
@@ -442,10 +442,9 @@
 ARMV6HF.fontT2K.javahInclude = ["com/sun/javafx/font/t2k/**/*"]
 ARMV6HF.fontT2K.nativeSource = [
         file("$closedDir/javafx-font-t2k-native/src"),
-        file("$closedDir/javafx-font-t2k-native/src/layout"),
-        file("$closedDir/javafx-font-t2k-native/src/layoutfx")]
+        file("$closedDir/javafx-font-t2k-native/src/layout")]
 ARMV6HF.fontT2K.compiler = compiler
-ARMV6HF.fontT2K.ccFlags = fontCFlags
+ARMV6HF.fontT2K.ccFlags = [fontCFlags, "-DLE_STANDALONE"].flatten()
 ARMV6HF.fontT2K.linker = linker
 ARMV6HF.fontT2K.linkFlags = fontLFlags
 ARMV6HF.fontT2K.lib = "javafx_font_t2k"
--- a/buildSrc/armv6sf.gradle	Thu Nov 14 10:49:15 2013 -0800
+++ b/buildSrc/armv6sf.gradle	Mon Nov 18 22:06:51 2013 -0800
@@ -461,10 +461,9 @@
 ARMV6SF.fontT2K.javahInclude = ["com/sun/javafx/font/t2k/**/*"]
 ARMV6SF.fontT2K.nativeSource = [
         file("$closedDir/javafx-font-t2k-native/src"),
-        file("$closedDir/javafx-font-t2k-native/src/layout"),
-        file("$closedDir/javafx-font-t2k-native/src/layoutfx")]
+        file("$closedDir/javafx-font-t2k-native/src/layout")]
 ARMV6SF.fontT2K.compiler = compiler
-ARMV6SF.fontT2K.ccFlags = fontCFlags
+ARMV6SF.fontT2K.ccFlags = [fontCFlags, "-DLE_STANDALONE"].flatten()
 ARMV6SF.fontT2K.linker = linker
 ARMV6SF.fontT2K.linkFlags = fontLFlags
 ARMV6SF.fontT2K.lib = "javafx_font_t2k"
--- a/buildSrc/ios.gradle	Thu Nov 14 10:49:15 2013 -0800
+++ b/buildSrc/ios.gradle	Mon Nov 18 22:06:51 2013 -0800
@@ -304,10 +304,9 @@
 IOS.fontT2K.arm = [:]
 IOS.fontT2K.arm.nativeSource = [
         file("$closedDir/javafx-font-t2k-native/src"),
-        file("$closedDir/javafx-font-t2k-native/src/layout"),
-        file("$closedDir/javafx-font-t2k-native/src/layoutfx")]
+        file("$closedDir/javafx-font-t2k-native/src/layout")]
 IOS.fontT2K.arm.compiler = compiler
-IOS.fontT2K.arm.ccFlags = ["-DJFXFONT_PLUS", ccFlags, "-arch", archArm, "-isysroot", sdkPath(iPhoneOS)].flatten()
+IOS.fontT2K.arm.ccFlags = ["-DJFXFONT_PLUS", "-DLE_STANDALONE", ccFlags, "-arch", archArm, "-isysroot", sdkPath(iPhoneOS)].flatten()
 IOS.fontT2K.arm.linker = linker
 IOS.fontT2K.arm.linkFlags = ["-arch_only", archArm, "-syslibroot", sdkPath(iPhoneOS), linkFlags].flatten()
 IOS.fontT2K.arm.lib = "javafx_font_t2k_${archArm}"
@@ -315,7 +314,7 @@
 IOS.fontT2K.x86 = [:]
 IOS.fontT2K.x86.nativeSource = [IOS.fontT2K.arm.nativeSource].flatten()
 IOS.fontT2K.x86.compiler = compiler
-IOS.fontT2K.x86.ccFlags = ["-DJFXFONT_PLUS", ccFlags, "-arch", archX86, "-isysroot", sdkPath(iPhoneSim)].flatten()
+IOS.fontT2K.x86.ccFlags = ["-DJFXFONT_PLUS", "-DLE_STANDALONE", ccFlags, "-arch", archX86, "-isysroot", sdkPath(iPhoneSim)].flatten()
 IOS.fontT2K.x86.linker = linker
 IOS.fontT2K.x86.linkFlags = ["-arch_only", archX86, "-syslibroot", sdkPath(iPhoneSim), linkFlags].flatten()
 IOS.fontT2K.x86.lib = "javafx_font_t2k_${archX86}"
--- a/buildSrc/linux.gradle	Thu Nov 14 10:49:15 2013 -0800
+++ b/buildSrc/linux.gradle	Mon Nov 18 22:06:51 2013 -0800
@@ -241,10 +241,9 @@
 LINUX.fontT2K.javahInclude = ["com/sun/javafx/font/t2k/**/*"]
 LINUX.fontT2K.nativeSource = [
         file("$closedDir/javafx-font-t2k-native/src"),
-        file("$closedDir/javafx-font-t2k-native/src/layout"),
-        file("$closedDir/javafx-font-t2k-native/src/layoutfx")]
+        file("$closedDir/javafx-font-t2k-native/src/layout")]
 LINUX.fontT2K.compiler = compiler
-LINUX.fontT2K.ccFlags = ["-DJFXFONT_PLUS", ccFlags].flatten()
+LINUX.fontT2K.ccFlags = ["-DJFXFONT_PLUS", "-DLE_STANDALONE", ccFlags].flatten()
 LINUX.fontT2K.linker = linker
 LINUX.fontT2K.linkFlags = [linkFlags].flatten()
 LINUX.fontT2K.lib = "javafx_font_t2k"
--- a/buildSrc/mac.gradle	Thu Nov 14 10:49:15 2013 -0800
+++ b/buildSrc/mac.gradle	Mon Nov 18 22:06:51 2013 -0800
@@ -198,10 +198,9 @@
 MAC.fontT2K.javahInclude = ["com/sun/javafx/font/t2k/**/*"]
 MAC.fontT2K.nativeSource = [
         file("$closedDir/javafx-font-t2k-native/src"),
-        file("$closedDir/javafx-font-t2k-native/src/layout"),
-        file("$closedDir/javafx-font-t2k-native/src/layoutfx")]
+        file("$closedDir/javafx-font-t2k-native/src/layout")]
 MAC.fontT2K.compiler = compiler
-MAC.fontT2K.ccFlags = ["-DJFXFONT_PLUS", ccFlags].flatten()
+MAC.fontT2K.ccFlags = ["-DJFXFONT_PLUS", "-DLE_STANDALONE", ccFlags].flatten()
 MAC.fontT2K.linker = linker
 MAC.fontT2K.linkFlags = [linkFlags].flatten()
 MAC.fontT2K.lib = "javafx_font_t2k"
--- a/buildSrc/win.gradle	Thu Nov 14 10:49:15 2013 -0800
+++ b/buildSrc/win.gradle	Mon Nov 18 22:06:51 2013 -0800
@@ -258,10 +258,9 @@
 WIN.fontT2K.javahInclude = ["com/sun/javafx/font/t2k/**/*"]
 WIN.fontT2K.nativeSource = [
         file("$closedDir/javafx-font-t2k-native/src"),
-        file("$closedDir/javafx-font-t2k-native/src/layout"),
-        file("$closedDir/javafx-font-t2k-native/src/layoutfx")]
+        file("$closedDir/javafx-font-t2k-native/src/layout")]
 WIN.fontT2K.compiler = compiler
-WIN.fontT2K.ccFlags = ["/DJFXFONT_PLUS", ccFlags].flatten()
+WIN.fontT2K.ccFlags = ["/DJFXFONT_PLUS", "/DLE_STANDALONE", ccFlags].flatten()
 WIN.fontT2K.linker = linker
 WIN.fontT2K.linkFlags = [linkFlags, "advapi32.lib", "gdi32.lib", "user32.lib"].flatten()
 WIN.fontT2K.lib = "javafx_font_t2k"
--- a/buildSrc/x86egl.gradle	Thu Nov 14 10:49:15 2013 -0800
+++ b/buildSrc/x86egl.gradle	Mon Nov 18 22:06:51 2013 -0800
@@ -381,10 +381,9 @@
 X86EGL.fontT2K.javahInclude = ["com/sun/javafx/font/t2k/**/*"]
 X86EGL.fontT2K.nativeSource = [
         file("$closedDir/javafx-font-t2k-native/src"),
-        file("$closedDir/javafx-font-t2k-native/src/layout"),
-        file("$closedDir/javafx-font-t2k-native/src/layoutfx")]
+        file("$closedDir/javafx-font-t2k-native/src/layout")]
 X86EGL.fontT2K.compiler = compiler
-X86EGL.fontT2K.ccFlags = fontCFlags
+X86EGL.fontT2K.ccFlags = [fontCFlags, "-DLE_STANDALONE"].flatten()
 X86EGL.fontT2K.linker = linker
 X86EGL.fontT2K.linkFlags = fontLFlags
 X86EGL.fontT2K.lib = "javafx_font_t2k"
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/ComboBoxListViewSkin.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/ComboBoxListViewSkin.java	Mon Nov 18 22:06:51 2013 -0800
@@ -397,6 +397,7 @@
         textField = comboBox.getEditor();
         textField.setFocusTraversable(true);
         textField.promptTextProperty().bind(comboBox.promptTextProperty());
+        textField.tooltipProperty().bind(comboBox.tooltipProperty());
 
         // Fix for RT-21406: ComboBox do not show initial text value
         initialTextFieldValue = textField.getText();
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/LabeledSkinBase.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/LabeledSkinBase.java	Mon Nov 18 22:06:51 2013 -0800
@@ -29,6 +29,7 @@
 import javafx.beans.InvalidationListener;
 import javafx.beans.Observable;
 import javafx.geometry.HPos;
+import javafx.geometry.NodeOrientation;
 import javafx.geometry.Orientation;
 import javafx.geometry.Pos;
 import javafx.geometry.VPos;
@@ -1149,7 +1150,11 @@
                 textClip = new Rectangle();
             }
 
-            textClip.setX(text.getLayoutBounds().getMinX());
+            if (labeled.getEffectiveNodeOrientation() == NodeOrientation.LEFT_TO_RIGHT) {
+                textClip.setX(text.getLayoutBounds().getMinX());
+            } else {
+                textClip.setX(text.getLayoutBounds().getMaxX() - wrapWidth);
+            }
             textClip.setY(text.getLayoutBounds().getMinY());
             textClip.setWidth(wrapWidth);
             textClip.setHeight(wrapHeight);
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/NestedTableColumnHeader.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/NestedTableColumnHeader.java	Mon Nov 18 22:06:51 2013 -0800
@@ -36,11 +36,14 @@
 import javafx.geometry.NodeOrientation;
 import javafx.scene.Cursor;
 import javafx.scene.Node;
+import javafx.scene.control.ResizeFeaturesBase;
 import javafx.scene.control.TableColumnBase;
 import javafx.scene.control.TableView;
+import javafx.scene.control.TreeTableView;
 import javafx.scene.input.MouseEvent;
 import javafx.scene.paint.Color;
 import javafx.scene.shape.Rectangle;
+import javafx.util.Callback;
 
 /**
  * <p>This class is used to construct the header of a TableView. We take the approach
@@ -145,7 +148,9 @@
             if (me.getClickCount() == 2 && me.isPrimaryButtonDown()) {
                 // the user wants to resize the column such that its
                 // width is equal to the widest element in the column
-                header.getTableViewSkin().resizeColumnToFitContent(column, -1);
+                if (column.isResizable()) {
+                    header.getTableViewSkin().resizeColumnToFitContent(column, -1);
+                }
             } else {
                 // rather than refer to the rect variable, we just grab
                 // it from the source to prevent a small memory leak.
@@ -308,7 +313,7 @@
         if (getColumns() != null) {
             getColumns().removeListener(weakColumnsListener);
         }
-        
+
         for (int i = 0; i < getColumnHeaders().size(); i++) {
             TableColumnHeader header = getColumnHeaders().get(i);
             header.dispose();
@@ -468,20 +473,32 @@
             rect.visibleProperty().unbind();
         }
         dragRects.clear();
-        
-        if (getColumns() == null) {
+
+        List<? extends TableColumnBase> columns = getColumns();
+
+        if (columns == null) {
             return;
         }
 
-        boolean isConstrainedResize = TableView.CONSTRAINED_RESIZE_POLICY.equals(
-                getTableViewSkin().columnResizePolicyProperty());
-        
-        for (int col = 0; col < getColumns().size(); col++) {
+        final TableViewSkinBase<?,?,?,?,?,?> skin = getTableViewSkin();
+        Callback<ResizeFeaturesBase, Boolean> columnResizePolicy = skin.columnResizePolicyProperty().get();
+        boolean isConstrainedResize =
+                skin instanceof TableViewSkin ? TableView.CONSTRAINED_RESIZE_POLICY.equals(columnResizePolicy) :
+                skin instanceof TreeTableViewSkin ? TreeTableView.CONSTRAINED_RESIZE_POLICY.equals(columnResizePolicy) :
+                false;
+
+        // RT-32547 - don't show resize cursor when in constrained resize mode
+        // and there is only one column
+        if (isConstrainedResize && skin.getVisibleLeafColumns().size() == 1) {
+            return;
+        }
+
+        for (int col = 0; col < columns.size(); col++) {
             if (isConstrainedResize && col == getColumns().size() - 1) {
                 break;
             }
-            
-            final TableColumnBase c = getColumns().get(col);
+
+            final TableColumnBase c = columns.get(col);
             final Rectangle rect = new Rectangle();
             rect.getProperties().put(TABLE_COLUMN_KEY, c);
             rect.getProperties().put(TABLE_COLUMN_HEADER_KEY, this);
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/ScrollPaneSkin.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/ScrollPaneSkin.java	Mon Nov 18 22:06:51 2013 -0800
@@ -271,9 +271,12 @@
             @Override public void requestLayout() {
                 // if scrollNode requested layout, will want to recompute
                 nodeSizeInvalid = true;
-                updateVerticalSB();
-                updateHorizontalSB();
+
                 super.requestLayout(); // add as layout root for next layout pass
+
+                // Need to layout the ScrollPane as well in case scrollbars
+                // appeared or disappeared.
+                ScrollPaneSkin.this.getSkinnable().requestLayout();
             }
             @Override protected void layoutChildren() {
                 if (nodeSizeInvalid) {
@@ -930,6 +933,7 @@
                 nodeWidth = snapSize(scrollNode.getLayoutBounds().getWidth());
                 nodeHeight = snapSize(scrollNode.getLayoutBounds().getHeight());
             }
+            nodeSizeInvalid = false;
         }
     }
 
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/TextAreaSkin.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/TextAreaSkin.java	Mon Nov 18 22:06:51 2013 -0800
@@ -707,7 +707,7 @@
                         // Swap caret and anchor
                         textArea.selectRange(textArea.getCaretPosition(), textArea.getAnchor());
                     }
-                    if (pos >= 0) {
+                    if (pos > 0) {
                         if (pos >= textArea.getAnchor()) {
                             pos = textArea.getAnchor();
                         }
@@ -718,8 +718,8 @@
                             hit.setCharIndex(pos - 1);
                         }
                         textNode.setImpl_caretPosition(oldPos);
-                        positionCaret(hit, true, false);
                     }
+                    positionCaret(hit, true, false);
                     e.consume();
                 }
             });
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/Utils.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/Utils.java	Mon Nov 18 22:06:51 2013 -0800
@@ -30,6 +30,7 @@
 
 package com.sun.javafx.scene.control.skin;
 
+import java.text.Bidi;
 import java.text.BreakIterator;
 
 import static javafx.scene.control.OverrunStyle.*;
@@ -210,7 +211,7 @@
                 // RT-23458: Use a faster algorithm for the most common case
                 // where truncation happens at the end, i.e. for ELLIPSIS and
                 // CLIP, but not for other cases such as WORD_ELLIPSIS, etc.
-                if (style == ELLIPSIS) {
+                if (style == ELLIPSIS && !new Bidi(text, Bidi.DIRECTION_LEFT_TO_RIGHT).isMixed()) {
                     int hit = computeTruncationIndex(font, text, width - ellipsisWidth);
                     if (hit < 0 || hit >= text.length()) {
                         return text;
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/VirtualFlow.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/VirtualFlow.java	Mon Nov 18 22:06:51 2013 -0800
@@ -1678,7 +1678,6 @@
             Callback<VirtualFlow,T> createCell = getCreateCell();
             if (createCell != null) {
                 accumCell = createCell.call(this);
-                accumCell.getProperties().put(NEW_CELL, null);
                 accumCellParent.getChildren().setAll(accumCell);
             }
         }
@@ -1786,10 +1785,13 @@
         assert cell != null;
 
         cell.updateIndex(index);
-        
-        if (cell.isNeedsLayout() && cell.getScene() != null && cell.getProperties().containsKey(NEW_CELL)) {
+
+        // make sure the cell is sized correctly. This is important for both
+        // general layout of cells in a VirtualFlow, but also in cases such as
+        // RT-34333, where the sizes were being reported incorrectly to the
+        // ComboBox popup.
+        if (cell.isNeedsLayout() && cell.getScene() != null) {
             cell.impl_processCSS(false);
-            cell.getProperties().remove(NEW_CELL);
         }
     }
 
@@ -1800,13 +1802,6 @@
      **************************************************************************/
 
     /**
-     * Indicates that this is a newly created cell and we need call impl_processCSS for it.
-     * 
-     * See RT-23616 for more details.
-     */
-    private static final String NEW_CELL = "newcell";
-    
-    /**
      * Get a cell which can be used in the layout. This function will reuse
      * cells from the pile where possible, and will create new cells when
      * necessary.
@@ -1855,7 +1850,6 @@
                 }
             } else {
                 cell = getCreateCell().call(this);
-                cell.getProperties().put(NEW_CELL, null);
             }
         }
 
--- a/modules/controls/src/main/java/javafx/scene/control/TreeTableView.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/controls/src/main/java/javafx/scene/control/TreeTableView.java	Mon Nov 18 22:06:51 2013 -0800
@@ -1237,19 +1237,19 @@
      * order list contains the columns that have been added to it either programmatically
      * or via a user clicking on the headers themselves.
      */
-    private ReadOnlyObjectWrapper<Comparator<S>> comparator;
-    private void setComparator(Comparator<S> value) {
+    private ReadOnlyObjectWrapper<Comparator<TreeItem<S>>> comparator;
+    private void setComparator(Comparator<TreeItem<S>> value) {
         comparatorPropertyImpl().set(value);
     }
-    public final Comparator<S> getComparator() {
+    public final Comparator<TreeItem<S>> getComparator() {
         return comparator == null ? null : comparator.get();
     }
-    public final ReadOnlyObjectProperty<Comparator<S>> comparatorProperty() {
+    public final ReadOnlyObjectProperty<Comparator<TreeItem<S>>> comparatorProperty() {
         return comparatorPropertyImpl().getReadOnlyProperty();
     }
-    private ReadOnlyObjectWrapper<Comparator<S>> comparatorPropertyImpl() {
+    private ReadOnlyObjectWrapper<Comparator<TreeItem<S>>> comparatorPropertyImpl() {
         if (comparator == null) {
-            comparator = new ReadOnlyObjectWrapper<Comparator<S>>(this, "comparator");
+            comparator = new ReadOnlyObjectWrapper<>(this, "comparator");
         }
         return comparator;
     }
@@ -1596,11 +1596,11 @@
         final ObservableList<TreeTableColumn<S,?>> sortOrder = getSortOrder();
         
         // update the Comparator property
-        final Comparator<S> oldComparator = getComparator();
+        final Comparator<TreeItem<S>> oldComparator = getComparator();
         if (sortOrder.isEmpty()) {
             setComparator(null);
         } else {
-            Comparator<S> newComparator = new TableColumnComparatorBase.TreeTableColumnComparator(sortOrder);
+            Comparator<TreeItem<S>> newComparator = new TableColumnComparatorBase.TreeTableColumnComparator(sortOrder);
             setComparator(newComparator);
         }
         
--- a/modules/controls/src/test/java/javafx/scene/control/ComboBoxTest.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/controls/src/test/java/javafx/scene/control/ComboBoxTest.java	Mon Nov 18 22:06:51 2013 -0800
@@ -1083,4 +1083,23 @@
             fail("Stack overflow should not happen here");
         }
     }
+
+    @Test public void test_rt21186() {
+        final ComboBox<String> comboBox = new ComboBox<>();
+        comboBox.setEditable(true);
+
+        new StageLoader(comboBox);
+
+        assertNull(comboBox.getTooltip());
+        assertNull(comboBox.getEditor().getTooltip());
+
+        Tooltip tooltip = new Tooltip("Tooltip");
+        comboBox.setTooltip(tooltip);
+        assertEquals(tooltip, comboBox.getTooltip());
+        assertEquals(tooltip, comboBox.getEditor().getTooltip());
+
+        comboBox.setTooltip(null);
+        assertNull(comboBox.getTooltip());
+        assertNull(comboBox.getEditor().getTooltip());
+    }
 }
--- a/modules/controls/src/test/java/javafx/scene/control/TableViewKeyInputTest.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/controls/src/test/java/javafx/scene/control/TableViewKeyInputTest.java	Mon Nov 18 22:06:51 2013 -0800
@@ -51,7 +51,6 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
-//@Ignore("Disabling tests as they fail with OOM in continuous builds")
 public class TableViewKeyInputTest {
     private TableView<String> tableView;
     private TableView.TableViewSelectionModel<String> sm;
--- a/modules/controls/src/test/java/javafx/scene/control/TreeTableViewKeyInputTest.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/controls/src/test/java/javafx/scene/control/TreeTableViewKeyInputTest.java	Mon Nov 18 22:06:51 2013 -0800
@@ -52,7 +52,6 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
-//@Ignore("Disabling tests as they fail with OOM in continuous builds")
 public class TreeTableViewKeyInputTest {
     private TreeTableView<String> tableView;
     private TreeTableView.TreeTableViewSelectionModel<String> sm;
--- a/modules/controls/src/test/java/javafx/scene/control/TreeTableViewTest.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/controls/src/test/java/javafx/scene/control/TreeTableViewTest.java	Mon Nov 18 22:06:51 2013 -0800
@@ -28,12 +28,7 @@
 import static com.sun.javafx.scene.control.infrastructure.ControlTestUtils.assertStyleClassContains;
 import static javafx.scene.control.TreeTableColumn.SortType.ASCENDING;
 import static javafx.scene.control.TreeTableColumn.SortType.DESCENDING;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
 
 import java.util.Comparator;
 import java.util.List;
@@ -2657,4 +2652,56 @@
         treeTableView.edit(0, col);
         assertEquals(1, rt_29849_start_count);
     }
+
+    @Test public void test_rt_34327() {
+        // by default the comparator is null.
+        // NOTE: this method (prior to the fix as part of RT-34327) would have
+        // returned Comparator<String>, but after the fix it correctly returns
+        // a Comparator<TreeItem<String>>
+        Comparator nonGenericComparator = treeTableView.getComparator();
+        Comparator<TreeItem<String>> genericComparator = treeTableView.getComparator();
+        assertNull(nonGenericComparator);
+        assertNull(genericComparator);
+
+        // add in a column and some data
+        TreeTableColumn<String, String> col = new TreeTableColumn<>("column");
+        col.setEditable(true);
+        col.setCellValueFactory(new Callback<TreeTableColumn.CellDataFeatures<String, String>, ObservableValue<String>>() {
+            @Override public ObservableValue<String> call(TreeTableColumn.CellDataFeatures<String, String> param) {
+                return new ReadOnlyObjectWrapper<>(param.getValue().getValue());
+            }
+        });
+        treeTableView.getColumns().add(col);
+
+        installChildren();
+
+        // sort by that column
+        treeTableView.getSortOrder().add(col);
+
+        // get the new comparator, which should no longer be null
+        nonGenericComparator = treeTableView.getComparator();
+        genericComparator = treeTableView.getComparator();
+        assertNotNull(nonGenericComparator);
+        assertNotNull(genericComparator);
+
+        // now, as noted above, previously we would use the Comparator to compare
+        // two String instances, which would fail at runtime as the Comparator
+        // was actually expecting to compare two TreeItem<String>, but the API
+        // was failing us.
+        try {
+            nonGenericComparator.compare("abc", "def");
+            fail("This should not work!");
+        } catch (ClassCastException e) {
+            // if we get the exception, we're happy
+        }
+
+        try {
+            Object string1 = "abc";
+            Object string2 = "def";
+            genericComparator.compare((TreeItem<String>)string1, (TreeItem<String>)string2);
+            fail("This should not work!");
+        } catch (ClassCastException e) {
+            // if we get the exception, we're happy
+        }
+    }
 }
--- a/modules/fxml/src/main/java/javafx/fxml/FXMLLoader.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/fxml/src/main/java/javafx/fxml/FXMLLoader.java	Mon Nov 18 22:06:51 2013 -0800
@@ -50,7 +50,6 @@
 import java.util.Set;
 import java.util.regex.Pattern;
 
-import com.sun.javafx.fxml.*;
 import javafx.beans.DefaultProperty;
 import javafx.beans.property.Property;
 import javafx.beans.value.ChangeListener;
@@ -75,6 +74,10 @@
 import javax.xml.stream.util.StreamReaderDelegate;
 
 import com.sun.javafx.beans.IDProperty;
+import com.sun.javafx.fxml.BeanAdapter;
+import com.sun.javafx.fxml.LoadListener;
+import com.sun.javafx.fxml.ParseTraceElement;
+import com.sun.javafx.fxml.PropertyNotFoundException;
 import com.sun.javafx.fxml.expression.Expression;
 import com.sun.javafx.fxml.expression.ExpressionValue;
 import com.sun.javafx.fxml.expression.KeyPath;
--- a/modules/fxpackager/src/main/java/com/sun/javafx/tools/ant/FXJar.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/fxpackager/src/main/java/com/sun/javafx/tools/ant/FXJar.java	Mon Nov 18 22:06:51 2013 -0800
@@ -115,8 +115,6 @@
         checkAttributesAndElements();
 
         createJarParams.setCss2bin(css2bin);
-        //always embed JavaFX launcher
-        createJarParams.setEmbedLauncher(true);
 
         if (app != null) {
            createJarParams.setApplicationClass(app.get().mainClass);
--- a/modules/fxpackager/src/main/java/com/sun/javafx/tools/packager/CreateJarParams.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/fxpackager/src/main/java/com/sun/javafx/tools/packager/CreateJarParams.java	Mon Nov 18 22:06:51 2013 -0800
@@ -78,6 +78,12 @@
         this.css2bin = css2bin;
     }
 
+    /**
+     * In JKD8/FX8 launcher is never embedded,
+     * app must use main to call Application launcher()
+     * @deprecated
+     * @param embedLauncher
+     */
     public void setEmbedLauncher(boolean embedLauncher) {
         this.embedLauncher = embedLauncher;
     }
@@ -109,7 +115,7 @@
         return "CreateJarParams{" + "applicationClass=" + applicationClass
                 + " preloader=" + preloader + " classpath=" + classpath
                 + " manifestAttrs=" + manifestAttrs
-                + " embedLauncher=" + embedLauncher + " css2bin=" + css2bin
+                + " embedLauncher=deprecated" + " css2bin=" + css2bin
                 + " outfile=" + outfile + " sdkHome=" + fxVersion + '}'
                 + "            CommonParams{" + "outdir=" + outdir
                 + " verbose=" + verbose + " resources=" + resources + '}';
--- a/modules/fxpackager/src/main/java/com/sun/javafx/tools/packager/Main.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/fxpackager/src/main/java/com/sun/javafx/tools/packager/Main.java	Mon Nov 18 22:06:51 2013 -0800
@@ -193,7 +193,7 @@
                         } else if (arg.equalsIgnoreCase("-manifestAttrs")) {
                             createJarParams.setManifestAttrs(createAttrMap(nextArg(args, i++)));
                         } else if (arg.equalsIgnoreCase("-noembedlauncher")) {
-                            createJarParams.setEmbedLauncher(false);
+                            System.out.println("-noembedlauncher is deprecated");
                         } else if (arg.equalsIgnoreCase("-nocss2bin")) {
                             createJarParams.setCss2bin(false);
                         } else if (arg.equalsIgnoreCase("-runtimeVersion")) {
--- a/modules/fxpackager/src/main/java/com/sun/javafx/tools/packager/PackagerLib.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/fxpackager/src/main/java/com/sun/javafx/tools/packager/PackagerLib.java	Mon Nov 18 22:06:51 2013 -0800
@@ -105,16 +105,9 @@
     private File bssTmpDir;
     private boolean isSignedJNLP;
 
+
     private enum Filter {ALL, CLASSES_ONLY, RESOURCES};
 
-    private static String[] launcherFiles = {
-        "com/javafx/main/Main.class",
-        "com/javafx/main/Main$1.class",
-        "com/javafx/main/Main$2.class",
-        "com/javafx/main/NoJavaFXFallback.class"
-    };
-    private static String prefix_in_antjar = "/resources/classes/";
-
     private ClassLoader classLoader;
 
     private ClassLoader getClassLoader() throws PackagerException {
@@ -251,60 +244,46 @@
                 attr.put(new Attributes.Name(e.getKey()), e.getValue());
             }
         }
-        if (createJarParams.embedLauncher) {
-            //Reset Classpath (make sense if we are updating jar)
-            attr.remove(Attributes.Name.CLASS_PATH);
 
-            attr.put(Attributes.Name.MAIN_CLASS, "com/javafx/main/Main");
-            attr.put(new Attributes.Name(MANIFEST_JAVAFX_MAIN), createJarParams.applicationClass);
-            attr.put(new Attributes.Name("JavaFX-Version"), createJarParams.fxVersion);
+        attr.put(Attributes.Name.MAIN_CLASS, createJarParams.applicationClass);
+        if (createJarParams.classpath != null) {
+            // Allow comma or semicolon as delimeter (turn them into spaces)
+            String cp = createJarParams.classpath;
+            cp = cp.replace(';', ' ').replace(',', ' ');
+            attr.put(new Attributes.Name("Class-Path"), cp);
+        }
 
-            if (createJarParams.preloader != null) {
-                attr.put(new Attributes.Name("JavaFX-Preloader-Class"), createJarParams.preloader);
+        attr.put(new Attributes.Name("JavaFX-Version"), createJarParams.fxVersion);
+
+        if (createJarParams.preloader != null) {
+            attr.put(new Attributes.Name("JavaFX-Preloader-Class"), createJarParams.preloader);
+        }
+
+
+        if (createJarParams.arguments != null) {
+            int idx = 1;
+            for (String arg: createJarParams.arguments) {
+                attr.put(new Attributes.Name("JavaFX-Argument-"+idx),
+                        encodeAsBase64(arg.getBytes()));
+                idx++;
             }
-
-            if (createJarParams.classpath != null) {
-                // Allow comma or semicolon as delimeter (turn them into spaces)
-                String cp = createJarParams.classpath;
-                cp = cp.replace(';', ' ').replace(',', ' ');
-                attr.put(new Attributes.Name("JavaFX-Class-Path"), cp);
-            }
-            //Default fallback class uses "private" interface to
-            // get additional error paramters. Do not add it to manifest
-            // explicitly to avoid treating it as custom
-            if (createJarParams.fallbackClass != null &&
-                    !createJarParams.defaultFallbackApp.equals(
-                    createJarParams.fallbackClass)) {
-                attr.put(new Attributes.Name("JavaFX-Fallback-Class"),
-                        createJarParams.fallbackClass);
-            }
-
-            if (createJarParams.arguments != null) {
-                int idx = 1;
-                for (String arg: createJarParams.arguments) {
-                    attr.put(new Attributes.Name("JavaFX-Argument-"+idx),
-                            encodeAsBase64(arg.getBytes()));
+        }
+        if (createJarParams.params != null) {
+            int idx = 1;
+            for (Param p : createJarParams.params) {
+                if (p.name != null) { //otherwise it is something weird and we skip it
+                    attr.put(new Attributes.Name("JavaFX-Parameter-Name-" + idx),
+                            encodeAsBase64(p.name.getBytes()));
+                    if (p.value != null) { //legal, means not value specified
+                        attr.put(new Attributes.Name("JavaFX-Parameter-Value-" + idx),
+                                encodeAsBase64(p.value.getBytes()));
+                    }
                     idx++;
                 }
             }
-            if (createJarParams.params != null) {
-                int idx = 1;
-                for (Param p : createJarParams.params) {
-                    if (p.name != null) { //otherwise it is something weird and we skip it
-                        attr.put(new Attributes.Name("JavaFX-Parameter-Name-" + idx),
-                                encodeAsBase64(p.name.getBytes()));
-                        if (p.value != null) { //legal, means not value specified
-                            attr.put(new Attributes.Name("JavaFX-Parameter-Value-" + idx),
-                                    encodeAsBase64(p.value.getBytes()));
-                        }
-                        idx++;
-                    }
-                }
-            }
-        } else {
-            attr.put(Attributes.Name.MAIN_CLASS, createJarParams.applicationClass);
         }
 
+
         if (createJarParams.css2bin) {
             try {
                 bssTmpDir = File.createTempFile("bssfiles", "");
@@ -1404,9 +1383,6 @@
                             pr.getBaseDir().getAbsolutePath().length() + 1);
                 }
             }
-            if (createJarParams.embedLauncher) {
-                addEmbeddedLauncher(jar);
-            }
         } finally {
             jar.close();
             alreadyAddedEntries.clear();
@@ -1429,30 +1405,6 @@
         }
     }
 
-    private void addEmbeddedLauncher(JarOutputStream jar) throws IOException {
-        for (String cls : launcherFiles) {
-            String nm = prefix_in_antjar + cls;
-            InputStream in = PackagerLib.class.getResourceAsStream(nm);
-            if (in == null) {
-                System.err.println(
-                        "Internal error. Missing embedded resource [" + cls + "]");
-            }
-            jar.putNextEntry(new JarEntry(cls));
-
-            byte b[] = new byte[65000];
-            int i;
-            try {
-                while ((i = in.read(b)) > 0) {
-                    jar.write(b, 0, i);
-                }
-            } finally {
-                in.close();
-            }
-
-            jar.closeEntry();
-        }
-    }
-
     //add everything but manifest from given jar file
     private void copyFromOtherJar(JarOutputStream jar, File inputFile) throws IOException {
         JarFile inJar = new JarFile(inputFile);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/graphics/src/main/java/com/sun/javafx/embed/EmbeddedSceneDSInterface.java	Mon Nov 18 22:06:51 2013 -0800
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2010, 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 com.sun.javafx.embed;
+
+import java.util.Set;
+
+import javafx.scene.input.TransferMode;
+
+/**
+ * Drag source interface. There are two implementations:
+ *   - EmbeddedSceneDS, which is used, when FX scene inside JFXPanel/FXCanvas is a drag source
+ *   - SwingDragSource, which is used for external drag sources
+ */
+public interface EmbeddedSceneDSInterface {
+
+    public Set<TransferMode> getSupportedActions();
+
+    public Object getData(String mimeType);
+
+    public String[] getMimeTypes();
+
+    public boolean isMimeTypeAvailable(String mimeType);
+
+    public void dragDropEnd(TransferMode performedAction);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/graphics/src/main/java/com/sun/javafx/embed/EmbeddedSceneDTInterface.java	Mon Nov 18 22:06:51 2013 -0800
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2010, 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 com.sun.javafx.embed;
+
+import javafx.scene.input.TransferMode;
+
+/**
+ * Embedded FX drop target.
+ */
+public interface EmbeddedSceneDTInterface {
+
+    public TransferMode handleDragEnter(int x, int y, int xAbs, int yAbs,
+                                        TransferMode recommendedDropAction,
+                                        EmbeddedSceneDSInterface dragSource);
+
+    public void handleDragLeave();
+
+    public TransferMode handleDragDrop(int x, int y, int xAbs, int yAbs,
+                                       TransferMode recommendedDropAction);
+
+    public TransferMode handleDragOver(int x, int y, int xAbs, int yAbs,
+                                       TransferMode recommendedDropAction);
+}
--- a/modules/graphics/src/main/java/com/sun/javafx/embed/EmbeddedSceneDragSourceInterface.java	Thu Nov 14 10:49:15 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2010, 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 com.sun.javafx.embed;
-
-import java.util.Set;
-
-import javafx.scene.input.TransferMode;
-
-/**
- * Embedded FX drag source.
- */
-public interface EmbeddedSceneDragSourceInterface {
-
-    public Set<TransferMode> getSupportedActions();
-
-    public Object getData(String mimeType);
-
-    public String[] getMimeTypes();
-
-    public boolean isMimeTypeAvailable(String mimeType);
-
-    public void dragDropEnd(TransferMode performedAction);
-}
--- a/modules/graphics/src/main/java/com/sun/javafx/embed/EmbeddedSceneDragStartListenerInterface.java	Thu Nov 14 10:49:15 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) 2012, 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 com.sun.javafx.embed;
-
-import javafx.scene.input.TransferMode;
-
-public interface EmbeddedSceneDragStartListenerInterface {
-    public void dragStarted(EmbeddedSceneDragSourceInterface dragSource,
-                            TransferMode dragAction);
-}
--- a/modules/graphics/src/main/java/com/sun/javafx/embed/EmbeddedSceneDropTargetInterface.java	Thu Nov 14 10:49:15 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2010, 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 com.sun.javafx.embed;
-
-import javafx.scene.input.TransferMode;
-
-/**
- * Embedded FX drop target.
- */
-public interface EmbeddedSceneDropTargetInterface {
-
-    public TransferMode handleDragEnter(int x, int y, int xAbs, int yAbs,
-                                        TransferMode recommendedDropAction,
-                                        EmbeddedSceneDragSourceInterface dragSource);
-
-    public void handleDragLeave();
-
-    public TransferMode handleDragDrop(int x, int y, int xAbs, int yAbs,
-                                       TransferMode recommendedDropAction);
-
-    public TransferMode handleDragOver(int x, int y, int xAbs, int yAbs,
-                                       TransferMode recommendedDropAction);
-}
--- a/modules/graphics/src/main/java/com/sun/javafx/embed/EmbeddedSceneInterface.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/java/com/sun/javafx/embed/EmbeddedSceneInterface.java	Mon Nov 18 22:06:51 2013 -0800
@@ -78,9 +78,9 @@
     
     public boolean traverseOut(Direction dir);
 
-    public void setDragStartListener(EmbeddedSceneDragStartListenerInterface l);
+    public void setDragStartListener(HostDragStartListener l);
 
-    public EmbeddedSceneDropTargetInterface createDropTarget();
+    public EmbeddedSceneDTInterface createDropTarget();
 
     public void inputMethodEvent(EventType<InputMethodEvent> type,
                                  ObservableList<InputMethodTextRun> composed, String committed,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/graphics/src/main/java/com/sun/javafx/embed/HostDragStartListener.java	Mon Nov 18 22:06:51 2013 -0800
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012, 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 com.sun.javafx.embed;
+
+import javafx.scene.input.TransferMode;
+
+/*
+ * Interface, which is implemented by the host UI toolkit to track,
+ * when DnD is started in embedded FX scene.
+ */
+public interface HostDragStartListener {
+    public void dragStarted(EmbeddedSceneDSInterface dragSource, TransferMode dragAction);
+}
--- a/modules/graphics/src/main/java/com/sun/javafx/scene/traversal/Hueristic2D.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/java/com/sun/javafx/scene/traversal/Hueristic2D.java	Mon Nov 18 22:06:51 2013 -0800
@@ -38,6 +38,8 @@
 import sun.util.logging.PlatformLogger.Level;
 
 import static com.sun.javafx.scene.traversal.Direction.*;
+import java.util.function.Function;
+import javafx.geometry.Bounds;
 
 
 public class Hueristic2D implements Algorithm {
@@ -48,9 +50,9 @@
         focusLogger = Logging.getFocusLogger();
     }
 
+    @Override
     public Node traverse(Node node, Direction dir, TraversalEngine engine) {
         Node newNode = null;
-        int newNodeIndex = -1;
 
         cacheTraversal(node, dir, engine);
 
@@ -78,22 +80,17 @@
             }
 
             Bounds currentB = node.localToScene(node.getLayoutBounds());
-            BoundingBox bb = null;
 
             if (cacheStartTraversalNode != null) {
                 Bounds cachedB = cacheStartTraversalNode.localToScene(cacheStartTraversalNode.getLayoutBounds());
                 switch (dir) {
                 case UP:
-                    newNode = getNearestNodeUp(currentB, cachedB, engine, node, newNode);
-                    break;
                 case DOWN:
-                    newNode = getNearestNodeDown(currentB, cachedB, engine, node, newNode);
+                    newNode = getNearestNodeUpOrDown(currentB, cachedB, engine, node, newNode, dir);
                     break;
                 case LEFT:
-                    newNode = getNearestNodeLeft(currentB, cachedB, engine, node, newNode);
-                    break;
                 case RIGHT:
-                    newNode = getNearestNodeRight(currentB, cachedB, engine, node, newNode);
+                    newNode = getNearestNodeLeftOrRight(currentB, cachedB, engine, node, newNode, dir);
                     break;
                 default:
                     break;
@@ -182,10 +179,6 @@
         return newNode;
     }
 
-    private Node findNextParent(Node node) {
-        return null;
-    }
-
     private Node findNextFocusableInList(List<Node> nodeList, int startIndex) {
         Node newNode = null;
 
@@ -296,10 +289,6 @@
         return parentNodes;
     }
 
-    private static Parent getParent(Node child) {
-        return (child.getParent() instanceof Group) ? (child.getParent().getParent()) : (child.getParent());
-    }
-
     private boolean isOnAxis(Direction dir, Bounds cur, Bounds tgt) {
 
         final double cmin, cmax, tmin, tmax;
@@ -413,8 +402,7 @@
         if (dir == Direction.NEXT || dir == Direction.PREVIOUS) {
             traversalNodeStack.clear();
             reverseDirection = false;
-        }
-        else {
+        } else {
             if (cacheStartTraversalNode == null || dir != cacheStartTraversalDirection) {
 
                 if ((dir == UP && cacheStartTraversalDirection == DOWN) ||
@@ -422,10 +410,9 @@
                     (dir == LEFT && cacheStartTraversalDirection == RIGHT) ||
                     (dir == RIGHT && cacheStartTraversalDirection == LEFT) && !traversalNodeStack.empty()) {
                     reverseDirection = true;
-                }
-                else {
+                } else {
                     /*
-                    ** if we don't have a row set, or the direction has changed, then
+                     ** if we don't have a row set, or the direction has changed, then
                     ** make the current node the row.
                     ** otherwise we are moving in the same direction as last time, so
                     ** we'll just leave it alone.
@@ -435,8 +422,7 @@
                     reverseDirection = false;
                     traversalNodeStack.clear();
                 }
-            }
-            else {
+            } else {
                 /*
                 ** we're going this way again!
                 */
@@ -444,610 +430,131 @@
             }
         }
     }
+    
+    private static final Function<Bounds, Double> BOUNDS_TOP_SIDE = new Function<Bounds, Double>() {
 
-    protected Node getNearestNodeUp(Bounds currentB, Bounds originB, TraversalEngine engine, Node node, Node reversingNode) {
+        @Override
+        public Double apply(Bounds t) {
+            return t.getMinY();
+        }
+    };
+
+    private static final Function<Bounds, Double> BOUNDS_BOTTOM_SIDE = new Function<Bounds, Double>() {
+
+        @Override
+        public Double apply(Bounds t) {
+            return t.getMaxY();
+        }
+    };
+
+    protected Node getNearestNodeUpOrDown(Bounds currentB, Bounds originB, TraversalEngine engine, Node node, Node reversingNode, Direction dir) {
 
         List<Node> nodes = engine.getAllTargetNodes();
-
+        
+        Function<Bounds, Double> ySideInDirection = dir == DOWN ? BOUNDS_BOTTOM_SIDE : BOUNDS_TOP_SIDE;
+        Function<Bounds, Double> ySideInOpositeDirection = dir == DOWN ? BOUNDS_TOP_SIDE : BOUNDS_BOTTOM_SIDE;
+        
         Bounds biasedB = new BoundingBox(originB.getMinX(), currentB.getMinY(), originB.getWidth(), currentB.getHeight());
 
         Point2D currentMid2D = new Point2D(currentB.getMinX()+(currentB.getWidth()/2), currentB.getMinY());
-        Point2D currentTopLeft2D = new Point2D(currentB.getMinX(), currentB.getMinY());
-        Point2D currentTopRight2D = new Point2D(currentB.getMaxX(), currentB.getMinY());
+        Point2D currenLeftCorner2D = new Point2D(currentB.getMinX(),ySideInDirection.apply(currentB));
+        Point2D currentRightCorner2D = new Point2D(currentB.getMaxX(), ySideInDirection.apply(currentB));
 
-        Point2D originTopLeft2D = new Point2D(originB.getMinX(), originB.getMinY());
+        Point2D originLeftCorner2D = new Point2D(originB.getMinX(), ySideInDirection.apply(originB));
 
-        TargetNode reversingTargetNode = null;
         TargetNode targetNode = new TargetNode();
         TargetNode nearestNodeCurrentSimple2D = null;
         TargetNode nearestNodeOriginSimple2D = null;
-        TargetNode nearestNodeAverageUp = null;
+        TargetNode nearestNodeAverage = null;
         TargetNode nearestNodeOnOriginX = null;
         TargetNode nearestNodeOnCurrentX = null;
-        TargetNode nearestNodeTopLeft = null;
-        TargetNode nearestNodeAnythingAnywhereUp = null;
+        TargetNode nearestNodeLeft = null;
+        TargetNode nearestNodeAnythingAnywhere = null;
 
         if (nodes.size() > 0) {
-            int nodeIndex;
+            /*
+             ** we've just changed direction, and have a node on stack.
+             ** there is a strong preference for this node, just make sure
+             ** it's not a bad choice, as sometimes we got here as a last-chance
+             */
+            if (reversingNode != null) {
+                return reversingNode;
+            }
+            
+            for (int nodeIndex = 0; nodeIndex < nodes.size(); nodeIndex++) {
+                final Node n = nodes.get(nodeIndex);
 
-            if (reversingNode != null) {
-                Bounds targetBounds = reversingNode.localToScene(reversingNode.getLayoutBounds());
-                reversingTargetNode = new TargetNode();
+                Bounds targetBounds = n.localToScene(n.getLayoutBounds());
+                /*
+                ** check that the target node starts after we 
+                ** and the target node ends after we end
+                */
+                if (dir == UP ? (currentB.getMinY() > targetBounds.getMaxY()) :
+                        currentB.getMaxY() < targetBounds.getMinY()) {
 
-                reversingTargetNode.node = reversingNode;
-                reversingTargetNode.bounds = targetBounds;
-
-                /*
-                ** closest biased : simple 2d
-                */
-                double outdB = outDistance(Direction.UP, biasedB, targetBounds);
-
-                if (isOnAxis(Direction.UP, biasedB, targetBounds)) {
-                    reversingTargetNode.biased2DMetric = outdB + centerSideDistance(Direction.UP, biasedB, targetBounds) / 100;
-                }
-                else {
-                    final double cosd = cornerSideDistance(Direction.UP, biasedB, targetBounds);
-                    reversingTargetNode.biased2DMetric = 100000 + outdB*outdB + 9*cosd*cosd;
-                }
-
-                /*
-                ** closest current : simple 2d
-                */
-                double outdC = outDistance(Direction.UP, currentB, targetBounds);
-
-                if (isOnAxis(Direction.UP, currentB, targetBounds)) {
-                    reversingTargetNode.current2DMetric = outdC + centerSideDistance(Direction.UP, currentB, targetBounds) / 100;
-                }
-                else {
-                    final double cosd = cornerSideDistance(Direction.UP, currentB, targetBounds);
-                    reversingTargetNode.current2DMetric = 100000 + outdC*outdC + 9*cosd*cosd;
-                }
-
-
-                reversingTargetNode.bottomLeftDistance = currentTopLeft2D.distance(targetBounds.getMinX(), targetBounds.getMaxY());
-                reversingTargetNode.midDistance = currentMid2D.distance(targetBounds.getMinX()+(originB.getWidth()/2), targetBounds.getMaxY());
-                reversingTargetNode.bottomRightDistance = currentTopRight2D.distance(originB.getMaxX(), targetBounds.getMaxY());
-
-                double currentTopLeftToTargetMidDistance = currentTopLeft2D.distance(targetBounds.getMinX()+(targetBounds.getWidth()/2), targetBounds.getMaxY());
-                double currentTopLeftToTargetBottomRightDistance = currentTopLeft2D.distance(targetBounds.getMaxX(), targetBounds.getMaxY());
-                double currentTopRightToTargetBottomLeftDistance = currentTopRight2D.distance(targetBounds.getMinX(), targetBounds.getMaxY());
-                double currentTopRightToTargetMidDistance = currentTopRight2D.distance(targetBounds.getMinX()+(targetBounds.getWidth()/2), targetBounds.getMaxY());
-                double currentTopRightToTargetBottomRightDistance = currentTopRight2D.distance(targetBounds.getMaxX(), targetBounds.getMaxY());
-                double currentMidToTargetBottomLeftDistance = currentMid2D.distance(targetBounds.getMinX(), targetBounds.getMaxY());
-                double currentMidToTargetMidDistance = currentMid2D.distance(targetBounds.getMinX()+(targetBounds.getWidth()/2), targetBounds.getMaxY());
-                double currentMidToTargetBottomRightDistance = currentMid2D.distance(targetBounds.getMaxX(), targetBounds.getMaxY());
-
-                double biasTopLeftToTargetMidDistance = currentTopLeft2D.distance(targetBounds.getMinX()+(originB.getWidth()/2), targetBounds.getMaxY());
-                double biasTopLeftToTargetBottomRightDistance = currentTopLeft2D.distance(originB.getMaxX(), targetBounds.getMaxY());
-                double biasTopRightToTargetMidDistance = currentTopRight2D.distance(targetBounds.getMinX()+(originB.getWidth()/2), targetBounds.getMaxY());
-                double biasMidToTargetBottomRightDistance = currentMid2D.distance(originB.getMaxX(), targetBounds.getMaxY());
-
-                reversingTargetNode.averageDistance =
-                    (reversingTargetNode.bottomLeftDistance+biasTopLeftToTargetMidDistance+biasTopLeftToTargetBottomRightDistance+
-                     currentTopRightToTargetBottomLeftDistance+reversingTargetNode.bottomRightDistance+biasTopRightToTargetMidDistance+reversingTargetNode.midDistance)/7;
-
-                reversingTargetNode.biasShortestDistance =
-                    findMin9(reversingTargetNode.bottomLeftDistance, biasTopLeftToTargetMidDistance, biasTopLeftToTargetBottomRightDistance,
-                             currentTopRightToTargetBottomLeftDistance, biasTopRightToTargetMidDistance, reversingTargetNode.bottomRightDistance,
-                             currentMidToTargetBottomLeftDistance, reversingTargetNode.midDistance, biasMidToTargetBottomRightDistance);
-
-                reversingTargetNode.shortestDistance =
-                    findMin9(reversingTargetNode.bottomLeftDistance, currentTopLeftToTargetMidDistance, currentTopLeftToTargetBottomRightDistance,
-                             currentTopRightToTargetBottomLeftDistance, currentTopRightToTargetMidDistance, currentTopRightToTargetBottomRightDistance,
-                             currentMidToTargetBottomLeftDistance, currentMidToTargetMidDistance, currentMidToTargetBottomRightDistance);
-
-            }
-
-            for (nodeIndex = 0; nodeIndex < nodes.size(); nodeIndex++) {
-
-                Bounds targetBounds = nodes.get(nodeIndex).localToScene(nodes.get(nodeIndex).getLayoutBounds());
-                /*
-                ** check that the target node starts after we start target.minX > origin.minX
-                ** and the target node ends after we end target.maxX > origin.maxX
-                */
-                if ((currentB.getMinY() > targetBounds.getMaxY())) {
-
-                    targetNode.node = nodes.get(nodeIndex);
+                    targetNode.node = n;
                     targetNode.bounds = targetBounds;
 
                     /*
                     ** closest biased : simple 2d
                     */
-                    double outdB = outDistance(Direction.UP, biasedB, targetBounds);
+                    double outdB = outDistance(dir, biasedB, targetBounds);
 
-                    if (isOnAxis(Direction.UP, biasedB, targetBounds)) {
-                        targetNode.biased2DMetric = outdB + centerSideDistance(Direction.UP, biasedB, targetBounds) / 100;
+                    if (isOnAxis(dir, biasedB, targetBounds)) {
+                        targetNode.biased2DMetric = outdB + centerSideDistance(dir, biasedB, targetBounds) / 100;
                     }
                     else {
-                        final double cosd = cornerSideDistance(Direction.UP, biasedB, targetBounds);
+                        final double cosd = cornerSideDistance(dir, biasedB, targetBounds);
                         targetNode.biased2DMetric = 100000 + outdB*outdB + 9*cosd*cosd;
                     }
                     /*
                     ** closest current : simple 2d
                     */
-                    double outdC = outDistance(Direction.UP, currentB, targetBounds);
+                    double outdC = outDistance(dir, currentB, targetBounds);
 
-                    if (isOnAxis(Direction.UP, currentB, targetBounds)) {
-                        targetNode.current2DMetric = outdC + centerSideDistance(Direction.UP, currentB, targetBounds) / 100;
+                    if (isOnAxis(dir, currentB, targetBounds)) {
+                        targetNode.current2DMetric = outdC + centerSideDistance(dir, currentB, targetBounds) / 100;
                     }
                     else {
-                        final double cosd = cornerSideDistance(Direction.UP, currentB, targetBounds);
+                        final double cosd = cornerSideDistance(dir, currentB, targetBounds);
                         targetNode.current2DMetric = 100000 + outdC*outdC + 9*cosd*cosd;
                     }
 
+                    targetNode.leftCornerDistance = currenLeftCorner2D.distance(targetBounds.getMinX(), ySideInOpositeDirection.apply(targetBounds));
+                    targetNode.midDistance = currentMid2D.distance(targetBounds.getMinX()+(originB.getWidth()/2), ySideInOpositeDirection.apply(targetBounds));
+                    targetNode.rightCornerDistance = currentRightCorner2D.distance(originB.getMaxX(), ySideInOpositeDirection.apply(targetBounds));
 
-                    targetNode.bottomLeftDistance = currentTopLeft2D.distance(targetBounds.getMinX(), targetBounds.getMaxY());
-                    targetNode.midDistance = currentMid2D.distance(targetBounds.getMinX()+(originB.getWidth()/2), targetBounds.getMaxY());
-                    targetNode.bottomRightDistance = currentTopRight2D.distance(originB.getMaxX(), targetBounds.getMaxY());
+                    double currentTopLeftToTargetMidDistance = currenLeftCorner2D.distance(targetBounds.getMinX()+(targetBounds.getWidth()/2), ySideInOpositeDirection.apply(targetBounds));
+                    double currentTopLeftToTargetBottomRightDistance = currenLeftCorner2D.distance(targetBounds.getMaxX(), ySideInOpositeDirection.apply(targetBounds));
+                    double currentTopRightToTargetBottomLeftDistance = currentRightCorner2D.distance(targetBounds.getMinX(), ySideInOpositeDirection.apply(targetBounds));
+                    double currentTopRightToTargetMidDistance = currentRightCorner2D.distance(targetBounds.getMinX()+(targetBounds.getWidth()/2), ySideInOpositeDirection.apply(targetBounds));
+                    double currentTopRightToTargetBottomRightDistance = currentRightCorner2D.distance(targetBounds.getMaxX(), ySideInOpositeDirection.apply(targetBounds));
+                    double currentMidToTargetBottomLeftDistance = currentMid2D.distance(targetBounds.getMinX(), ySideInOpositeDirection.apply(targetBounds));
+                    double currentMidToTargetMidDistance = currentMid2D.distance(targetBounds.getMinX()+(targetBounds.getWidth()/2), ySideInOpositeDirection.apply(targetBounds));
+                    double currentMidToTargetBottomRightDistance = currentMid2D.distance(targetBounds.getMaxX(), ySideInOpositeDirection.apply(targetBounds));
 
-                    double currentTopLeftToTargetMidDistance = currentTopLeft2D.distance(targetBounds.getMinX()+(targetBounds.getWidth()/2), targetBounds.getMaxY());
-                    double currentTopLeftToTargetBottomRightDistance = currentTopLeft2D.distance(targetBounds.getMaxX(), targetBounds.getMaxY());
-                    double currentTopRightToTargetBottomLeftDistance = currentTopRight2D.distance(targetBounds.getMinX(), targetBounds.getMaxY());
-                    double currentTopRightToTargetMidDistance = currentTopRight2D.distance(targetBounds.getMinX()+(targetBounds.getWidth()/2), targetBounds.getMaxY());
-                    double currentTopRightToTargetBottomRightDistance = currentTopRight2D.distance(targetBounds.getMaxX(), targetBounds.getMaxY());
-                    double currentMidToTargetBottomLeftDistance = currentMid2D.distance(targetBounds.getMinX(), targetBounds.getMaxY());
-                    double currentMidToTargetMidDistance = currentMid2D.distance(targetBounds.getMinX()+(targetBounds.getWidth()/2), targetBounds.getMaxY());
-                    double currentMidToTargetBottomRightDistance = currentMid2D.distance(targetBounds.getMaxX(), targetBounds.getMaxY());
-
-                    double biasTopLeftToTargetMidDistance = currentTopLeft2D.distance(targetBounds.getMinX()+(originB.getWidth()/2), targetBounds.getMaxY());
-                    double biasTopLeftToTargetBottomRightDistance = currentTopLeft2D.distance(originB.getMaxX(), targetBounds.getMaxY());
-                    double biasTopRightToTargetMidDistance = currentTopRight2D.distance(targetBounds.getMinX()+(originB.getWidth()/2), targetBounds.getMaxY());
-                    double biasMidToTargetBottomRightDistance = currentMid2D.distance(originB.getMaxX(), targetBounds.getMaxY());
+                    double biasTopLeftToTargetMidDistance = currenLeftCorner2D.distance(targetBounds.getMinX()+(originB.getWidth()/2), ySideInOpositeDirection.apply(targetBounds));
+                    double biasTopLeftToTargetBottomRightDistance = currenLeftCorner2D.distance(originB.getMaxX(), ySideInOpositeDirection.apply(targetBounds));
+                    double biasTopRightToTargetMidDistance = currentRightCorner2D.distance(targetBounds.getMinX()+(originB.getWidth()/2), ySideInOpositeDirection.apply(targetBounds));
+                    double biasMidToTargetBottomRightDistance = currentMid2D.distance(originB.getMaxX(), ySideInOpositeDirection.apply(targetBounds));
 
                     targetNode.averageDistance =
-                        (targetNode.bottomLeftDistance+biasTopLeftToTargetMidDistance+biasTopLeftToTargetBottomRightDistance+
-                         currentTopRightToTargetBottomLeftDistance+targetNode.bottomRightDistance+biasTopRightToTargetMidDistance+targetNode.midDistance)/7;
+                        (targetNode.leftCornerDistance+biasTopLeftToTargetMidDistance+biasTopLeftToTargetBottomRightDistance+
+                         currentTopRightToTargetBottomLeftDistance+targetNode.rightCornerDistance+biasTopRightToTargetMidDistance+targetNode.midDistance)/7;
 
                     targetNode.biasShortestDistance =
-                        findMin9(targetNode.bottomLeftDistance, biasTopLeftToTargetMidDistance, biasTopLeftToTargetBottomRightDistance,
-                                 currentTopRightToTargetBottomLeftDistance, biasTopRightToTargetMidDistance, targetNode.bottomRightDistance,
+                        findMin(targetNode.leftCornerDistance, biasTopLeftToTargetMidDistance, biasTopLeftToTargetBottomRightDistance,
+                                 currentTopRightToTargetBottomLeftDistance, biasTopRightToTargetMidDistance, targetNode.rightCornerDistance,
                                  currentMidToTargetBottomLeftDistance, targetNode.midDistance, biasMidToTargetBottomRightDistance);
 
                     targetNode.shortestDistance =
-                        findMin9(targetNode.bottomLeftDistance, currentTopLeftToTargetMidDistance, currentTopLeftToTargetBottomRightDistance,
+                        findMin(targetNode.leftCornerDistance, currentTopLeftToTargetMidDistance, currentTopLeftToTargetBottomRightDistance,
                                  currentTopRightToTargetBottomLeftDistance, currentTopRightToTargetMidDistance, currentTopRightToTargetBottomRightDistance,
                                  currentMidToTargetBottomLeftDistance, currentMidToTargetMidDistance, currentMidToTargetBottomRightDistance);
 
                     /*
                     ** closest biased : simple 2d
                     */
-                    if (outdC >= 0.0) {
-                        if (nearestNodeOriginSimple2D == null || targetNode.biased2DMetric < nearestNodeOriginSimple2D.biased2DMetric) {
-
-                            if (nearestNodeOriginSimple2D == null) {
-                                nearestNodeOriginSimple2D = new TargetNode();
-                            }
-                            nearestNodeOriginSimple2D.copy(targetNode);
-                        }
-                    }
-                    /*
-                    ** closest current : simple 2d
-                    */
-                    if (outdC >= 0.0) {
-                        if (nearestNodeCurrentSimple2D == null || targetNode.current2DMetric < nearestNodeCurrentSimple2D.current2DMetric) {
-
-                            if (nearestNodeCurrentSimple2D == null) {
-                                nearestNodeCurrentSimple2D = new TargetNode();
-                            }
-                            nearestNodeCurrentSimple2D.copy(targetNode);
-                        }
-                    }
-                    /*
-                    ** on the Origin X
-                    */
-                    if ((originB.getMaxX() > targetBounds.getMinX()) && (targetBounds.getMaxX() > originB.getMinX())) {
-                        if (nearestNodeOnOriginX == null || nearestNodeOnOriginX.biasShortestDistance > targetNode.biasShortestDistance) {
-
-                            if (nearestNodeOnOriginX == null) {
-                                nearestNodeOnOriginX = new TargetNode();
-                            }
-                            nearestNodeOnOriginX.copy(targetNode);
-                        }
-                    }
-                    /*
-                    ** on the Current X
-                    */
-                    if ((currentB.getMaxX() > targetBounds.getMinX()) && (targetBounds.getMaxX() > currentB.getMinX())) {
-                        if (nearestNodeOnCurrentX == null || nearestNodeOnCurrentX.biasShortestDistance > targetNode.biasShortestDistance) {
-
-                            if (nearestNodeOnCurrentX == null) {
-                                nearestNodeOnCurrentX = new TargetNode();
-                            }
-                            nearestNodeOnCurrentX.copy(targetNode);
-                        }
-                    }
-                    /*
-                    ** Closest top left / bottom left corners.
-                    */
-                    if (nearestNodeTopLeft == null || nearestNodeTopLeft.bottomLeftDistance > targetNode.bottomLeftDistance) {
-                        if (((originB.getMinY() >= currentB.getMinY()) && (targetBounds.getMinY() >= currentB.getMinY()))  ||
-                            ((originB.getMinY() <= currentB.getMinY()) && (targetBounds.getMinY() <= currentB.getMinY()))) {
-
-                            if (nearestNodeTopLeft == null) {
-                                nearestNodeTopLeft = new TargetNode();
-                            }
-                            nearestNodeTopLeft.copy(targetNode);
-                        }
-                    }
-
-                    if (nearestNodeAverageUp == null || nearestNodeAverageUp.averageDistance > targetNode.averageDistance) {
-                        if (((originB.getMinX() >= currentB.getMinX()) && (targetBounds.getMinX() >= currentB.getMinX()))  ||
-                            ((originB.getMinX() <= currentB.getMinX()) && (targetBounds.getMinX() <= currentB.getMinX()))) {
-
-                            if (nearestNodeAverageUp == null) {
-                                nearestNodeAverageUp = new TargetNode();
-                            }
-                            nearestNodeAverageUp.copy(targetNode);
-                        }
-                    }
-
-                    if (nearestNodeAnythingAnywhereUp == null || nearestNodeAnythingAnywhereUp.shortestDistance > targetNode.shortestDistance) {
-
-                        if (nearestNodeAnythingAnywhereUp == null) {
-                            nearestNodeAnythingAnywhereUp = new TargetNode();
-                        }
-                        nearestNodeAnythingAnywhereUp.copy(targetNode);
-                    }
-                }
-            }
-        }
-        nodes.clear();
-
-        if (reversingTargetNode != null) {
-            reversingTargetNode.originTopLeftDistance = originTopLeft2D.distance(reversingTargetNode.bounds.getMinX(), reversingTargetNode.bounds.getMaxY());
-        }
-
-        if (nearestNodeOriginSimple2D != null) {
-            nearestNodeOriginSimple2D.originTopLeftDistance = originTopLeft2D.distance(nearestNodeOriginSimple2D.bounds.getMinX(), nearestNodeOriginSimple2D.bounds.getMaxY());
-        }
-
-        if (nearestNodeCurrentSimple2D != null) {
-            nearestNodeCurrentSimple2D.originTopLeftDistance = originTopLeft2D.distance(nearestNodeCurrentSimple2D.bounds.getMinX(), nearestNodeCurrentSimple2D.bounds.getMaxY());
-        }
-
-        if (nearestNodeOnOriginX != null) {
-            nearestNodeOnOriginX.originTopLeftDistance = originTopLeft2D.distance(nearestNodeOnOriginX.bounds.getMinX(), nearestNodeOnOriginX.bounds.getMaxY());
-        }
-
-        if (nearestNodeOnCurrentX != null) {
-            nearestNodeOnCurrentX.originTopLeftDistance = originTopLeft2D.distance(nearestNodeOnCurrentX.bounds.getMinX(), nearestNodeOnCurrentX.bounds.getMaxY());
-        }
-
-        if (nearestNodeAverageUp != null) {
-            nearestNodeAverageUp.originTopLeftDistance = originTopLeft2D.distance(nearestNodeAverageUp.bounds.getMinX(), nearestNodeAverageUp.bounds.getMaxY());
-        }
-
-        if (nearestNodeTopLeft != null) {
-            nearestNodeTopLeft.originTopLeftDistance = originTopLeft2D.distance(nearestNodeTopLeft.bounds.getMinX(), nearestNodeTopLeft.bounds.getMaxY());
-        }
-
-        if (nearestNodeAnythingAnywhereUp != null) {
-            nearestNodeAnythingAnywhereUp.originTopLeftDistance = originTopLeft2D.distance(nearestNodeAnythingAnywhereUp.bounds.getMinX(), nearestNodeAnythingAnywhereUp.bounds.getMaxY());
-        }
-
-        if (focusLogger.isLoggable(Level.FINER)) {
-            if (reversingTargetNode != null) {
-                focusLogger.finer("reversingTargetNode.node : "+reversingTargetNode.node);
-            }
-            if (nearestNodeOriginSimple2D != null) {
-                focusLogger.finer("nearestNodeOriginSimple2D.node : "+nearestNodeOriginSimple2D.node);
-            }
-            if (nearestNodeCurrentSimple2D != null) {
-                focusLogger.finer("nearestNodeCurrentSimple2D.node : "+nearestNodeCurrentSimple2D.node);
-            }
-            if (nearestNodeOnOriginX != null) {
-                focusLogger.finer("nearestNodeOnOriginX.node : "+nearestNodeOnOriginX.node);
-            }
-            if (nearestNodeOnCurrentX != null) {
-                focusLogger.finer("nearestNodeOnCurrentX.node : "+nearestNodeOnCurrentX.node);
-            }
-            if (nearestNodeAverageUp != null) {
-                focusLogger.finer("nearestNodeAverageUp.node : "+nearestNodeAverageUp.node);
-            }
-            if (nearestNodeTopLeft != null) {
-                focusLogger.finer("nearestNodeTopLeft.node : "+nearestNodeTopLeft.node);
-            }
-            if (nearestNodeAnythingAnywhereUp != null) {
-                focusLogger.finer("nearestNodeAnythingAnywhereUp.node : "+nearestNodeAnythingAnywhereUp.node);
-            }
-        }
-
-        /*
-        ** we've just changed direction, and have a node on stack.
-        ** there is a strong preference for this node, just make sure
-        ** it's not a bad choice, as sometimes we got here as a last-chance
-        */
-        if (reversingTargetNode != null) {
-            return reversingNode;
-        }
-
-        if (nearestNodeOnOriginX != null && nearestNodeOnOriginX.biasShortestDistance < Double.MAX_VALUE) {
-            /*
-            ** there's a preference, all else being equal, to return nearestNodeOnOriginX
-            */
-            if (nearestNodeOnCurrentX != null && nearestNodeAverageUp != null &&
-                nearestNodeOnOriginX.node == nearestNodeOnCurrentX.node && nearestNodeOnOriginX.node == nearestNodeAverageUp.node) {
-                return nearestNodeOnOriginX.node;
-            }
-            if (nearestNodeOnCurrentX != null && nearestNodeOriginSimple2D != null &&
-                nearestNodeOnOriginX.node == nearestNodeOnCurrentX.node && nearestNodeOnOriginX.node == nearestNodeOriginSimple2D.node) {
-                return nearestNodeOnOriginX.node;
-            }
-            if (nearestNodeOnCurrentX != null && nearestNodeTopLeft != null &&
-                nearestNodeOnOriginX.node == nearestNodeOnCurrentX.node && nearestNodeOnOriginX.node == nearestNodeTopLeft.node) {
-                return nearestNodeOnOriginX.node;
-            }
-            if (nearestNodeOnCurrentX != null && nearestNodeAnythingAnywhereUp != null &&
-                nearestNodeOnOriginX.node == nearestNodeOnCurrentX.node && nearestNodeOnOriginX.node == nearestNodeAnythingAnywhereUp.node) {
-                return nearestNodeOnOriginX.node;
-            }
-            if (nearestNodeAverageUp != null && nearestNodeOnOriginX.node == nearestNodeAverageUp.node) {
-                return nearestNodeOnOriginX.node;
-            }
-
-            if (nearestNodeOnCurrentX != null && nearestNodeOnCurrentX.biasShortestDistance < Double.MAX_VALUE) {
-                if (nearestNodeOnOriginX == null || (nearestNodeOnCurrentX.bottomLeftDistance < nearestNodeOnOriginX.bottomLeftDistance) &&
-                    (nearestNodeOnCurrentX.originTopLeftDistance < nearestNodeOnOriginX.originTopLeftDistance) &&
-                    (nearestNodeOnCurrentX.bounds.getMinX() - currentTopLeft2D.getX()) < (nearestNodeOnOriginX.bounds.getMinX() - currentTopLeft2D.getX()) )  {
-
-                    return nearestNodeOnCurrentX.node;
-                }
-                else if (nearestNodeOnOriginX != null) {
-                    if (nearestNodeAverageUp == null || nearestNodeOnOriginX.averageDistance < nearestNodeAverageUp.averageDistance) {
-                        return nearestNodeOnOriginX.node;
-                    }
-                }
-            }
-
-        }
-        else {
-            if (nearestNodeOnOriginX == null && nearestNodeOnCurrentX == null && nearestNodeCurrentSimple2D != null) {
-                if (nearestNodeAverageUp != null && nearestNodeTopLeft != null && nearestNodeAnythingAnywhereUp != null && (nearestNodeAverageUp.node == nearestNodeTopLeft.node && nearestNodeAverageUp.node == nearestNodeAnythingAnywhereUp.node)) {
-                    return nearestNodeAverageUp.node;
-                }
-                return nearestNodeCurrentSimple2D.node;
-            }
-            else if (nearestNodeAverageUp != null && nearestNodeTopLeft != null && nearestNodeAnythingAnywhereUp != null &&
-                     nearestNodeAverageUp.biasShortestDistance == nearestNodeTopLeft.biasShortestDistance &&
-                     nearestNodeAverageUp.biasShortestDistance == nearestNodeAnythingAnywhereUp.biasShortestDistance &&
-                     nearestNodeAverageUp.biasShortestDistance < Double.MAX_VALUE) {
-
-                if (nearestNodeOnOriginX != null && nearestNodeOnOriginX.originTopLeftDistance < nearestNodeAverageUp.originTopLeftDistance) {
-                    return nearestNodeOnOriginX.node;
-                }
-                else {
-                    return nearestNodeAverageUp.node;
-                }
-            }
-        }
-
-        /*
-        ** is the average closer?
-        */
-        if (nearestNodeAverageUp != null && (nearestNodeOnOriginX == null || (nearestNodeAverageUp.biasShortestDistance < nearestNodeOnOriginX.biasShortestDistance))) {
-            /*
-            ** but is one in the way
-            */
-            if (nearestNodeOnOriginX != null && (nearestNodeOnOriginX.bounds.getMaxY() >= nearestNodeAverageUp.bounds.getMaxY())) {
-                return nearestNodeOnOriginX.node;
-            }
-            if (nearestNodeOriginSimple2D != null) {
-                if (nearestNodeOriginSimple2D.current2DMetric <= nearestNodeAverageUp.current2DMetric) {
-                    return nearestNodeOriginSimple2D.node;
-                }
-                if (nearestNodeOriginSimple2D.bounds.getMaxY() >= nearestNodeAverageUp.bounds.getMaxY()) {
-                    return nearestNodeOriginSimple2D.node;
-                }
-            }
-            return nearestNodeAverageUp.node;
-        }
-
-        /*
-        ** this is an odd one, in that is isn't the closest on current, or on the
-        ** origin, but it looks better for most cases...
-        */
-        if ((nearestNodeCurrentSimple2D != null && nearestNodeOnCurrentX != null && nearestNodeAverageUp != null && nearestNodeTopLeft != null && nearestNodeAnythingAnywhereUp != null) &&
-            (nearestNodeCurrentSimple2D.node == nearestNodeOnCurrentX.node) &&
-            (nearestNodeCurrentSimple2D.node ==  nearestNodeAverageUp.node) &&
-            (nearestNodeCurrentSimple2D.node == nearestNodeTopLeft.node) &&
-            (nearestNodeCurrentSimple2D.node == nearestNodeAnythingAnywhereUp.node)) {
-            return nearestNodeCurrentSimple2D.node;
-        }
-
-        if (nearestNodeOnOriginX != null && (nearestNodeOnCurrentX == null || (nearestNodeOnOriginX.bottomRightDistance < nearestNodeOnCurrentX.bottomRightDistance))) {
-            return nearestNodeOnOriginX.node;
-        }
-        /*
-        ** There isn't a clear winner, just go to the one nearest the current
-        ** focus owner, or if invalid then try the other contenders.
-        */
-        if (nearestNodeOnOriginX != null) {
-            return nearestNodeOnOriginX.node;
-        }
-        else if (nearestNodeOriginSimple2D != null) {
-            return nearestNodeOriginSimple2D.node;
-        }
-        else if (nearestNodeOnCurrentX != null) {
-            return nearestNodeOnCurrentX.node;
-        }
-        else if (nearestNodeAverageUp != null) {
-            return nearestNodeAverageUp.node;
-        }
-        else if (nearestNodeTopLeft != null) {
-            return nearestNodeTopLeft.node;
-        }
-        else if (nearestNodeAnythingAnywhereUp != null) {
-            return nearestNodeAnythingAnywhereUp.node;
-        }
-        return null;
-    }
-
-
-    protected Node getNearestNodeDown(Bounds currentB, Bounds originB, TraversalEngine engine, Node node, Node reversingNode) {
-
-        List<Node> nodes = engine.getAllTargetNodes();
-
-        Bounds biasedB = new BoundingBox(originB.getMinX(), currentB.getMinY(), originB.getWidth(), currentB.getHeight());
-
-        Point2D currentMid2D = new Point2D(currentB.getMinX()+(currentB.getWidth()/2), currentB.getMaxY());
-        Point2D currentBottomLeft2D = new Point2D(currentB.getMinX(), currentB.getMaxY());
-        Point2D currentBottomRight2D = new Point2D(currentB.getMaxX(), currentB.getMaxY());
-
-        Point2D originBottomLeft2D = new Point2D(originB.getMinX(), originB.getMaxY());
-
-        TargetNode reversingTargetNode = null;
-        TargetNode targetNode = new TargetNode();
-        TargetNode nearestNodeCurrentSimple2D = null;
-        TargetNode nearestNodeOriginSimple2D = null;
-        TargetNode nearestNodeAverageDown = null;
-        TargetNode nearestNodeOnOriginX = null;
-        TargetNode nearestNodeOnCurrentX = null;
-        TargetNode nearestNodeBottomLeft = null;
-        TargetNode nearestNodeAnythingAnywhereDown = null;
-
-        if (nodes.size() > 0) {
-            int nodeIndex;
-
-            if (reversingNode != null) {
-                Bounds targetBounds = reversingNode.localToScene(reversingNode.getLayoutBounds());
-                reversingTargetNode = new TargetNode();
-
-                reversingTargetNode.node = reversingNode;
-                reversingTargetNode.bounds = targetBounds;
-
-                /*
-                ** closest biased : simple 2d
-                */
-                double outdB = outDistance(Direction.DOWN, biasedB, targetBounds);
-
-                if (isOnAxis(Direction.DOWN, biasedB, targetBounds)) {
-                    reversingTargetNode.biased2DMetric = outdB + centerSideDistance(Direction.DOWN, biasedB, targetBounds) / 100;
-                }
-                else {
-                    final double cosd = cornerSideDistance(Direction.DOWN, biasedB, targetBounds);
-                    reversingTargetNode.biased2DMetric = 100000 + outdB*outdB + 9*cosd*cosd;
-                }
-
-                /*
-                ** closest current : simple 2d
-                */
-                double outdC = outDistance(Direction.DOWN, currentB, targetBounds);
-
-                if (isOnAxis(Direction.DOWN, currentB, targetBounds)) {
-                    reversingTargetNode.current2DMetric = outdC + centerSideDistance(Direction.DOWN, currentB, targetBounds) / 100;
-                }
-                else {
-                    final double cosd = cornerSideDistance(Direction.DOWN, currentB, targetBounds);
-                    reversingTargetNode.current2DMetric = 100000 + outdC*outdC + 9*cosd*cosd;
-                }
-
-                reversingTargetNode.topLeftDistance = currentBottomLeft2D.distance(targetBounds.getMinX(), targetBounds.getMinY());
-                reversingTargetNode.midDistance = currentMid2D.distance(targetBounds.getMinX()+(originB.getWidth()/2), targetBounds.getMinY());
-                reversingTargetNode.topRightDistance = currentBottomRight2D.distance(originB.getMaxX(), targetBounds.getMinY());
-
-                double currentBottomLeftToTargetTopRightDistance = currentBottomLeft2D.distance(targetBounds.getMaxX(), targetBounds.getMinY());
-                double currentBottomLeftToTargetMidDistance = currentBottomLeft2D.distance(targetBounds.getMinX()+(targetBounds.getWidth()/2), targetBounds.getMinY());
-                double currentBottomRightToTargetTopLeftDistance = currentBottomRight2D.distance(targetBounds.getMinX(), targetBounds.getMinY());
-                double currentBottomRightToTargetTopRightDistance = currentBottomRight2D.distance(targetBounds.getMaxX(), targetBounds.getMinY());
-                double currentBottomRightToTargetMidDistance = currentBottomRight2D.distance(targetBounds.getMinX()+(targetBounds.getWidth()/2), targetBounds.getMinY());
-                double currentMidToTargetTopLeftDistance = currentMid2D.distance(targetBounds.getMinX(), targetBounds.getMinY());
-                double currentMidToTargetTopRightDistance = currentMid2D.distance(targetBounds.getMaxX(), targetBounds.getMinY());
-                double currentMidToTargetMidDistance = currentMid2D.distance(targetBounds.getMinX()+(targetBounds.getWidth()/2), targetBounds.getMinY());
-
-                double biasBottomLeftToTargetTopRightDistance = currentBottomLeft2D.distance(originB.getMaxX(), targetBounds.getMinY());
-                double biasBottomLeftToTargetMidDistance = currentBottomLeft2D.distance(targetBounds.getMinX()+(originB.getWidth()/2), targetBounds.getMinY());
-                double biasBottomRightToTargetMidDistance = currentBottomRight2D.distance(targetBounds.getMinX()+(originB.getWidth()/2), targetBounds.getMinY());
-                double biasMidToTargetTopRightDistance = currentMid2D.distance(originB.getMaxX(), targetBounds.getMinY());
-
-                reversingTargetNode.averageDistance =
-                    (reversingTargetNode.topLeftDistance+biasBottomLeftToTargetMidDistance+biasBottomLeftToTargetTopRightDistance+
-                     currentBottomRightToTargetTopLeftDistance+reversingTargetNode.topRightDistance+biasBottomRightToTargetMidDistance+reversingTargetNode.midDistance)/7;
-
-                reversingTargetNode.biasShortestDistance =
-                    findMin9(reversingTargetNode.topLeftDistance, biasBottomLeftToTargetMidDistance, biasBottomLeftToTargetTopRightDistance,
-                             currentBottomRightToTargetTopLeftDistance, biasBottomRightToTargetMidDistance, reversingTargetNode.topRightDistance,
-                             currentMidToTargetTopLeftDistance, reversingTargetNode.midDistance, biasMidToTargetTopRightDistance);
-
-                reversingTargetNode.shortestDistance =
-                    findMin9(reversingTargetNode.topLeftDistance, currentBottomLeftToTargetMidDistance, currentBottomLeftToTargetTopRightDistance,
-                             currentBottomRightToTargetTopLeftDistance, currentBottomRightToTargetMidDistance, currentBottomRightToTargetTopRightDistance,
-                             currentMidToTargetTopLeftDistance, currentMidToTargetMidDistance, currentMidToTargetTopRightDistance);
-
-            }
-
-            for (nodeIndex = 0; nodeIndex < nodes.size(); nodeIndex++) {
-
-                Bounds targetBounds = nodes.get(nodeIndex).localToScene(nodes.get(nodeIndex).getLayoutBounds());
-                /*
-                ** check that the target node starts after we start target.minX > origin.minX
-                ** and the target node ends after we end target.maxX > origin.maxX
-                */
-                if ((currentB.getMaxY() < targetBounds.getMinY())) {
-
-                    targetNode.node = nodes.get(nodeIndex);
-                    targetNode.bounds = targetBounds;
-
-                    /*
-                    ** closest biased : simple 2d
-                    */
-                    double outdB = outDistance(Direction.DOWN, biasedB, targetBounds);
-
-                    if (isOnAxis(Direction.DOWN, biasedB, targetBounds)) {
-                        targetNode.biased2DMetric = outdB + centerSideDistance(Direction.DOWN, biasedB, targetBounds) / 100;
-                    }
-                    else {
-                        final double cosd = cornerSideDistance(Direction.DOWN, biasedB, targetBounds);
-                        targetNode.biased2DMetric = 100000 + outdB*outdB + 9*cosd*cosd;
-                    }
-                    /*
-                    ** closest current : simple 2d
-                    */
-                    double outdC = outDistance(Direction.DOWN, currentB, targetBounds);
-
-                    if (isOnAxis(Direction.DOWN, currentB, targetBounds)) {
-                        targetNode.current2DMetric = outdC + centerSideDistance(Direction.DOWN, currentB, targetBounds) / 100;
-                    }
-                    else {
-                        final double cosd = cornerSideDistance(Direction.DOWN, currentB, targetBounds);
-                        targetNode.current2DMetric = 100000 + outdC*outdC + 9*cosd*cosd;
-                    }
-
-                    targetNode.topLeftDistance = currentBottomLeft2D.distance(targetBounds.getMinX(), targetBounds.getMinY());
-                    targetNode.midDistance = currentMid2D.distance(targetBounds.getMinX()+(originB.getWidth()/2), targetBounds.getMinY());
-                    targetNode.topRightDistance = currentBottomRight2D.distance(originB.getMaxX(), targetBounds.getMinY());
-
-                    double currentBottomLeftToTargetTopRightDistance = currentBottomLeft2D.distance(targetBounds.getMaxX(), targetBounds.getMinY());
-                    double currentBottomLeftToTargetMidDistance = currentBottomLeft2D.distance(targetBounds.getMinX()+(targetBounds.getWidth()/2), targetBounds.getMinY());
-                    double currentBottomRightToTargetTopLeftDistance = currentBottomRight2D.distance(targetBounds.getMinX(), targetBounds.getMinY());
-                    double currentBottomRightToTargetTopRightDistance = currentBottomRight2D.distance(targetBounds.getMaxX(), targetBounds.getMinY());
-                    double currentBottomRightToTargetMidDistance = currentBottomRight2D.distance(targetBounds.getMinX()+(targetBounds.getWidth()/2), targetBounds.getMinY());
-                    double currentMidToTargetTopLeftDistance = currentMid2D.distance(targetBounds.getMinX(), targetBounds.getMinY());
-                    double currentMidToTargetTopRightDistance = currentMid2D.distance(targetBounds.getMaxX(), targetBounds.getMinY());
-                    double currentMidToTargetMidDistance = currentMid2D.distance(targetBounds.getMinX()+(targetBounds.getWidth()/2), targetBounds.getMinY());
-
-                    double biasBottomLeftToTargetTopRightDistance = currentBottomLeft2D.distance(originB.getMaxX(), targetBounds.getMinY());
-                    double biasBottomLeftToTargetMidDistance = currentBottomLeft2D.distance(targetBounds.getMinX()+(originB.getWidth()/2), targetBounds.getMinY());
-                    double biasBottomRightToTargetMidDistance = currentBottomRight2D.distance(targetBounds.getMinX()+(originB.getWidth()/2), targetBounds.getMinY());
-                    double biasMidToTargetTopRightDistance = currentMid2D.distance(originB.getMaxX(), targetBounds.getMinY());
-
-                    targetNode.averageDistance =
-                        (targetNode.topLeftDistance+biasBottomLeftToTargetMidDistance+biasBottomLeftToTargetTopRightDistance+
-                         currentBottomRightToTargetTopLeftDistance+targetNode.topRightDistance+biasBottomRightToTargetMidDistance+targetNode.midDistance)/7;
-
-                    targetNode.biasShortestDistance =
-                        findMin9(targetNode.topLeftDistance, biasBottomLeftToTargetMidDistance, biasBottomLeftToTargetTopRightDistance,
-                                 currentBottomRightToTargetTopLeftDistance, biasBottomRightToTargetMidDistance, targetNode.topRightDistance,
-                                 currentMidToTargetTopLeftDistance, targetNode.midDistance, biasMidToTargetTopRightDistance);
-
-                    targetNode.shortestDistance =
-                        findMin9(targetNode.topLeftDistance, currentBottomLeftToTargetMidDistance, currentBottomLeftToTargetTopRightDistance,
-                                 currentBottomRightToTargetTopLeftDistance, currentBottomRightToTargetMidDistance, currentBottomRightToTargetTopRightDistance,
-                                 currentMidToTargetTopLeftDistance, currentMidToTargetMidDistance, currentMidToTargetTopRightDistance);
-
-
-                    /*
-                    ** closest biased : simple 2d
-                    */
                     if (outdB >= 0.0) {
                         if (nearestNodeOriginSimple2D == null || targetNode.biased2DMetric < nearestNodeOriginSimple2D.biased2DMetric) {
 
@@ -1094,70 +601,55 @@
                         }
                     }
                     /*
-                    ** Closest bottom left / top left corners.
+                    ** Closest top left / bottom left corners.
                     */
-                    if (nearestNodeBottomLeft == null || nearestNodeBottomLeft.topLeftDistance > targetNode.topLeftDistance) {
+                    if (nearestNodeLeft == null || nearestNodeLeft.leftCornerDistance > targetNode.leftCornerDistance) {
                         if (((originB.getMinX() >= currentB.getMinX()) && (targetBounds.getMinX() >= currentB.getMinX()))  ||
                             ((originB.getMinX() <= currentB.getMinX()) && (targetBounds.getMinX() <= currentB.getMinX()))) {
 
-                            if (nearestNodeBottomLeft == null) {
-                                nearestNodeBottomLeft = new TargetNode();
+                            if (nearestNodeLeft == null) {
+                                nearestNodeLeft = new TargetNode();
                             }
-                            nearestNodeBottomLeft.copy(targetNode);
+                            nearestNodeLeft.copy(targetNode);
                         }
                     }
 
-                    if (nearestNodeAverageDown == null || nearestNodeAverageDown.averageDistance > targetNode.averageDistance) {
+                    if (nearestNodeAverage == null || nearestNodeAverage.averageDistance > targetNode.averageDistance) {
                         if (((originB.getMinX() >= currentB.getMinX()) && (targetBounds.getMinX() >= currentB.getMinX()))  ||
                             ((originB.getMinX() <= currentB.getMinX()) && (targetBounds.getMinX() <= currentB.getMinX()))) {
 
-                            if (nearestNodeAverageDown == null) {
-                                nearestNodeAverageDown = new TargetNode();
+                            if (nearestNodeAverage == null) {
+                                nearestNodeAverage = new TargetNode();
                             }
-                            nearestNodeAverageDown.copy(targetNode);
+                            nearestNodeAverage.copy(targetNode);
                         }
                     }
 
-                    if (nearestNodeAnythingAnywhereDown == null || nearestNodeAnythingAnywhereDown.shortestDistance > targetNode.shortestDistance) {
-                        if (nearestNodeAnythingAnywhereDown == null) {
-                            nearestNodeAnythingAnywhereDown = new TargetNode();
+                    if (nearestNodeAnythingAnywhere == null || nearestNodeAnythingAnywhere.shortestDistance > targetNode.shortestDistance) {
+
+                        if (nearestNodeAnythingAnywhere == null) {
+                            nearestNodeAnythingAnywhere = new TargetNode();
                         }
-                        nearestNodeAnythingAnywhereDown.copy(targetNode);
+                        nearestNodeAnythingAnywhere.copy(targetNode);
                     }
                 }
             }
         }
         nodes.clear();
 
-        if (reversingTargetNode != null) {
-            reversingTargetNode.originBottomLeftDistance = originBottomLeft2D.distance(reversingTargetNode.bounds.getMinX(), reversingTargetNode.bounds.getMinY());
+        if (nearestNodeOnOriginX != null) {
+            nearestNodeOnOriginX.originLeftCornerDistance = originLeftCorner2D.distance(nearestNodeOnOriginX.bounds.getMinX(), ySideInOpositeDirection.apply(nearestNodeOnOriginX.bounds));
         }
-        if (nearestNodeOriginSimple2D != null) {
-            nearestNodeOriginSimple2D.originBottomLeftDistance = originBottomLeft2D.distance(nearestNodeOriginSimple2D.bounds.getMinX(), nearestNodeOriginSimple2D.bounds.getMinY());
+
+        if (nearestNodeOnCurrentX != null) {
+            nearestNodeOnCurrentX.originLeftCornerDistance = originLeftCorner2D.distance(nearestNodeOnCurrentX.bounds.getMinX(), ySideInOpositeDirection.apply(nearestNodeOnCurrentX.bounds));
         }
-        if (nearestNodeCurrentSimple2D != null) {
-            nearestNodeCurrentSimple2D.originBottomLeftDistance = originBottomLeft2D.distance(nearestNodeCurrentSimple2D.bounds.getMinX(), nearestNodeCurrentSimple2D.bounds.getMinY());
-        }
-        if (nearestNodeOnOriginX != null) {
-            nearestNodeOnOriginX.originBottomLeftDistance = originBottomLeft2D.distance(nearestNodeOnOriginX.bounds.getMinX(), nearestNodeOnOriginX.bounds.getMinY());
-        }
-        if (nearestNodeOnCurrentX != null) {
-            nearestNodeOnCurrentX.originBottomLeftDistance = originBottomLeft2D.distance(nearestNodeOnCurrentX.bounds.getMinX(), nearestNodeOnCurrentX.bounds.getMinY());
-        }
-        if (nearestNodeAverageDown != null) {
-            nearestNodeAverageDown.originBottomLeftDistance = originBottomLeft2D.distance(nearestNodeAverageDown.bounds.getMinX(), nearestNodeAverageDown.bounds.getMinY());
-        }
-        if (nearestNodeBottomLeft != null) {
-            nearestNodeBottomLeft.originBottomLeftDistance = originBottomLeft2D.distance(nearestNodeBottomLeft.bounds.getMinX(), nearestNodeBottomLeft.bounds.getMinY());
-        }
-        if (nearestNodeAnythingAnywhereDown != null) {
-            nearestNodeAnythingAnywhereDown.originBottomLeftDistance = originBottomLeft2D.distance(nearestNodeAnythingAnywhereDown.bounds.getMinX(), nearestNodeAnythingAnywhereDown.bounds.getMinY());
+
+        if (nearestNodeAverage != null) {
+            nearestNodeAverage.originLeftCornerDistance = originLeftCorner2D.distance(nearestNodeAverage.bounds.getMinX(), ySideInOpositeDirection.apply(nearestNodeAverage.bounds));
         }
 
         if (focusLogger.isLoggable(Level.FINER)) {
-            if (reversingTargetNode != null) {
-                focusLogger.finer("reversingTargetNode.node : "+reversingTargetNode.node);
-            }
             if (nearestNodeOriginSimple2D != null) {
                 focusLogger.finer("nearestNodeOriginSimple2D.node : "+nearestNodeOriginSimple2D.node);
             }
@@ -1170,78 +662,57 @@
             if (nearestNodeOnCurrentX != null) {
                 focusLogger.finer("nearestNodeOnCurrentX.node : "+nearestNodeOnCurrentX.node);
             }
-            if (nearestNodeAverageDown != null) {
-                focusLogger.finer("nearestNodeAverageDown.node : "+nearestNodeAverageDown.node);
+            if (nearestNodeAverage != null) {
+                focusLogger.finer("nearestNodeAverageUp.node : "+nearestNodeAverage.node);
             }
-            if (nearestNodeBottomLeft != null) {
-                focusLogger.finer("nearestNodeTopLeft.node : "+nearestNodeBottomLeft.node);
+            if (nearestNodeLeft != null) {
+                focusLogger.finer("nearestNodeTopLeft.node : "+nearestNodeLeft.node);
             }
-            if (nearestNodeAnythingAnywhereDown != null) {
-                focusLogger.finer("nearestNodeAnythingAnywhereDown.node : "+nearestNodeAnythingAnywhereDown.node);
+            if (nearestNodeAnythingAnywhere != null) {
+                focusLogger.finer("nearestNodeAnythingAnywhereUp.node : "+nearestNodeAnythingAnywhere.node);
             }
         }
 
-        /*
-        ** we've just changed direction, and have a node on stack.
-        ** there is a strong preference for this node, just make sure
-        ** it's not a bad choice, as sometimes we got here as a last-chance
-        */
-        if (reversingTargetNode != null) {
-            return reversingNode;
-        }
         if (nearestNodeOnOriginX != null && nearestNodeOnOriginX.biasShortestDistance < Double.MAX_VALUE) {
             /*
             ** there's a preference, all else being equal, to return nearestNodeOnOriginX
             */
-            if (nearestNodeOnCurrentX != null && nearestNodeAverageDown != null &&
-                nearestNodeOnOriginX.node == nearestNodeOnCurrentX.node && nearestNodeOnOriginX.node == nearestNodeAverageDown.node) {
+            if (nearestNodeOnCurrentX != null && nearestNodeOnOriginX.node == nearestNodeOnCurrentX.node
+                    && ((nearestNodeAverage != null && nearestNodeOnOriginX.node == nearestNodeAverage.node)
+                    || (nearestNodeOriginSimple2D != null && nearestNodeOnOriginX.node == nearestNodeOriginSimple2D.node)
+                    || (nearestNodeLeft != null && nearestNodeOnOriginX.node == nearestNodeLeft.node)
+                    || (nearestNodeAnythingAnywhere != null && nearestNodeOnOriginX.node == nearestNodeAnythingAnywhere.node))) {
                 return nearestNodeOnOriginX.node;
             }
-            if (nearestNodeOnCurrentX != null && nearestNodeOriginSimple2D != null &&
-                nearestNodeOnOriginX.node == nearestNodeOnCurrentX.node && nearestNodeOnOriginX.node == nearestNodeOriginSimple2D.node) {
-                return nearestNodeOnOriginX.node;
-            }
-            if (nearestNodeOnCurrentX != null && nearestNodeBottomLeft != null && nearestNodeOnOriginX.node == nearestNodeOnCurrentX.node && nearestNodeOnOriginX.node == nearestNodeBottomLeft.node) {
-                return nearestNodeOnOriginX.node;
-            }
-            if (nearestNodeOnCurrentX != null && nearestNodeAnythingAnywhereDown != null && nearestNodeOnOriginX.node == nearestNodeOnCurrentX.node && nearestNodeOnOriginX.node == nearestNodeAnythingAnywhereDown.node) {
-                return nearestNodeOnOriginX.node;
-            }
-            if (nearestNodeAverageDown != null && nearestNodeOnOriginX.node == nearestNodeAverageDown.node) {
+            if (nearestNodeAverage != null && nearestNodeOnOriginX.node == nearestNodeAverage.node) {
                 return nearestNodeOnOriginX.node;
             }
 
             if (nearestNodeOnCurrentX != null && nearestNodeOnCurrentX.biasShortestDistance < Double.MAX_VALUE) {
-                if (nearestNodeOnOriginX == null || (nearestNodeOnCurrentX.topLeftDistance < nearestNodeOnOriginX.topLeftDistance) &&
-                    (nearestNodeOnCurrentX.originBottomLeftDistance < nearestNodeOnOriginX.originBottomLeftDistance) &&
-                    (nearestNodeOnCurrentX.bounds.getMinX() - currentBottomLeft2D.getX()) < (nearestNodeOnOriginX.bounds.getMinX() - currentBottomLeft2D.getX())  )  {
+                if ((nearestNodeOnCurrentX.leftCornerDistance < nearestNodeOnOriginX.leftCornerDistance) &&
+                    (nearestNodeOnCurrentX.originLeftCornerDistance < nearestNodeOnOriginX.originLeftCornerDistance) &&
+                (nearestNodeOnCurrentX.bounds.getMinX() - currenLeftCorner2D.getX()) < (nearestNodeOnOriginX.bounds.getMinX() - currenLeftCorner2D.getX())) {
 
                     return nearestNodeOnCurrentX.node;
-                }
-                else  if (nearestNodeOnOriginX != null) {
-                    if (nearestNodeAverageDown == null || nearestNodeOnOriginX.averageDistance < nearestNodeAverageDown.averageDistance) {
-                        return nearestNodeOnOriginX.node;
-                    }
+                } else if (nearestNodeAverage == null || nearestNodeOnOriginX.averageDistance < nearestNodeAverage.averageDistance) {
+                    return nearestNodeOnOriginX.node;
                 }
             }
-        }
-        else {
+        } else {
             if (nearestNodeOnOriginX == null && nearestNodeOnCurrentX == null && nearestNodeCurrentSimple2D != null) {
-                if (nearestNodeAverageDown != null && nearestNodeBottomLeft != null && nearestNodeAnythingAnywhereDown != null && (nearestNodeAverageDown.node == nearestNodeBottomLeft.node && nearestNodeAverageDown.node == nearestNodeAnythingAnywhereDown.node)) {
-                    return nearestNodeAverageDown.node;
+                if (nearestNodeAverage != null && nearestNodeLeft != null && (nearestNodeAverage.node == nearestNodeLeft.node && nearestNodeAverage.node == nearestNodeAnythingAnywhere.node)) {
+                    return nearestNodeAverage.node;
                 }
                 return nearestNodeCurrentSimple2D.node;
-            }
-            else if (nearestNodeAverageDown != null && nearestNodeBottomLeft != null && nearestNodeAnythingAnywhereDown != null &&
-                     nearestNodeAverageDown.biasShortestDistance == nearestNodeBottomLeft.biasShortestDistance &&
-                     nearestNodeAverageDown.biasShortestDistance == nearestNodeAnythingAnywhereDown.biasShortestDistance &&
-                     nearestNodeAverageDown.biasShortestDistance < Double.MAX_VALUE) {
+            } else if (nearestNodeAverage != null && nearestNodeLeft != null && nearestNodeAnythingAnywhere != null
+                    &&     nearestNodeAverage.biasShortestDistance == nearestNodeLeft.biasShortestDistance &&
+                     nearestNodeAverage.biasShortestDistance == nearestNodeAnythingAnywhere.biasShortestDistance &&
+                     nearestNodeAverage.biasShortestDistance < Double.MAX_VALUE) {
 
-                if (nearestNodeOnOriginX != null && nearestNodeOnOriginX.originBottomLeftDistance < nearestNodeAverageDown.originBottomLeftDistance) {
+                if (nearestNodeOnOriginX != null && nearestNodeOnOriginX.originLeftCornerDistance < nearestNodeAverage.originLeftCornerDistance) {
                     return nearestNodeOnOriginX.node;
-                }
-                else {
-                    return nearestNodeAverageDown.node;
+                } else {
+                    return nearestNodeAverage.node;
                 }
             }
         }
@@ -1249,223 +720,180 @@
         /*
         ** is the average closer?
         */
-        if (nearestNodeAverageDown != null && (nearestNodeOnOriginX == null || (nearestNodeAverageDown.biasShortestDistance < nearestNodeOnOriginX.biasShortestDistance))) {
+        if (nearestNodeAverage != null && (nearestNodeOnOriginX == null || (nearestNodeAverage.biasShortestDistance < nearestNodeOnOriginX.biasShortestDistance))) {
             /*
             ** but is one in the way
             */
-            if (nearestNodeOnOriginX != null && (nearestNodeOnOriginX.bounds.getMinY() <= nearestNodeAverageDown.bounds.getMinY())) {
+            if (nearestNodeOnOriginX != null && (ySideInOpositeDirection.apply(nearestNodeOnOriginX.bounds) >= ySideInOpositeDirection.apply(nearestNodeAverage.bounds))) {
                 return nearestNodeOnOriginX.node;
             }
             if (nearestNodeOriginSimple2D != null) {
-                if (nearestNodeOriginSimple2D.current2DMetric <= nearestNodeAverageDown.current2DMetric) {
+                if (nearestNodeOriginSimple2D.current2DMetric <= nearestNodeAverage.current2DMetric) {
                     return nearestNodeOriginSimple2D.node;
                 }
-                if (nearestNodeOnOriginX.bounds.getMinY() <= nearestNodeAverageDown.bounds.getMinY()) {
+                if (ySideInOpositeDirection.apply(nearestNodeOriginSimple2D.bounds) >= ySideInOpositeDirection.apply(nearestNodeAverage.bounds)) {
                     return nearestNodeOriginSimple2D.node;
                 }
             }
-            return nearestNodeAverageDown.node;
+            return nearestNodeAverage.node;
         }
 
         /*
         ** this is an odd one, in that is isn't the closest on current, or on the
         ** origin, but it looks better for most cases...
         */
-        if ((nearestNodeCurrentSimple2D != null && nearestNodeOnCurrentX != null && nearestNodeAverageDown != null && nearestNodeBottomLeft != null && nearestNodeAnythingAnywhereDown != null) &&
+        if ((nearestNodeCurrentSimple2D != null && nearestNodeOnCurrentX != null && nearestNodeAverage != null && nearestNodeLeft != null && nearestNodeAnythingAnywhere != null) &&
             (nearestNodeCurrentSimple2D.node == nearestNodeOnCurrentX.node) &&
-            (nearestNodeCurrentSimple2D.node ==  nearestNodeAverageDown.node) &&
-            (nearestNodeCurrentSimple2D.node == nearestNodeBottomLeft.node) &&
-            (nearestNodeCurrentSimple2D.node == nearestNodeAnythingAnywhereDown.node)) {
+            (nearestNodeCurrentSimple2D.node ==  nearestNodeAverage.node) &&
+            (nearestNodeCurrentSimple2D.node == nearestNodeLeft.node) &&
+            (nearestNodeCurrentSimple2D.node == nearestNodeAnythingAnywhere.node)) {
             return nearestNodeCurrentSimple2D.node;
         }
 
-        if (nearestNodeOnOriginX != null && (nearestNodeOnCurrentX == null || (nearestNodeOnOriginX.topRightDistance < nearestNodeOnCurrentX.topRightDistance))) {
+        if (nearestNodeOnOriginX != null && (nearestNodeOnCurrentX == null || (nearestNodeOnOriginX.rightCornerDistance < nearestNodeOnCurrentX.rightCornerDistance))) {
             return nearestNodeOnOriginX.node;
         }
         /*
         ** There isn't a clear winner, just go to the one nearest the current
-        ** focus owner, or if invalid then try the other contenders.
-        */
+         ** focus owner, or if invalid then try the other contenders.
+         */
         if (nearestNodeOnOriginX != null) {
             return nearestNodeOnOriginX.node;
-        }
-        else if (nearestNodeOriginSimple2D != null) {
+        } else if (nearestNodeOriginSimple2D != null) {
             return nearestNodeOriginSimple2D.node;
-        }
-        else if (nearestNodeOnCurrentX != null) {
+        } else if (nearestNodeOnCurrentX != null) {
             return nearestNodeOnCurrentX.node;
-        }
-        else if (nearestNodeAverageDown != null) {
-            return nearestNodeAverageDown.node;
-        }
-        else if (nearestNodeBottomLeft != null) {
-            return nearestNodeBottomLeft.node;
-        }
-        else if (nearestNodeAnythingAnywhereDown != null) {
-            return nearestNodeAnythingAnywhereDown.node;
+        } else if (nearestNodeAverage != null) {
+            return nearestNodeAverage.node;
+        } else if (nearestNodeLeft != null) {
+            return nearestNodeLeft.node;
+        } else if (nearestNodeAnythingAnywhere != null) {
+            return nearestNodeAnythingAnywhere.node;
         }
         return null;
     }
+    
+    private static final Function<Bounds, Double> BOUNDS_LEFT_SIDE = new Function<Bounds, Double>() {
 
-    protected Node getNearestNodeLeft(Bounds currentB, Bounds originB, TraversalEngine engine, Node node, Node reversingNode) {
+        @Override
+        public Double apply(Bounds t) {
+            return t.getMinX();
+        }
+    };
+    
+    private static final Function<Bounds, Double> BOUNDS_RIGHT_SIDE = new Function<Bounds, Double>() {
+
+        @Override
+        public Double apply(Bounds t) {
+            return t.getMaxX();
+        }
+    };
+
+    protected Node getNearestNodeLeftOrRight(Bounds currentB, Bounds originB, TraversalEngine engine, Node node, Node reversingNode, Direction dir) {
 
         List<Node> nodes = engine.getAllTargetNodes();
+        
+        Function<Bounds, Double> xSideInDirection = dir == LEFT ? BOUNDS_LEFT_SIDE : BOUNDS_RIGHT_SIDE;
+        Function<Bounds, Double> xSideInOpositeDirection = dir == LEFT ? BOUNDS_RIGHT_SIDE : BOUNDS_LEFT_SIDE;
 
-        Bounds biasedB = new BoundingBox(currentB.getMinX(), originB.getMinY(), currentB.getWidth(), originB.getHeight());
+        Bounds biasedB = new BoundingBox(xSideInDirection.apply(currentB), originB.getMinY(), currentB.getWidth(), originB.getHeight());
 
-        Point2D currentMid2D = new Point2D(currentB.getMinX(), currentB.getMinY()+(currentB.getHeight()/2));
-        Point2D currentTopLeft2D = new Point2D(currentB.getMinX(), currentB.getMinY());
-        Point2D currentBottomLeft2D = new Point2D(currentB.getMinX(), currentB.getMaxY());
+        Point2D currentMid2D = new Point2D(xSideInDirection.apply(currentB), currentB.getMinY()+(currentB.getHeight()/2));
+        Point2D currentTopCorner2D = new Point2D(xSideInDirection.apply(currentB), currentB.getMinY());
+        Point2D currentBottomCorner2D = new Point2D(xSideInDirection.apply(currentB), currentB.getMaxY());
 
-        Point2D originTopLeft2D = new Point2D(originB.getMinX(), originB.getMinY());
+        Point2D originTopCorner2D = new Point2D(xSideInDirection.apply(originB), originB.getMinY());
 
-        TargetNode reversingTargetNode = null;
         TargetNode targetNode = new TargetNode();
         TargetNode nearestNodeCurrentSimple2D = null;
         TargetNode nearestNodeOriginSimple2D = null;
-        TargetNode nearestNodeAverageLeft = null;
+        TargetNode nearestNodeAverage = null;
         TargetNode nearestNodeOnOriginY = null;
         TargetNode nearestNodeOnCurrentY = null;
         TargetNode nearestNodeTopLeft = null;
         TargetNode nearestNodeAnythingAnywhereLeft = null;
 
         if (nodes.size() > 0) {
-            int nodeIndex;
+            /*
+             ** we've just changed direction, and have a node on stack.
+             ** there is a strong preference for this node, just make sure
+             ** it's not a bad choice, as sometimes we got here as a last-chance
+             */
+            if (reversingNode != null) {
+                return reversingNode;
+            }
+            
+            for (int nodeIndex = 0; nodeIndex < nodes.size(); nodeIndex++) {
+                final Node n = nodes.get(nodeIndex);
 
-            if (reversingNode != null) {
-                Bounds targetBounds = reversingNode.localToScene(reversingNode.getLayoutBounds());
-                reversingTargetNode = new TargetNode();
+                Bounds targetBounds = n.localToScene(n.getLayoutBounds());
+                /*
+                ** check that the target node starts after we start
+                ** and the target node ends after we end 
+                */
+                if (dir == LEFT ? currentB.getMinX() >  targetBounds.getMinX() : 
+                        currentB.getMaxX() < targetBounds.getMaxX()) {
 
-                reversingTargetNode.node = reversingNode;
-                reversingTargetNode.bounds = targetBounds;
-
-                /*
-                ** closest biased : simple 2d
-                */
-                double outdB = outDistance(Direction.LEFT, biasedB, targetBounds);
-
-                if (isOnAxis(Direction.LEFT, biasedB, targetBounds)) {
-                    reversingTargetNode.biased2DMetric = outdB + centerSideDistance(Direction.LEFT, biasedB, targetBounds) / 100;
-                }
-                else {
-                    final double cosd = cornerSideDistance(Direction.LEFT, biasedB, targetBounds);
-                    reversingTargetNode.biased2DMetric = 100000 + outdB*outdB + 9*cosd*cosd;
-                }
-                /*
-                ** closest current : simple 2d
-                */
-                double outdC = outDistance(Direction.LEFT, currentB, targetBounds);
-
-                if (isOnAxis(Direction.LEFT, currentB, targetBounds)) {
-                    reversingTargetNode.current2DMetric = outdC + centerSideDistance(Direction.LEFT, currentB, targetBounds) / 100;
-                }
-                else {
-                    final double cosd = cornerSideDistance(Direction.LEFT, currentB, targetBounds);
-                    reversingTargetNode.current2DMetric = 100000 + outdC*outdC + 9*cosd*cosd;
-                }
-
-                reversingTargetNode.topRightDistance = currentTopLeft2D.distance(targetBounds.getMaxX(), targetBounds.getMinY());
-                reversingTargetNode.midDistance = currentMid2D.distance(targetBounds.getMaxX(), targetBounds.getMinY()+(originB.getHeight()/2));
-                reversingTargetNode.bottomRightDistance = currentBottomLeft2D.distance(originB.getMaxX(), targetBounds.getMaxY());
-
-                double currentTopLeftToTargetBottomRightDistance = currentTopLeft2D.distance(targetBounds.getMaxX(), targetBounds.getMaxY());
-                double currentTopLeftToTargetMidDistance = currentTopLeft2D.distance(targetBounds.getMaxX(), targetBounds.getMinY()+(targetBounds.getHeight()/2));
-                double currentBottomLeftToTargetTopRightDistance = currentBottomLeft2D.distance(targetBounds.getMaxX(), targetBounds.getMinY());
-                double currentBottomLeftToTargetBottomRightDistance = currentBottomLeft2D.distance(targetBounds.getMaxX(), targetBounds.getMaxY());
-                double currentBottomLeftToTargetMidDistance = currentBottomLeft2D.distance(targetBounds.getMaxX(), targetBounds.getMinY()+(targetBounds.getHeight()/2));
-                double currentMidToTargetTopRightDistance = currentMid2D.distance(targetBounds.getMaxX(), targetBounds.getMinY());
-                double currentMidToTargetBottomRightDistance = currentMid2D.distance(targetBounds.getMaxX(), targetBounds.getMaxY());
-                double currentMidToTargetMidDistance = currentMid2D.distance(targetBounds.getMaxX(), targetBounds.getMinY()+(targetBounds.getHeight()/2));
-
-                double biasTopLeftToTargetBottomRightDistance = currentTopLeft2D.distance(originB.getMaxX(), targetBounds.getMaxY());
-                double biasTopLeftToTargetMidDistance = currentTopLeft2D.distance(targetBounds.getMaxX(), targetBounds.getMinY()+(originB.getHeight()/2));
-                double biasBottomLeftToTargetMidDistance = currentBottomLeft2D.distance(targetBounds.getMaxX(), targetBounds.getMinY()+(originB.getHeight()/2));
-                double biasMidToTargetBottomRightDistance = currentMid2D.distance(originB.getMaxX(), targetBounds.getMaxY());
-
-                reversingTargetNode.averageDistance =
-                    (reversingTargetNode.topRightDistance+biasTopLeftToTargetBottomRightDistance+biasTopLeftToTargetMidDistance+
-                     currentBottomLeftToTargetTopRightDistance+reversingTargetNode.bottomRightDistance+biasBottomLeftToTargetMidDistance)/7;
-
-                reversingTargetNode.biasShortestDistance = findMin9(reversingTargetNode.topRightDistance, biasTopLeftToTargetBottomRightDistance, biasTopLeftToTargetMidDistance,
-                                                currentBottomLeftToTargetTopRightDistance, reversingTargetNode.bottomRightDistance, biasBottomLeftToTargetMidDistance,
-                                                currentMidToTargetTopRightDistance, biasMidToTargetBottomRightDistance, reversingTargetNode.midDistance);
-
-                reversingTargetNode.shortestDistance = findMin9(reversingTargetNode.topRightDistance, currentTopLeftToTargetBottomRightDistance, currentTopLeftToTargetMidDistance,
-                                            currentBottomLeftToTargetTopRightDistance, currentBottomLeftToTargetBottomRightDistance, currentBottomLeftToTargetMidDistance,
-                                            currentMidToTargetTopRightDistance, currentMidToTargetBottomRightDistance, currentMidToTargetMidDistance);
-            }
-
-
-            for (nodeIndex = 0; nodeIndex < nodes.size(); nodeIndex++) {
-
-                Bounds targetBounds = nodes.get(nodeIndex).localToScene(nodes.get(nodeIndex).getLayoutBounds());
-                /*
-                ** check that the target node starts after we start target.minX > origin.minX
-                ** and the target node ends after we end target.maxX > origin.maxX
-                */
-                if (currentB.getMinX() >  targetBounds.getMinX()) {
-
-                    targetNode.node = nodes.get(nodeIndex);
+                    targetNode.node = n;
                     targetNode.bounds = targetBounds;
 
                     /*
                     ** closest biased : simple 2d
                     */
-                    double outdB = outDistance(Direction.LEFT, biasedB, targetBounds);
+                    double outdB = outDistance(dir, biasedB, targetBounds);
 
-                    if (isOnAxis(Direction.LEFT, biasedB, targetBounds)) {
-                        targetNode.biased2DMetric = outdB + centerSideDistance(Direction.LEFT, biasedB, targetBounds) / 100;
+                    if (isOnAxis(dir, biasedB, targetBounds)) {
+                        targetNode.biased2DMetric = outdB + centerSideDistance(dir, biasedB, targetBounds) / 100;
                     }
                     else {
-                        final double cosd = cornerSideDistance(Direction.LEFT, biasedB, targetBounds);
+                        final double cosd = cornerSideDistance(dir, biasedB, targetBounds);
                         targetNode.biased2DMetric = 100000 + outdB*outdB + 9*cosd*cosd;
                     }
                     /*
                     ** closest current : simple 2d
                     */
-                    double outdC = outDistance(Direction.LEFT, currentB, targetBounds);
+                    double outdC = outDistance(dir, currentB, targetBounds);
 
-                    if (isOnAxis(Direction.LEFT, currentB, targetBounds)) {
-                        targetNode.current2DMetric = outdC + centerSideDistance(Direction.LEFT, currentB, targetBounds) / 100;
+                    if (isOnAxis(dir, currentB, targetBounds)) {
+                        targetNode.current2DMetric = outdC + centerSideDistance(dir, currentB, targetBounds) / 100;
                     }
                     else {
-                        final double cosd = cornerSideDistance(Direction.LEFT, currentB, targetBounds);
+                        final double cosd = cornerSideDistance(dir, currentB, targetBounds);
                         targetNode.current2DMetric = 100000 + outdC*outdC + 9*cosd*cosd;
                     }
 
-                    targetNode.topRightDistance = currentTopLeft2D.distance(targetBounds.getMaxX(), targetBounds.getMinY());
-                    targetNode.midDistance = currentMid2D.distance(targetBounds.getMaxX(), targetBounds.getMinY()+(originB.getHeight()/2));
-                    targetNode.bottomRightDistance = currentBottomLeft2D.distance(originB.getMaxX(), targetBounds.getMaxY());
+                    targetNode.topCornerDistance = currentTopCorner2D.distance(xSideInOpositeDirection.apply(targetBounds), targetBounds.getMinY());
+                    targetNode.midDistance = currentMid2D.distance(xSideInOpositeDirection.apply(targetBounds), targetBounds.getMinY()+(originB.getHeight()/2));
+                    targetNode.bottomCornerDistance = currentBottomCorner2D.distance(xSideInOpositeDirection.apply(originB), targetBounds.getMaxY());
 
-                    double currentTopLeftToTargetBottomRightDistance = currentTopLeft2D.distance(targetBounds.getMaxX(), targetBounds.getMaxY());
-                    double currentTopLeftToTargetMidDistance = currentTopLeft2D.distance(targetBounds.getMaxX(), targetBounds.getMinY()+(targetBounds.getHeight()/2));
-                    double currentBottomLeftToTargetTopRightDistance = currentBottomLeft2D.distance(targetBounds.getMaxX(), targetBounds.getMinY());
-                    double currentBottomLeftToTargetBottomRightDistance = currentBottomLeft2D.distance(targetBounds.getMaxX(), targetBounds.getMaxY());
-                    double currentBottomLeftToTargetMidDistance = currentBottomLeft2D.distance(targetBounds.getMaxX(), targetBounds.getMinY()+(targetBounds.getHeight()/2));
-                    double currentMidToTargetTopRightDistance = currentMid2D.distance(targetBounds.getMaxX(), targetBounds.getMinY());
-                    double currentMidToTargetBottomRightDistance = currentMid2D.distance(targetBounds.getMaxX(), targetBounds.getMaxY());
-                    double currentMidToTargetMidDistance = currentMid2D.distance(targetBounds.getMaxX(), targetBounds.getMinY()+(targetBounds.getHeight()/2));
+                    double currentTopLeftToTargetBottomRightDistance = currentTopCorner2D.distance(xSideInOpositeDirection.apply(targetBounds), targetBounds.getMaxY());
+                    double currentTopLeftToTargetMidDistance = currentTopCorner2D.distance(xSideInOpositeDirection.apply(targetBounds), targetBounds.getMinY()+(targetBounds.getHeight()/2));
+                    double currentBottomLeftToTargetTopRightDistance = currentBottomCorner2D.distance(xSideInOpositeDirection.apply(targetBounds), targetBounds.getMinY());
+                    double currentBottomLeftToTargetBottomRightDistance = currentBottomCorner2D.distance(xSideInOpositeDirection.apply(targetBounds), targetBounds.getMaxY());
+                    double currentBottomLeftToTargetMidDistance = currentBottomCorner2D.distance(xSideInOpositeDirection.apply(targetBounds), targetBounds.getMinY()+(targetBounds.getHeight()/2));
+                    double currentMidToTargetTopRightDistance = currentMid2D.distance(xSideInOpositeDirection.apply(targetBounds), targetBounds.getMinY());
+                    double currentMidToTargetBottomRightDistance = currentMid2D.distance(xSideInOpositeDirection.apply(targetBounds), targetBounds.getMaxY());
+                    double currentMidToTargetMidDistance = currentMid2D.distance(xSideInOpositeDirection.apply(targetBounds), targetBounds.getMinY()+(targetBounds.getHeight()/2));
 
-                    double biasTopLeftToTargetBottomRightDistance = currentTopLeft2D.distance(originB.getMaxX(), targetBounds.getMaxY());
-                    double biasTopLeftToTargetMidDistance = currentTopLeft2D.distance(targetBounds.getMaxX(), targetBounds.getMinY()+(originB.getHeight()/2));
-                    double biasBottomLeftToTargetMidDistance = currentBottomLeft2D.distance(targetBounds.getMaxX(), targetBounds.getMinY()+(originB.getHeight()/2));
-                    double biasMidToTargetBottomRightDistance = currentMid2D.distance(originB.getMaxX(), targetBounds.getMaxY());
+                    double biasTopLeftToTargetBottomRightDistance = currentTopCorner2D.distance(xSideInOpositeDirection.apply(originB), targetBounds.getMaxY());
+                    double biasTopLeftToTargetMidDistance = currentTopCorner2D.distance(xSideInOpositeDirection.apply(targetBounds), targetBounds.getMinY()+(originB.getHeight()/2));
+                    double biasBottomLeftToTargetMidDistance = currentBottomCorner2D.distance(xSideInOpositeDirection.apply(targetBounds), targetBounds.getMinY()+(originB.getHeight()/2));
+                    double biasMidToTargetBottomRightDistance = currentMid2D.distance(xSideInOpositeDirection.apply(originB), targetBounds.getMaxY());
 
                     targetNode.averageDistance =
-                        (targetNode.topRightDistance+biasTopLeftToTargetBottomRightDistance+biasTopLeftToTargetMidDistance+
-                         currentBottomLeftToTargetTopRightDistance+targetNode.bottomRightDistance+biasBottomLeftToTargetMidDistance)/7;
+                        (targetNode.topCornerDistance+biasTopLeftToTargetBottomRightDistance+biasTopLeftToTargetMidDistance+
+                         currentBottomLeftToTargetTopRightDistance+targetNode.bottomCornerDistance+biasBottomLeftToTargetMidDistance)/7;
 
                     targetNode.biasShortestDistance =
-                        findMin9(targetNode.topRightDistance, biasTopLeftToTargetBottomRightDistance, biasTopLeftToTargetMidDistance,
-                                 currentBottomLeftToTargetTopRightDistance, targetNode.bottomRightDistance, biasBottomLeftToTargetMidDistance,
+                        findMin(targetNode.topCornerDistance, biasTopLeftToTargetBottomRightDistance, biasTopLeftToTargetMidDistance,
+                                 currentBottomLeftToTargetTopRightDistance, targetNode.bottomCornerDistance, biasBottomLeftToTargetMidDistance,
                                  currentMidToTargetTopRightDistance, biasMidToTargetBottomRightDistance, targetNode.midDistance);
 
                     targetNode.shortestDistance =
-                        findMin9(targetNode.topRightDistance, currentTopLeftToTargetBottomRightDistance, currentTopLeftToTargetMidDistance,
+                        findMin(targetNode.topCornerDistance, currentTopLeftToTargetBottomRightDistance, currentTopLeftToTargetMidDistance,
                                  currentBottomLeftToTargetTopRightDistance, currentBottomLeftToTargetBottomRightDistance, currentBottomLeftToTargetMidDistance,
                                  currentMidToTargetTopRightDistance, currentMidToTargetBottomRightDistance, currentMidToTargetMidDistance);
 
-
                     /*
                     ** closest biased : simple 2d
                     */
@@ -1494,7 +922,7 @@
                     ** on the Origin Y
                     */
                     if ((originB.getMaxY() > targetBounds.getMinY()) && (targetBounds.getMaxY() > originB.getMinY())) {
-                        if (nearestNodeOnOriginY == null || nearestNodeOnOriginY.topRightDistance > targetNode.topRightDistance) {
+                        if (nearestNodeOnOriginY == null || nearestNodeOnOriginY.topCornerDistance > targetNode.topCornerDistance) {
 
                             if (nearestNodeOnOriginY == null) {
                                 nearestNodeOnOriginY = new TargetNode();
@@ -1506,7 +934,7 @@
                     ** on the Current Y
                     */
                     if ((currentB.getMaxY() > targetBounds.getMinY()) && (targetBounds.getMaxY() > currentB.getMinY())) {
-                        if (nearestNodeOnCurrentY == null || nearestNodeOnCurrentY.topRightDistance > targetNode.topRightDistance) {
+                        if (nearestNodeOnCurrentY == null || nearestNodeOnCurrentY.topCornerDistance > targetNode.topCornerDistance) {
 
                             if (nearestNodeOnCurrentY == null) {
                                 nearestNodeOnCurrentY = new TargetNode();
@@ -1517,7 +945,7 @@
                     /*
                     ** Closest top left / top right corners.
                     */
-                    if (nearestNodeTopLeft == null || nearestNodeTopLeft.topRightDistance > targetNode.topRightDistance) {
+                    if (nearestNodeTopLeft == null || nearestNodeTopLeft.topCornerDistance > targetNode.topCornerDistance) {
 
                         if (nearestNodeTopLeft == null) {
                             nearestNodeTopLeft = new TargetNode();
@@ -1525,12 +953,12 @@
                         nearestNodeTopLeft.copy(targetNode);
                     }
 
-                    if (nearestNodeAverageLeft == null || nearestNodeAverageLeft.averageDistance > targetNode.averageDistance) {
+                    if (nearestNodeAverage == null || nearestNodeAverage.averageDistance > targetNode.averageDistance) {
 
-                        if (nearestNodeAverageLeft == null) {
-                            nearestNodeAverageLeft = new TargetNode();
+                        if (nearestNodeAverage == null) {
+                            nearestNodeAverage = new TargetNode();
                         }
-                        nearestNodeAverageLeft.copy(targetNode);
+                        nearestNodeAverage.copy(targetNode);
                     }
 
                     if (nearestNodeAnythingAnywhereLeft == null || nearestNodeAnythingAnywhereLeft.shortestDistance > targetNode.shortestDistance) {
@@ -1545,32 +973,19 @@
         }
         nodes.clear();
 
-        if (reversingTargetNode != null) {
-            reversingTargetNode.originTopRightDistance = originTopLeft2D.distance(reversingTargetNode.bounds.getMinX(), reversingTargetNode.bounds.getMinY());
+        if (nearestNodeOnOriginY != null) {
+            nearestNodeOnOriginY.originTopCornerDistance = originTopCorner2D.distance(xSideInOpositeDirection.apply(nearestNodeOnOriginY.bounds), nearestNodeOnOriginY.bounds.getMinY());
         }
-        if (nearestNodeOriginSimple2D != null) {
-            nearestNodeOriginSimple2D.originTopRightDistance = originTopLeft2D.distance(nearestNodeOriginSimple2D.bounds.getMinX(), nearestNodeOriginSimple2D.bounds.getMinY());
+        
+        if (nearestNodeOnCurrentY != null) {
+            nearestNodeOnCurrentY.originTopCornerDistance = originTopCorner2D.distance(xSideInOpositeDirection.apply(nearestNodeOnCurrentY.bounds), nearestNodeOnCurrentY.bounds.getMinY());
         }
-        if (nearestNodeCurrentSimple2D != null) {
-            nearestNodeCurrentSimple2D.originTopRightDistance = originTopLeft2D.distance(nearestNodeCurrentSimple2D.bounds.getMinX(), nearestNodeCurrentSimple2D.bounds.getMinY());
-        }
-        if (nearestNodeOnOriginY != null) {
-            nearestNodeOnOriginY.originTopRightDistance = originTopLeft2D.distance(nearestNodeOnOriginY.bounds.getMinX(), nearestNodeOnOriginY.bounds.getMinY());
-        }
-        if (nearestNodeOnCurrentY != null) {
-            nearestNodeOnCurrentY.originTopRightDistance = originTopLeft2D.distance(nearestNodeOnCurrentY.bounds.getMinX(), nearestNodeOnCurrentY.bounds.getMinY());
-        }
-        if (nearestNodeAverageLeft != null) {
-            nearestNodeAverageLeft.originTopRightDistance = originTopLeft2D.distance(nearestNodeAverageLeft.bounds.getMinX(), nearestNodeAverageLeft.bounds.getMinY());
-        }
-        if (nearestNodeTopLeft != null) {
-            nearestNodeTopLeft.originTopRightDistance = originTopLeft2D.distance(nearestNodeTopLeft.bounds.getMinX(), nearestNodeTopLeft.bounds.getMinY());
-        }
-        if (nearestNodeAnythingAnywhereLeft != null) {
-            nearestNodeAnythingAnywhereLeft.originTopRightDistance = originTopLeft2D.distance(nearestNodeAnythingAnywhereLeft.bounds.getMinX(), nearestNodeAnythingAnywhereLeft.bounds.getMinY());
+        
+        if (nearestNodeAverage != null) {
+            nearestNodeAverage.originTopCornerDistance = originTopCorner2D.distance(xSideInOpositeDirection.apply(nearestNodeAverage.bounds), nearestNodeAverage.bounds.getMinY());
         }
 
-        if (nearestNodeOnCurrentY == null && nearestNodeOnOriginY == null && reversingTargetNode == null) {
+        if (nearestNodeOnCurrentY == null && nearestNodeOnOriginY == null) {
             cacheStartTraversalNode = null;
             cacheStartTraversalDirection = null;
             reverseDirection = false;
@@ -1578,9 +993,6 @@
         }
 
         if (focusLogger.isLoggable(Level.FINER)) {
-            if (reversingTargetNode != null) {
-                focusLogger.finer("reversingTargetNode.node : "+reversingTargetNode.node);
-            }
             if (nearestNodeOriginSimple2D != null) {
                 focusLogger.finer("nearestNodeOriginSimple2D.node : "+nearestNodeOriginSimple2D.node);
             }
@@ -1593,8 +1005,8 @@
             if (nearestNodeOnCurrentY != null) {
                 focusLogger.finer("nearestNodeOnCurrentY.node : "+nearestNodeOnCurrentY.node);
             }
-            if (nearestNodeAverageLeft != null) {
-                focusLogger.finer("nearestNodeAverageLeft.node : "+nearestNodeAverageLeft.node);
+            if (nearestNodeAverage != null) {
+                focusLogger.finer("nearestNodeAverageLeft.node : "+nearestNodeAverage.node);
             }
             if (nearestNodeTopLeft != null) {
                 focusLogger.finer("nearestNodeTopLeft.node : "+nearestNodeTopLeft.node);
@@ -1604,73 +1016,47 @@
             }
         }
 
-        /*
-        ** we've just changed direction, and have a node on stack.
-        ** there is a strong preference for this node, just make sure
-        ** it's not a bad choice, as sometimes we got here as a last-chance
-        */
-        if (reversingTargetNode != null) {
-            return reversingNode;
-        }
-
         if (nearestNodeOnOriginY != null && nearestNodeOnOriginY.biasShortestDistance < Double.MAX_VALUE) {
             /*
-            ** there's a preference, all else being equal, to return nearestNodeOnOriginY
-            */
-            if (nearestNodeOnOriginY != null && nearestNodeOnCurrentY != null &&
-                (nearestNodeOnOriginY.node == nearestNodeOnCurrentY.node)) {
+             ** there's a preference, all else being equal, to return nearestNodeOnOriginY
+             */
+            if (nearestNodeOnCurrentY != null && nearestNodeOnOriginY.node == nearestNodeOnCurrentY.node
+                    && ((nearestNodeAverage != null && nearestNodeOnOriginY.node == nearestNodeAverage.node)
+                    || (nearestNodeTopLeft != null && nearestNodeOnOriginY.node == nearestNodeTopLeft.node)
+                    || (nearestNodeAnythingAnywhereLeft != null && nearestNodeOnOriginY.node == nearestNodeAnythingAnywhereLeft.node))) {
                 return nearestNodeOnOriginY.node;
             }
-            if (nearestNodeOnOriginY != null && nearestNodeOnCurrentY != null && nearestNodeAverageLeft != null &&
-                (nearestNodeOnOriginY.node == nearestNodeOnCurrentY.node) && (nearestNodeOnOriginY.node == nearestNodeAverageLeft.node)) {
-                return nearestNodeOnOriginY.node;
-            }
-            if (nearestNodeOnOriginY != null && nearestNodeOnCurrentY != null && nearestNodeTopLeft != null &&
-                (nearestNodeOnOriginY.node == nearestNodeOnCurrentY.node) && (nearestNodeOnOriginY.node == nearestNodeTopLeft.node)) {
-                return nearestNodeOnOriginY.node;
-            }
-            if (nearestNodeOnOriginY != null && nearestNodeOnCurrentY != null && nearestNodeAnythingAnywhereLeft != null &&
-                (nearestNodeOnOriginY.node == nearestNodeOnCurrentY.node) && (nearestNodeOnOriginY.node == nearestNodeAnythingAnywhereLeft.node)) {
-                return nearestNodeOnOriginY.node;
-            }
-            if (nearestNodeOnOriginY != null && nearestNodeAverageLeft != null &&
-                (nearestNodeOnOriginY.node == nearestNodeAverageLeft.node)) {
+
+            if (nearestNodeAverage != null && nearestNodeOnOriginY.node == nearestNodeAverage.node) {
                 return nearestNodeOnOriginY.node;
             }
 
             if (nearestNodeOnCurrentY != null && nearestNodeOnCurrentY.biasShortestDistance < Double.MAX_VALUE) {
-                if (nearestNodeOnOriginY == null ||
-                    (nearestNodeOnCurrentY.bottomRightDistance < nearestNodeOnOriginY.bottomRightDistance) &&
-                    (nearestNodeOnCurrentY.originTopRightDistance < nearestNodeOnOriginY.originTopRightDistance) &&
-                    (nearestNodeOnCurrentY.bounds.getMinY() - currentTopLeft2D.getY()) < (nearestNodeOnOriginY.bounds.getMinY() - currentTopLeft2D.getY())  )  {
+                if ((nearestNodeOnCurrentY.bottomCornerDistance < nearestNodeOnOriginY.bottomCornerDistance)
+                        && (nearestNodeOnCurrentY.originTopCornerDistance < nearestNodeOnOriginY.originTopCornerDistance)
+                        && (nearestNodeOnCurrentY.bounds.getMinY() - currentTopCorner2D.getY()) < (nearestNodeOnOriginY.bounds.getMinY() - currentTopCorner2D.getY())) {
 
                     return nearestNodeOnCurrentY.node;
-                }
-                else if (nearestNodeOnOriginY != null) {
-                    if (nearestNodeAverageLeft != null || nearestNodeOnOriginY.averageDistance < nearestNodeAverageLeft.averageDistance) {
-                        return nearestNodeOnOriginY.node;
-                    }
+                } else if (nearestNodeAverage == null || nearestNodeOnOriginY.averageDistance < nearestNodeAverage.averageDistance) {
+                    return nearestNodeOnOriginY.node;
                 }
             }
-        }
-        else {
+        } else {
             if (nearestNodeOnOriginY == null && nearestNodeOnCurrentY == null && nearestNodeCurrentSimple2D != null) {
-                if (nearestNodeAverageLeft != null && nearestNodeTopLeft != null && nearestNodeAverageLeft != null &&  nearestNodeAnythingAnywhereLeft != null &&
-                    nearestNodeAverageLeft.node == nearestNodeTopLeft.node && nearestNodeAverageLeft.node == nearestNodeAnythingAnywhereLeft.node) {
-                    return nearestNodeAverageLeft.node;
+                if (nearestNodeAverage != null && nearestNodeTopLeft != null
+                        && nearestNodeAverage.node == nearestNodeTopLeft.node && nearestNodeAverage.node == nearestNodeAnythingAnywhereLeft.node) {
+                    return nearestNodeAverage.node;
                 }
                 return nearestNodeCurrentSimple2D.node;
-            }
-            else if (nearestNodeAverageLeft != null && nearestNodeTopLeft != null && nearestNodeAnythingAnywhereLeft != null &&
-                     nearestNodeAverageLeft.biasShortestDistance == nearestNodeTopLeft.biasShortestDistance &&
-                     nearestNodeAverageLeft.biasShortestDistance == nearestNodeAnythingAnywhereLeft.biasShortestDistance &&
-                     nearestNodeAverageLeft.biasShortestDistance < Double.MAX_VALUE) {
+            } else if (nearestNodeAverage != null && nearestNodeTopLeft != null && nearestNodeAnythingAnywhereLeft != null
+                    && nearestNodeAverage.biasShortestDistance == nearestNodeTopLeft.biasShortestDistance
+                    && nearestNodeAverage.biasShortestDistance == nearestNodeAnythingAnywhereLeft.biasShortestDistance
+                    && nearestNodeAverage.biasShortestDistance < Double.MAX_VALUE) {
 
-                if (nearestNodeOnOriginY != null && nearestNodeOnOriginY.originTopRightDistance < nearestNodeAverageLeft.originTopRightDistance) {
+                if (nearestNodeOnOriginY != null && nearestNodeOnOriginY.originTopCornerDistance < nearestNodeAverage.originTopCornerDistance) {
                     return nearestNodeOnOriginY.node;
-                }
-                else {
-                    return nearestNodeAverageLeft.node;
+                } else {
+                    return nearestNodeAverage.node;
                 }
             }
         }
@@ -1678,11 +1064,11 @@
         /*
         ** is the average closer?
         */
-        if (nearestNodeAverageLeft != null && (nearestNodeOnOriginY == null || nearestNodeAverageLeft.biasShortestDistance < nearestNodeOnOriginY.biasShortestDistance)) {
+        if (nearestNodeAverage != null && (nearestNodeOnOriginY == null || nearestNodeAverage.biasShortestDistance < nearestNodeOnOriginY.biasShortestDistance)) {
             /*
             ** but is one in the way
             */
-            if (nearestNodeOnOriginY != null && (nearestNodeOnOriginY.bounds.getMaxX() >= nearestNodeAverageLeft.bounds.getMaxX())) {
+            if (nearestNodeOnOriginY != null && (xSideInOpositeDirection.apply(nearestNodeOnOriginY.bounds) >= xSideInOpositeDirection.apply(nearestNodeAverage.bounds))) {
                 return nearestNodeOnOriginY.node;
             }
             /*
@@ -1696,14 +1082,14 @@
                 return nearestNodeOnCurrentY.node;
             }
 
-            if (nearestNodeOnOriginY != null &&  nearestNodeAverageLeft != null && nearestNodeOnOriginY.biasShortestDistance < Double.MAX_VALUE && (nearestNodeOnOriginY.originTopRightDistance < nearestNodeAverageLeft.originTopRightDistance)) {
+            if (nearestNodeOnOriginY != null && nearestNodeOnOriginY.biasShortestDistance < Double.MAX_VALUE && (nearestNodeOnOriginY.originTopCornerDistance < nearestNodeAverage.originTopCornerDistance)) {
                 return nearestNodeOnOriginY.node;
             }
-            return nearestNodeAverageLeft.node;
+            return nearestNodeAverage.node;
         }
 
 
-        if (nearestNodeOnOriginY != null && nearestNodeOnCurrentY != null && nearestNodeOnOriginY.bottomRightDistance < nearestNodeOnCurrentY.bottomRightDistance) {
+        if (nearestNodeOnOriginY != null && nearestNodeOnCurrentY != null && nearestNodeOnOriginY.bottomCornerDistance < nearestNodeOnCurrentY.bottomCornerDistance) {
             return nearestNodeOnOriginY.node;
         }
 
@@ -1719,474 +1105,38 @@
         */
         if (nearestNodeOnOriginY != null) {
             return nearestNodeOnOriginY.node;
-        }
-        else if (nearestNodeOriginSimple2D != null) {
+        } else if (nearestNodeOriginSimple2D != null) {
             return nearestNodeOriginSimple2D.node;
-        }
-        else if (nearestNodeOnCurrentY != null) {
+        } else if (nearestNodeOnCurrentY != null) {
             return nearestNodeOnCurrentY.node;
-        }
-        else if (nearestNodeAverageLeft != null) {
-            return nearestNodeAverageLeft.node;
-        }
-        else if (nearestNodeTopLeft != null) {
+        } else if (nearestNodeAverage != null) {
+            return nearestNodeAverage.node;
+        } else if (nearestNodeTopLeft != null) {
             return nearestNodeTopLeft.node;
-        }
-        else if (nearestNodeAnythingAnywhereLeft != null) {
+        } else if (nearestNodeAnythingAnywhereLeft != null) {
             return nearestNodeAnythingAnywhereLeft.node;
         }
         return null;
     }
 
-    protected Node getNearestNodeRight(Bounds currentB, Bounds originB, TraversalEngine engine, Node node, Node reversingNode) {
-
-        List<Node> nodes = engine.getAllTargetNodes();
-
-        Bounds biasedB = new BoundingBox(currentB.getMinX(), originB.getMinY(), currentB.getWidth(), originB.getHeight());
-
-        Point2D currentMid2D = new Point2D(currentB.getMaxX(), currentB.getMinY()+(currentB.getHeight()/2));
-        Point2D currentTopRight2D = new Point2D(currentB.getMaxX(), currentB.getMinY());
-        Point2D currentBottomRight2D = new Point2D(currentB.getMaxX(), currentB.getMaxY());
-
-        Point2D originTopRight2D = new Point2D(originB.getMaxX(), originB.getMinY());
-
-        TargetNode reversingTargetNode = null;
-        TargetNode targetNode = new TargetNode();
-        TargetNode nearestNodeCurrentSimple2D = null;
-        TargetNode nearestNodeOriginSimple2D = null;
-        TargetNode nearestNodeAverageRight = null;
-        TargetNode nearestNodeOnOriginY = null;
-        TargetNode nearestNodeOnCurrentY = null;
-        TargetNode nearestNodeTopRight = null;
-        TargetNode nearestNodeAnythingAnywhereRight = null;
-
-        if (nodes.size() > 0) {
-            int nodeIndex;
-
-            if (reversingNode != null) {
-                Bounds targetBounds = reversingNode.localToScene(reversingNode.getLayoutBounds());
-                reversingTargetNode = new TargetNode();
-
-                reversingTargetNode.node = reversingNode;
-                reversingTargetNode.bounds = targetBounds;
-
-                /*
-                ** closest biased : simple 2d
-                */
-                double outdB = outDistance(Direction.RIGHT, biasedB, targetBounds);
-
-                if (isOnAxis(Direction.RIGHT, biasedB, targetBounds)) {
-                    reversingTargetNode.biased2DMetric = outdB + centerSideDistance(Direction.RIGHT, biasedB, targetBounds) / 100;
-                }
-                else {
-                    final double cosd = cornerSideDistance(Direction.RIGHT, biasedB, targetBounds);
-                    reversingTargetNode.biased2DMetric = 100000 + outdB*outdB + 9*cosd*cosd;
-                }
-                /*
-                ** closest current : simple 2d
-                */
-                double outdC = outDistance(Direction.RIGHT, currentB, targetBounds);
-
-                if (isOnAxis(Direction.RIGHT, currentB, targetBounds)) {
-                    reversingTargetNode.current2DMetric = outdC + centerSideDistance(Direction.RIGHT, currentB, targetBounds) / 100;
-                }
-                else {
-                    final double cosd = cornerSideDistance(Direction.RIGHT, currentB, targetBounds);
-                    reversingTargetNode.current2DMetric = 100000 + outdC*outdC + 9*cosd*cosd;
-                }
-
-                reversingTargetNode.topLeftDistance = currentTopRight2D.distance(targetBounds.getMinX(), targetBounds.getMinY());
-                reversingTargetNode.midDistance  = currentMid2D.distance(targetBounds.getMinX(), targetBounds.getMinY()+(originB.getHeight()/2));
-                reversingTargetNode.bottomLeftDistance = currentBottomRight2D.distance(originB.getMinX(), targetBounds.getMaxY());
-
-                double currentTopRightToTargetBottomLeftDistance = currentTopRight2D.distance(targetBounds.getMinX(), targetBounds.getMaxY());
-                double currentTopRightToTargetMidDistance = currentTopRight2D.distance(targetBounds.getMinX(), targetBounds.getMinY()+(targetBounds.getHeight()/2));
-                double currentBottomRightToTargetTopLeftDistance = currentBottomRight2D.distance(targetBounds.getMinX(), targetBounds.getMinY());
-                double currentBottomRightToTargetBottomLeftDistance = currentBottomRight2D.distance(targetBounds.getMinX(), targetBounds.getMaxY());
-                double currentBottomRightToTargetMidDistance = currentBottomRight2D.distance(targetBounds.getMinX(), targetBounds.getMinY()+(targetBounds.getHeight()/2));
-                double currentMidToTargetTopLeftDistance = currentMid2D.distance(targetBounds.getMinX(), targetBounds.getMinY());
-                double currentMidToTargetBottomLeftDistance = currentMid2D.distance(targetBounds.getMinX(), targetBounds.getMaxY());
-                double currentMidToTargetMidDistance = currentMid2D.distance(targetBounds.getMinX(), targetBounds.getMinY()+(targetBounds.getHeight()/2));
-
-                double biasTopRightToTargetBottomLeftDistance = currentTopRight2D.distance(originB.getMinX(), targetBounds.getMaxY());
-                double biasTopRightToTargetMidDistance = currentTopRight2D.distance(targetBounds.getMinX(), targetBounds.getMinY()+(originB.getHeight()/2));
-                double biasBottomRightToTargetMidDistance = currentBottomRight2D.distance(targetBounds.getMinX(), targetBounds.getMinY()+(originB.getHeight()/2));
-                double biasMidToTargetBottomLeftDistance = currentMid2D.distance(originB.getMinX(), targetBounds.getMaxY());
-
-                reversingTargetNode.averageDistance =
-                    (reversingTargetNode.topLeftDistance+biasTopRightToTargetBottomLeftDistance+biasTopRightToTargetMidDistance+
-                     currentBottomRightToTargetTopLeftDistance+reversingTargetNode.bottomLeftDistance+biasBottomRightToTargetMidDistance)/7;
-
-
-                reversingTargetNode.biasShortestDistance =
-                    findMin9(reversingTargetNode.topLeftDistance, biasTopRightToTargetBottomLeftDistance, biasTopRightToTargetMidDistance,
-                             currentBottomRightToTargetTopLeftDistance, reversingTargetNode.bottomLeftDistance, biasBottomRightToTargetMidDistance,
-                             currentMidToTargetTopLeftDistance, biasMidToTargetBottomLeftDistance, reversingTargetNode.midDistance);
-
-                reversingTargetNode.shortestDistance =
-                    findMin9(reversingTargetNode.topLeftDistance, currentTopRightToTargetBottomLeftDistance, currentTopRightToTargetMidDistance,
-                             currentBottomRightToTargetTopLeftDistance, currentBottomRightToTargetBottomLeftDistance, currentBottomRightToTargetMidDistance,
-                             currentMidToTargetTopLeftDistance, currentMidToTargetBottomLeftDistance, currentMidToTargetMidDistance);
-            }
-
-
-            for (nodeIndex = 0; nodeIndex < nodes.size(); nodeIndex++) {
-
-                Bounds targetBounds = nodes.get(nodeIndex).localToScene(nodes.get(nodeIndex).getLayoutBounds());
-                /*
-                ** check that the target node starts after we start target.minX > origin.minX
-                ** and the target node ends after we end target.maxX > origin.maxX
-                */
-                if (currentB.getMaxX() <  targetBounds.getMaxX()) {
-
-                    targetNode.node = nodes.get(nodeIndex);
-                    targetNode.bounds = targetBounds;
-
-                    /*
-                    ** closest biased : simple 2d
-                    */
-                    double outdB = outDistance(Direction.RIGHT, biasedB, targetBounds);
-
-                    if (isOnAxis(Direction.RIGHT, biasedB, targetBounds)) {
-                        targetNode.biased2DMetric = outdB + centerSideDistance(Direction.RIGHT, biasedB, targetBounds) / 100;
-                    }
-                    else {
-                        final double cosd = cornerSideDistance(Direction.RIGHT, biasedB, targetBounds);
-                        targetNode.biased2DMetric = 100000 + outdB*outdB + 9*cosd*cosd;
-                    }
-                    /*
-                    ** closest current : simple 2d
-                    */
-                    double outdC = outDistance(Direction.RIGHT, currentB, targetBounds);
-
-                    if (isOnAxis(Direction.RIGHT, currentB, targetBounds)) {
-                        targetNode.current2DMetric = outdC + centerSideDistance(Direction.RIGHT, currentB, targetBounds) / 100;
-                    }
-                    else {
-                        final double cosd = cornerSideDistance(Direction.RIGHT, currentB, targetBounds);
-                        targetNode.current2DMetric = 100000 + outdC*outdC + 9*cosd*cosd;
-                    }
-
-                    targetNode.topLeftDistance = currentTopRight2D.distance(targetBounds.getMinX(), targetBounds.getMinY());
-                    targetNode.midDistance = currentMid2D.distance(targetBounds.getMinX(), targetBounds.getMinY()+(originB.getHeight()/2));
-                    targetNode.bottomLeftDistance = currentBottomRight2D.distance(originB.getMinX(), targetBounds.getMaxY());
-
-                    double currentTopRightToTargetBottomLeftDistance = currentTopRight2D.distance(targetBounds.getMinX(), targetBounds.getMaxY());
-                    double currentTopRightToTargetMidDistance = currentTopRight2D.distance(targetBounds.getMinX(), targetBounds.getMinY()+(targetBounds.getHeight()/2));
-                    double currentBottomRightToTargetTopLeftDistance = currentBottomRight2D.distance(targetBounds.getMinX(), targetBounds.getMinY());
-                    double currentBottomRightToTargetBottomLeftDistance = currentBottomRight2D.distance(targetBounds.getMinX(), targetBounds.getMaxY());
-                    double currentBottomRightToTargetMidDistance = currentBottomRight2D.distance(targetBounds.getMinX(), targetBounds.getMinY()+(targetBounds.getHeight()/2));
-                    double currentMidToTargetTopLeftDistance = currentMid2D.distance(targetBounds.getMinX(), targetBounds.getMinY());
-                    double currentMidToTargetBottomLeftDistance = currentMid2D.distance(targetBounds.getMinX(), targetBounds.getMaxY());
-                    double currentMidToTargetMidDistance = currentMid2D.distance(targetBounds.getMinX(), targetBounds.getMinY()+(targetBounds.getHeight()/2));
-
-                    double biasTopRightToTargetBottomLeftDistance = currentTopRight2D.distance(originB.getMinX(), targetBounds.getMaxY());
-                    double biasTopRightToTargetMidDistance = currentTopRight2D.distance(targetBounds.getMinX(), targetBounds.getMinY()+(originB.getHeight()/2));
-                    double biasBottomRightToTargetMidDistance = currentBottomRight2D.distance(targetBounds.getMinX(), targetBounds.getMinY()+(originB.getHeight()/2));
-                    double biasMidToTargetBottomLeftDistance = currentMid2D.distance(originB.getMinX(), targetBounds.getMaxY());
-
-                    targetNode.averageDistance =
-                        (targetNode.topLeftDistance+biasTopRightToTargetBottomLeftDistance+biasTopRightToTargetMidDistance+
-                         currentBottomRightToTargetTopLeftDistance+targetNode.bottomLeftDistance+biasBottomRightToTargetMidDistance)/7;
-
-                    targetNode.biasShortestDistance =
-                        findMin9(targetNode.topLeftDistance, biasTopRightToTargetBottomLeftDistance, biasTopRightToTargetMidDistance,
-                                 currentBottomRightToTargetTopLeftDistance, targetNode.bottomLeftDistance, biasBottomRightToTargetMidDistance,
-                                 currentMidToTargetTopLeftDistance, biasMidToTargetBottomLeftDistance, targetNode.midDistance);
-
-                    targetNode.shortestDistance =
-                        findMin9(targetNode.topLeftDistance, currentTopRightToTargetBottomLeftDistance, currentTopRightToTargetMidDistance,
-                                 currentBottomRightToTargetTopLeftDistance, currentBottomRightToTargetBottomLeftDistance, currentBottomRightToTargetMidDistance,
-                                 currentMidToTargetTopLeftDistance, currentMidToTargetBottomLeftDistance, currentMidToTargetMidDistance);
-
-
-                    /*
-                    ** closest biased : simple 2d
-                    */
-                    if (outdB >= 0.0) {
-                        if (nearestNodeOriginSimple2D == null || targetNode.biased2DMetric < nearestNodeOriginSimple2D.biased2DMetric) {
-
-                            if (nearestNodeOriginSimple2D == null) {
-                                nearestNodeOriginSimple2D = new TargetNode();
-                            }
-                            nearestNodeOriginSimple2D.copy(targetNode);
-                        }
-                    }
-                    /*
-                    ** closest current : simple 2d
-                    */
-                    if (outdC >= 0.0) {
-                        if (nearestNodeCurrentSimple2D == null || targetNode.current2DMetric < nearestNodeCurrentSimple2D.current2DMetric) {
-
-                            if (nearestNodeCurrentSimple2D == null) {
-                                nearestNodeCurrentSimple2D = new TargetNode();
-                            }
-                            nearestNodeCurrentSimple2D.copy(targetNode);
-                        }
-                    }
-                    /*
-                    ** on the Origin Y
-                    */
-                    if ((originB.getMaxY() > targetBounds.getMinY()) && (targetBounds.getMaxY() > originB.getMinY())) {
-                        if (nearestNodeOnOriginY == null || nearestNodeOnOriginY.topLeftDistance > targetNode.topLeftDistance) {
-
-                            if (nearestNodeOnOriginY == null) {
-                                nearestNodeOnOriginY = new TargetNode();
-                            }
-                            nearestNodeOnOriginY.copy(targetNode);
-                        }
-                    }
-                    /*
-                    ** on the Current Y
-                    */
-                    if ((currentB.getMaxY() > targetBounds.getMinY()) && (targetBounds.getMaxY() > currentB.getMinY())) {
-                        if (nearestNodeOnCurrentY == null || nearestNodeOnCurrentY.topLeftDistance > targetNode.topRightDistance) {
-
-                            if (nearestNodeOnCurrentY == null) {
-                                nearestNodeOnCurrentY = new TargetNode();
-                            }
-                            nearestNodeOnCurrentY.copy(targetNode);
-                        }
-                    }
-                    /*
-                    ** Closest top right / top left corners.
-                    */
-                    if (nearestNodeTopRight == null || nearestNodeTopRight.topLeftDistance > targetNode.topLeftDistance) {
-                        if (nearestNodeTopRight == null) {
-                            nearestNodeTopRight = new TargetNode();
-                        }
-                        nearestNodeTopRight.copy(targetNode);
-                    }
-
-                    if (nearestNodeAverageRight == null || nearestNodeAverageRight.averageDistance > targetNode.averageDistance) {
-                        if (nearestNodeAverageRight == null) {
-                            nearestNodeAverageRight = new TargetNode();
-                        }
-                        nearestNodeAverageRight.copy(targetNode);
-                    }
-
-                    if (nearestNodeAnythingAnywhereRight == null || nearestNodeAnythingAnywhereRight.shortestDistance > targetNode.shortestDistance) {
-
-                        if (nearestNodeAnythingAnywhereRight == null) {
-                            nearestNodeAnythingAnywhereRight = new TargetNode();
-                        }
-                        nearestNodeAnythingAnywhereRight.copy(targetNode);
-                    }
-                }
-            }
-        }
-        nodes.clear();
-
-        if (reversingTargetNode != null) {
-            reversingTargetNode.originTopLeftDistance = originTopRight2D.distance(reversingTargetNode.bounds.getMinX(), reversingTargetNode.bounds.getMinY());
-        }
-        if (nearestNodeOriginSimple2D != null) {
-            nearestNodeOriginSimple2D.originTopLeftDistance = originTopRight2D.distance(nearestNodeOriginSimple2D.bounds.getMinX(), nearestNodeOriginSimple2D.bounds.getMinY());
-        }
-        if (nearestNodeCurrentSimple2D != null) {
-            nearestNodeCurrentSimple2D.originTopLeftDistance = originTopRight2D.distance(nearestNodeCurrentSimple2D.bounds.getMinX(), nearestNodeCurrentSimple2D.bounds.getMinY());
-        }
-        if (nearestNodeOnOriginY != null) {
-            nearestNodeOnOriginY.originTopLeftDistance = originTopRight2D.distance(nearestNodeOnOriginY.bounds.getMinX(), nearestNodeOnOriginY.bounds.getMinY());
-        }
-        if (nearestNodeOnCurrentY != null) {
-            nearestNodeOnCurrentY.originTopLeftDistance = originTopRight2D.distance(nearestNodeOnCurrentY.bounds.getMinX(), nearestNodeOnCurrentY.bounds.getMinY());
-        }
-        if (nearestNodeAverageRight != null) {
-            nearestNodeAverageRight.originTopLeftDistance = originTopRight2D.distance(nearestNodeAverageRight.bounds.getMinX(), nearestNodeAverageRight.bounds.getMinY());
-        }
-        if (nearestNodeTopRight != null) {
-            nearestNodeTopRight.originTopLeftDistance = originTopRight2D.distance(nearestNodeTopRight.bounds.getMinX(), nearestNodeTopRight.bounds.getMinY());
-        }
-        if (nearestNodeAnythingAnywhereRight != null) {
-            nearestNodeAnythingAnywhereRight.originTopLeftDistance = originTopRight2D.distance(nearestNodeAnythingAnywhereRight.bounds.getMinX(), nearestNodeAnythingAnywhereRight.bounds.getMinY());
-        }
-
-        if (nearestNodeOnCurrentY == null && nearestNodeOnOriginY == null && reversingTargetNode == null) {
-            cacheStartTraversalNode = null;
-            cacheStartTraversalDirection = null;
-            reverseDirection = false;
-            traversalNodeStack.clear();
-        }
-
-        if (focusLogger.isLoggable(Level.FINER)) {
-            if (reversingTargetNode != null) {
-                focusLogger.finer("reversingTargetNode.node : "+reversingTargetNode.node);
-            }
-            if (nearestNodeOriginSimple2D != null) {
-                focusLogger.finer("nearestNodeOriginSimple2D.node : "+nearestNodeOriginSimple2D.node);
-            }
-            if (nearestNodeCurrentSimple2D != null) {
-                focusLogger.finer("nearestNodeCurrentSimple2D.node : "+nearestNodeCurrentSimple2D.node);
-            }
-            if (nearestNodeOnOriginY != null) {
-                focusLogger.finer("nearestNodeOnOriginY.node : "+nearestNodeOnOriginY.node);
-            }
-            if (nearestNodeOnCurrentY != null) {
-                focusLogger.finer("nearestNodeOnCurrentY.node : "+nearestNodeOnCurrentY.node);
-            }
-            if (nearestNodeAverageRight != null) {
-                focusLogger.finer("nearestNodeAverageRight.node : "+nearestNodeAverageRight.node);
-            }
-            if (nearestNodeTopRight != null) {
-                focusLogger.finer("nearestNodeTopRight.node : "+nearestNodeTopRight.node);
-            }
-            if (nearestNodeAnythingAnywhereRight != null) {
-                focusLogger.finer("nearestNodeAnythingAnywhereRight.node : "+nearestNodeAnythingAnywhereRight.node);
-            }
-        }
-
-        /*
-        ** we've just changed direction, and have a node on stack.
-        ** there is a strong preference for this node, just make sure
-        ** it's not a bad choice, as sometimes we got here as a last-chance
-        */
-        if (reversingTargetNode != null) {
-            return reversingNode;
-        }
-        if (nearestNodeOnOriginY != null && nearestNodeOnOriginY.biasShortestDistance < Double.MAX_VALUE) {
-            /*
-            ** there's a preference, all else being equal, to return nearestNodeOnOriginY
-            */
-            if (nearestNodeOnOriginY != null && nearestNodeOnCurrentY != null &&
-                (nearestNodeOnOriginY.node == nearestNodeOnCurrentY.node)) {
-                return nearestNodeOnOriginY.node;
-            }
-            if (nearestNodeOnOriginY != null && nearestNodeOnCurrentY != null && nearestNodeAverageRight != null &&
-                (nearestNodeOnOriginY.node == nearestNodeOnCurrentY.node) && (nearestNodeOnOriginY.node == nearestNodeAverageRight.node)) {
-                return nearestNodeOnOriginY.node;
-            }
-            if (nearestNodeOnOriginY != null && nearestNodeOnCurrentY != null && nearestNodeTopRight != null &&
-                (nearestNodeOnOriginY.node == nearestNodeOnCurrentY.node) && (nearestNodeOnOriginY.node == nearestNodeTopRight.node)) {
-                return nearestNodeOnOriginY.node;
-            }
-            if (nearestNodeOnOriginY != null && nearestNodeOnCurrentY != null && nearestNodeAnythingAnywhereRight != null &&
-                (nearestNodeOnOriginY.node == nearestNodeOnCurrentY.node) && (nearestNodeOnOriginY.node == nearestNodeAnythingAnywhereRight.node)) {
-                return nearestNodeOnOriginY.node;
-            }
-            if (nearestNodeOnOriginY != null && nearestNodeAverageRight != null &&
-                (nearestNodeOnOriginY.node == nearestNodeAverageRight.node)) {
-                return nearestNodeOnOriginY.node;
-            }
-
-            if (nearestNodeOnCurrentY != null && nearestNodeOnCurrentY.biasShortestDistance < Double.MAX_VALUE) {
-                if (nearestNodeOnOriginY == null ||
-                    (nearestNodeOnCurrentY.topLeftDistance < nearestNodeOnOriginY.topLeftDistance) &&
-                    (nearestNodeOnCurrentY.originTopLeftDistance < nearestNodeOnOriginY.originTopLeftDistance) &&
-                    (nearestNodeOnCurrentY.bounds.getMinY() - currentTopRight2D.getY()) < (nearestNodeOnOriginY.bounds.getMinY() - currentTopRight2D.getY())  )  {
-
-                    return nearestNodeOnCurrentY.node;
-                }
-                else if (nearestNodeOnOriginY != null) {
-                    if (nearestNodeAverageRight != null || nearestNodeOnOriginY.averageDistance < nearestNodeAverageRight.averageDistance) {
-                        return nearestNodeOnOriginY.node;
-                    }
-                }
-            }
-        }
-        else {
-            if (nearestNodeOnOriginY == null && nearestNodeOnCurrentY == null && nearestNodeCurrentSimple2D != null) {
-                if (nearestNodeAverageRight != null && nearestNodeTopRight != null && nearestNodeAverageRight != null && nearestNodeAnythingAnywhereRight != null &&
-                    nearestNodeAverageRight.node == nearestNodeTopRight.node && nearestNodeAverageRight.node == nearestNodeAnythingAnywhereRight.node) {
-                    return nearestNodeAverageRight.node;
-                }
-                return nearestNodeCurrentSimple2D.node;
-            }
-            else if (nearestNodeAverageRight != null && nearestNodeTopRight != null && nearestNodeAnythingAnywhereRight != null &&
-                     nearestNodeAverageRight.biasShortestDistance == nearestNodeTopRight.biasShortestDistance &&
-                     nearestNodeAverageRight.biasShortestDistance == nearestNodeAnythingAnywhereRight.biasShortestDistance &&
-                     nearestNodeAverageRight.biasShortestDistance < Double.MAX_VALUE) {
-
-                if (nearestNodeOnOriginY != null && nearestNodeOnOriginY.originTopLeftDistance < nearestNodeAverageRight.originTopLeftDistance) {
-                    return nearestNodeOnOriginY.node;
-                }
-                else {
-                    return nearestNodeAverageRight.node;
-                }
-            }
-        }
-        /*
-        ** is the average closer?
-        */
-        if (nearestNodeAverageRight != null && (nearestNodeOnOriginY == null || nearestNodeAverageRight.biasShortestDistance < nearestNodeOnOriginY.biasShortestDistance)) {
-            /*
-            ** but is one in the way
-            */
-            if (nearestNodeOnOriginY != null && (nearestNodeOnOriginY.bounds.getMinX() >= nearestNodeAverageRight.bounds.getMinX())) {
-                return nearestNodeOnOriginY.node;
-            }
-            /*
-            ** maybe Origin is better than this?
-            */
-            if (nearestNodeOnOriginY != null && nearestNodeOnCurrentY != null &&  nearestNodeOnOriginY.biasShortestDistance < Double.MAX_VALUE && (nearestNodeOnOriginY.node == nearestNodeOnCurrentY.node)) {
-                return nearestNodeOnOriginY.node;
-            }
-
-            if (nearestNodeOnCurrentY != null && nearestNodeOnOriginY != null && nearestNodeOnCurrentY.biasShortestDistance < Double.MAX_VALUE && (nearestNodeOnCurrentY.biasShortestDistance < nearestNodeOnOriginY.biasShortestDistance)) {
-                return nearestNodeOnCurrentY.node;
-            }
-            if (nearestNodeOnOriginY != null &&  nearestNodeAverageRight != null && nearestNodeOnOriginY.biasShortestDistance < Double.MAX_VALUE && (nearestNodeOnOriginY.originTopLeftDistance < nearestNodeAverageRight.originTopLeftDistance)) {
-                return nearestNodeOnOriginY.node;
-            }
-            return nearestNodeAverageRight.node;
-        }
-
-        if (nearestNodeOnOriginY != null && nearestNodeOnCurrentY != null && nearestNodeOnOriginY.bottomLeftDistance < nearestNodeOnCurrentY.bottomLeftDistance) {
-            return nearestNodeOnOriginY.node;
-        }
-
-        /*
-        ** if any of the remaining match we'll take that
-        */
-        if (nearestNodeOnCurrentY != null && nearestNodeTopRight != null && nearestNodeOnCurrentY.biasShortestDistance < Double.MAX_VALUE && (nearestNodeOnCurrentY.node == nearestNodeTopRight.node)) {
-            return nearestNodeOnCurrentY.node;
-        }
-        /*
-        ** There isn't a clear winner, just go to the one nearest the current
-        ** focus owner, or if invalid then try the other contenders.
-        */
-        if (nearestNodeOnOriginY != null) {
-            return nearestNodeOnOriginY.node;
-        }
-        else if (nearestNodeOriginSimple2D != null) {
-            return nearestNodeOriginSimple2D.node;
-        }
-        else if (nearestNodeOnCurrentY != null) {
-            return nearestNodeOnCurrentY.node;
-        }
-        else if (nearestNodeAverageRight != null) {
-            return nearestNodeAverageRight.node;
-        }
-        else if (nearestNodeTopRight != null) {
-            return nearestNodeTopRight.node;
-        }
-        else if (nearestNodeAnythingAnywhereRight != null) {
-            return nearestNodeAnythingAnywhereRight.node;
-        }
-        return null;
-    }
-
-
     static final class TargetNode {
         Node node = null;
         Bounds bounds = null;
         double biased2DMetric = Double.MAX_VALUE;
         double current2DMetric = Double.MAX_VALUE;
 
-        double bottomLeftDistance = Double.MAX_VALUE;
+        double leftCornerDistance = Double.MAX_VALUE;
         double midDistance = Double.MAX_VALUE;
-        double bottomRightDistance = Double.MAX_VALUE;
+        double rightCornerDistance = Double.MAX_VALUE;
+        double topCornerDistance = Double.MAX_VALUE;
+        double bottomCornerDistance = Double.MAX_VALUE;
 
         double shortestDistance = Double.MAX_VALUE;
         double biasShortestDistance = Double.MAX_VALUE;
         double averageDistance = Double.MAX_VALUE;
 
-        double topLeftDistance = Double.MAX_VALUE;
-        double topRightDistance = Double.MAX_VALUE;
-        double originTopLeftDistance = Double.MAX_VALUE;
-        double originTopRightDistance = Double.MAX_VALUE;
-        double originBottomLeftDistance = Double.MAX_VALUE;
-        double originBottomRightDistance = Double.MAX_VALUE;
+        double originLeftCornerDistance = Double.MAX_VALUE;
+        double originTopCornerDistance = Double.MAX_VALUE;
 
         void copy(TargetNode source) {
             node = source.node;
@@ -2194,37 +1144,27 @@
             biased2DMetric = source.biased2DMetric;
             current2DMetric = source.current2DMetric;
 
-            bottomLeftDistance = source.bottomLeftDistance;
+            leftCornerDistance = source.leftCornerDistance;
             midDistance = source.midDistance;
-            bottomRightDistance = source.bottomRightDistance;
+            rightCornerDistance = source.rightCornerDistance;
 
             shortestDistance = source.shortestDistance;
             biasShortestDistance = source.biasShortestDistance;
             averageDistance = source.averageDistance;
 
-            topLeftDistance = source.topLeftDistance;
-            topRightDistance = source.topRightDistance;
-            originTopLeftDistance = source.originTopLeftDistance;
-            originTopRightDistance = source.originTopRightDistance;
-            originBottomLeftDistance = source.originBottomLeftDistance;
-            originBottomRightDistance = source.originBottomRightDistance;
+            topCornerDistance = source.topCornerDistance;
+            bottomCornerDistance = source.bottomCornerDistance;
+            originLeftCornerDistance = source.originLeftCornerDistance;
+            originTopCornerDistance = source.originTopCornerDistance;
         }
     }
 
-    public static double findMin9(double d0, double d1, double d2, double d3, double d4, double d5, double d6, double d7, double d8) {
-        double doubleArray[] = new double[9];
-        doubleArray[1] = d1;
-        doubleArray[2] = d2;
-        doubleArray[3] = d3;
-        doubleArray[4] = d4;
-        doubleArray[5] = d5;
-        doubleArray[6] = d6;
-        doubleArray[7] = d7;
-        doubleArray[8] = d8;
+    public static double findMin(double... values) {
 
-        double minValue = d0;
-        for (int i = 1 ; i < doubleArray.length ; i++) {
-            minValue = (minValue <= doubleArray[i]) ? minValue : doubleArray[i];
+        double minValue = Double.MAX_VALUE;
+        
+        for (int i = 0 ; i < values.length ; i++) {
+            minValue = (minValue < values[i]) ? minValue : values[i];
         }
         return minValue;
     }
--- a/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGNode.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGNode.java	Mon Nov 18 22:06:51 2013 -0800
@@ -452,11 +452,17 @@
      * @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;
-        }
+        // The following code was a broken optimization that made an
+        // incorrect assumption about null meaning the same thing as
+        // SRC_OVER.  In reality, null means "pass through blending
+        // from children" and SRC_OVER means "intercept blending of
+        // children, allow them to blend with each other, but pass
+        // their result on in a single SRC_OVER operation into the bg".
+        // For leaf nodes, those are mostly the same thing, but Regions
+        // and Groups might behave differently for the two modes.
+//        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
--- a/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGShape3D.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/java/com/sun/javafx/sg/prism/NGShape3D.java	Mon Nov 18 22:06:51 2013 -0800
@@ -130,28 +130,40 @@
                     // The array of lights can have nulls
                     break;
                 } else if (lightBase.affects(this)) {
+                    float rL = lightBase.getColor().getRed();
+                    float gL = lightBase.getColor().getGreen();
+                    float bL = lightBase.getColor().getBlue();
+                    /* TODO: 3D
+                     * There is a limit on the number of lights that can affect
+                     * a 3D shape. (Currently we simply select the first 3)
+                     * Thus it is important to select the most relevant lights.
+                     * 
+                     * One such way would be to sort lights according to
+                     * intensity, which becomes especially relevant when lights
+                     * are attenuated. Only the most intense set of lights
+                     * would be set.
+                     * The approximate intesity a light will have on a given
+                     * shape, could be defined by:
+                     */
+//                    // Where d is distance from point light
+//                    float attenuationFactor = 1/(c + cL * d + cQ * d * d);
+//                    float intensity = rL * 0.299f + gL * 0.587f + bL * 0.114f;
+//                    intensity *= attenuationFactor;
                     if (lightBase instanceof NGPointLight) {
-                        NGPointLight light = (NGPointLight) lightBase;
-                        float intensity = light.getColor().getAlpha();
-                        if (intensity == 0.0f) {
-                            continue;
+                        NGPointLight light = (NGPointLight)lightBase;
+                        if (rL != 0.0f || gL != 0.0f || bL != 0.0f) {
+                            Affine3D lightWT = light.getWorldTransform();
+                            meshView.setPointLight(pointLightIdx++,
+                                    (float)lightWT.getMxt(),
+                                    (float)lightWT.getMyt(),
+                                    (float)lightWT.getMzt(),
+                                    rL, gL, bL, 1.0f);
                         }
-                        Affine3D lightWT = light.getWorldTransform();
-                        meshView.setPointLight(pointLightIdx++,
-                                (float)lightWT.getMxt(),
-                                (float)lightWT.getMyt(),
-                                (float)lightWT.getMzt(),
-                                light.getColor().getRed(),
-                                light.getColor().getGreen(),
-                                light.getColor().getBlue(),
-                                intensity);
                     } else if (lightBase instanceof NGAmbientLight) {
                         // Accumulate ambient lights
-                        ambientRed   += lightBase.getColor().getRedPremult();
-                        ambientGreen += lightBase.getColor().getGreenPremult();
-                        ambientBlue  += lightBase.getColor().getBluePremult();
-                    } else {
-                        // Unknown light type
+                        ambientRed   += rL;
+                        ambientGreen += gL;
+                        ambientBlue  += bL;
                     }
                 }
             }
@@ -162,8 +174,8 @@
         }
         // TODO: 3D Required for D3D implementation of lights, which is limited to 3
         while (pointLightIdx < 3) {
-            // Reset any previously set lights
-            meshView.setPointLight(pointLightIdx++, 0, 0, 0, 0, 0, 0, 0);
+                // Reset any previously set lights
+                meshView.setPointLight(pointLightIdx++, 0, 0, 0, 0, 0, 0, 0);
         }
 
         meshView.render(g);
--- a/modules/graphics/src/main/java/com/sun/javafx/text/PrismTextLayout.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/java/com/sun/javafx/text/PrismTextLayout.java	Mon Nov 18 22:06:51 2013 -0800
@@ -1286,7 +1286,7 @@
                 layoutCache.lines = lines;
                 layoutCache.layoutWidth = layoutWidth;
                 layoutCache.layoutHeight = layoutHeight;
-                layoutCache.analysis = flags | ANALYSIS_MASK;
+                layoutCache.analysis = flags & ANALYSIS_MASK;
                 synchronized (CACHE_SIZE_LOCK) {
                     int charCount = chars.length;
                     if (cacheSize + charCount > MAX_CACHE_SIZE) {
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/AbstractEventLoop.java	Thu Nov 14 10:49:15 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,122 +0,0 @@
-/*
- * Copyright (c) 2012, 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 com.sun.javafx.tk.quantum;
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.CountDownLatch;
-
-abstract class AbstractEventLoop {
-
-    static abstract class Task implements Runnable {
-
-        private final CountDownLatch latch = new CountDownLatch(1);
-
-        @Override
-        public void run() {
-            try {
-                doRun();
-            } finally {
-                latch.countDown();
-            }
-        }
-
-        protected abstract void doRun();
-
-        void await() throws InterruptedException {
-            latch.await();
-        }
-    };
-
-    static final class CallableTask<V> extends Task {
-
-        private V retValue;
-        private final Callable<V> c;
-        private Exception e;
-
-        CallableTask(final Callable<V> c) {
-            this.c = c;
-        }
-
-        @Override
-        public void doRun() {
-            try {
-                retValue = c.call();
-            } catch (Exception e) {
-                this.e = e;
-            }
-        }
-
-        V getResult() {
-            if (e == null) {
-                return retValue;
-            }
-            throw new RuntimeException(e);
-        }
-    }
-
-    static final class RunnableTask extends Task {
-
-        private final Runnable r;
-
-        RunnableTask(final Runnable r) {
-            this.r = r;
-        }
-
-        @Override
-        public void doRun() {
-            r.run();
-        }
-    }
-
-    public AbstractEventLoop() {
-    }
-
-    public void send(final Runnable r) {
-        final RunnableTask task = new RunnableTask(r);
-        await(task);
-    }
-
-    public <V> V send(final Callable<V> c) {
-        final CallableTask<V> task = new CallableTask<V>(c);
-        await(task);
-        return task.getResult();
-    }
-
-    protected abstract void schedule(Runnable r);
-
-    public abstract void start();
-
-    public abstract void stop();
-
-    private void await(final Task task) {
-        schedule(task);
-        try {
-            task.await();
-        } catch (InterruptedException e) {
-            throw new RuntimeException(e);
-        }
-    }
-}
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/EmbeddedScene.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/EmbeddedScene.java	Mon Nov 18 22:06:51 2013 -0800
@@ -25,6 +25,7 @@
 
 package com.sun.javafx.tk.quantum;
 
+import com.sun.javafx.embed.HostDragStartListener;
 import javafx.application.Platform;
 import javafx.collections.ObservableList;
 import javafx.event.EventType;
@@ -38,8 +39,7 @@
 import java.security.PrivilegedAction;
 import com.sun.javafx.cursor.CursorFrame;
 import com.sun.javafx.embed.AbstractEvents;
-import com.sun.javafx.embed.EmbeddedSceneDragStartListenerInterface;
-import com.sun.javafx.embed.EmbeddedSceneDropTargetInterface;
+import com.sun.javafx.embed.EmbeddedSceneDTInterface;
 import com.sun.javafx.embed.EmbeddedSceneInterface;
 import com.sun.javafx.embed.HostInterface;
 import com.sun.javafx.scene.input.KeyCodeMap;
@@ -59,7 +59,7 @@
     private UploadingPainter        painter;
     private PaintRenderJob          paintRenderJob;
     
-    private final EmbeddedSceneDnD dndDelegate;    
+    private final EmbeddedSceneDnD embeddedDnD;
 
     volatile IntBuffer  texBits;
     volatile int        texLineStride; // pre-scaled
@@ -70,7 +70,7 @@
         sceneState = new EmbeddedState(this);
 
         this.host = host;
-        this.dndDelegate = new EmbeddedSceneDnD(this);
+        this.embeddedDnD = new EmbeddedSceneDnD(this);
 
         PaintCollector collector = PaintCollector.getInstance();
         painter = new UploadingPainter(this);
@@ -110,7 +110,7 @@
 
     @Override
     public TKClipboard createDragboard(boolean isDragSource) {
-        return dndDelegate.createDragboard();
+        return embeddedDnD.createDragboard(isDragSource);
     }
 
     @Override
@@ -345,13 +345,13 @@
     }
 
     @Override
-    public void setDragStartListener(EmbeddedSceneDragStartListenerInterface l) {
-        dndDelegate.setDragStartListener(l);
+    public void setDragStartListener(HostDragStartListener l) {
+        embeddedDnD.setDragStartListener(l);
     }
 
     @Override
-    public EmbeddedSceneDropTargetInterface createDropTarget() {
-        return dndDelegate.createDropTarget();
+    public EmbeddedSceneDTInterface createDropTarget() {
+        return embeddedDnD.createDropTarget();
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/EmbeddedSceneDS.java	Mon Nov 18 22:06:51 2013 -0800
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2012, 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 com.sun.javafx.tk.quantum;
+
+import com.sun.glass.ui.ClipboardAssistance;
+import com.sun.javafx.embed.EmbeddedSceneDSInterface;
+
+import java.util.Arrays;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import javafx.scene.input.TransferMode;
+
+final class EmbeddedSceneDS implements EmbeddedSceneDSInterface {
+
+    private final EmbeddedSceneDnD dnd;
+    private final ClipboardAssistance assistant;
+    private final GlassSceneDnDEventHandler dndHandler;
+
+    public EmbeddedSceneDS(final EmbeddedSceneDnD dnd,
+                           final ClipboardAssistance assistant,
+                           final GlassSceneDnDEventHandler dndHandler) {
+        this.dnd = dnd;
+        this.assistant = assistant;
+        this.dndHandler = dndHandler;
+    }
+
+    @Override
+    public Set<TransferMode> getSupportedActions() {
+        assert dnd.isHostThread();
+        return dnd.executeOnFXThread(new Callable<Set<TransferMode>>() {
+            @Override
+            public Set<TransferMode> call() {
+                return QuantumClipboard.clipboardActionsToTransferModes(
+                        assistant.getSupportedSourceActions());
+            }
+        });
+    }
+
+    @Override
+    public Object getData(final String mimeType) {
+        assert dnd.isHostThread();
+        return dnd.executeOnFXThread(new Callable<Object>() {
+            @Override
+            public Object call() {
+                return assistant.getData(mimeType);
+            }
+        });
+    }
+
+    @Override
+    public String[] getMimeTypes() {
+        assert dnd.isHostThread();
+        return dnd.executeOnFXThread(new Callable<String[]>() {
+            @Override
+            public String[] call() {
+                return assistant.getMimeTypes();
+            }
+        });
+    }
+
+    @Override
+    public boolean isMimeTypeAvailable(final String mimeType) {
+        assert dnd.isHostThread();
+        return dnd.executeOnFXThread(new Callable<Boolean>() {
+            @Override
+            public Boolean call() {
+                return Arrays.asList(assistant.getMimeTypes()).contains(mimeType);
+            }
+        });
+    }
+
+    @Override
+    public void dragDropEnd(final TransferMode performedAction) {
+        assert dnd.isHostThread();
+        dnd.executeOnFXThread(new Callable<Void>() {
+            @Override
+            public Void call() {
+                try {
+                    dndHandler.handleDragEnd(performedAction, assistant);
+                } finally {
+                    dnd.onDragSourceReleased(EmbeddedSceneDS.this);
+                }
+                return null;
+            }
+        });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/EmbeddedSceneDT.java	Mon Nov 18 22:06:51 2013 -0800
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2012, 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 com.sun.javafx.tk.quantum;
+
+import com.sun.glass.ui.ClipboardAssistance;
+import com.sun.javafx.embed.EmbeddedSceneDSInterface;
+import com.sun.javafx.embed.EmbeddedSceneDTInterface;
+import java.util.concurrent.Callable;
+import javafx.application.Platform;
+import javafx.scene.input.TransferMode;
+
+final class EmbeddedSceneDT implements EmbeddedSceneDTInterface {
+
+    private final EmbeddedSceneDnD dnd;
+    private final GlassSceneDnDEventHandler dndHandler;
+    private EmbeddedSceneDSInterface dragSource;
+    private ClipboardAssistance assistant;
+
+    public EmbeddedSceneDT(final EmbeddedSceneDnD dnd,
+                           final GlassSceneDnDEventHandler dndHandler) {
+        this.dnd = dnd;
+        this.dndHandler = dndHandler;
+    }
+
+    private void close() {
+        dnd.onDropTargetReleased(this);
+        assistant = null;
+    }
+
+    @Override
+    public TransferMode handleDragEnter(final int x, final int y, final int xAbs,
+                                        final int yAbs,
+                                        final TransferMode recommendedDropAction,
+                                        final EmbeddedSceneDSInterface ds)
+    {
+        assert dnd.isHostThread();
+
+        return dnd.executeOnFXThread(new Callable<TransferMode>() {
+            @Override
+            public TransferMode call() {
+                assert dragSource == null;
+                assert assistant == null;
+
+                dragSource = ds;
+                assistant = new EmbeddedDTAssistant(dragSource);
+
+                return dndHandler.handleDragEnter(x, y, xAbs, yAbs,
+                                                  recommendedDropAction,
+                                                  assistant);
+            }
+        });
+    }
+
+    @Override
+    public void handleDragLeave() {
+        assert dnd.isHostThread();
+
+        dnd.executeOnFXThread(new Callable<Void>() {
+            @Override
+            public Void call() {
+                assert assistant != null;
+                try {
+                    dndHandler.handleDragLeave(assistant);
+                } finally {
+                    close();
+                }
+                return null;
+            }
+        });
+    }
+
+    @Override
+    public TransferMode handleDragDrop(final int x, final int y, final int xAbs,
+                                       final int yAbs,
+                                       final TransferMode recommendedDropAction) {
+        assert dnd.isHostThread();
+
+        return dnd.executeOnFXThread(new Callable<TransferMode>() {
+            @Override
+            public TransferMode call() {
+                assert assistant != null;
+                try {
+                    return dndHandler.handleDragDrop(x, y, xAbs, yAbs,
+                                                     recommendedDropAction,
+                                                     assistant);
+                } finally {
+                    close();
+                }
+            }
+        });
+    }
+
+    @Override
+    public TransferMode handleDragOver(final int x, final int y, final int xAbs,
+                                       final int yAbs,
+                                       final TransferMode recommendedDropAction) {
+        assert dnd.isHostThread();
+
+        return dnd.executeOnFXThread(new Callable<TransferMode>() {
+            @Override
+            public TransferMode call() {
+                assert assistant != null;
+                return dndHandler.handleDragOver(x, y, xAbs, yAbs,
+                                                 recommendedDropAction,
+                                                 assistant);
+            }
+        });
+    }
+
+    private static class EmbeddedDTAssistant extends ClipboardAssistance {
+
+        private EmbeddedSceneDSInterface dragSource;
+
+        EmbeddedDTAssistant(EmbeddedSceneDSInterface source) {
+            super("DND-Embedded");
+            dragSource = source;
+        }
+
+        @Override
+        public void flush() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Object getData(final String mimeType) {
+            return dragSource.getData(mimeType);
+        }
+
+        @Override
+        public int getSupportedSourceActions() {
+            return QuantumClipboard.transferModesToClipboardActions(dragSource.getSupportedActions());
+        }
+
+        @Override
+        public void setTargetAction(int actionDone) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public String[] getMimeTypes() {
+            return dragSource.getMimeTypes();
+        }
+    }
+}
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/EmbeddedSceneDnD.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/EmbeddedSceneDnD.java	Mon Nov 18 22:06:51 2013 -0800
@@ -26,26 +26,31 @@
 package com.sun.javafx.tk.quantum;
 
 import com.sun.glass.ui.ClipboardAssistance;
-import com.sun.javafx.embed.EmbeddedSceneDragSourceInterface;
-import com.sun.javafx.embed.EmbeddedSceneDragStartListenerInterface;
-import com.sun.javafx.embed.EmbeddedSceneDropTargetInterface;
+import com.sun.javafx.embed.EmbeddedSceneDSInterface;
+import com.sun.javafx.embed.HostDragStartListener;
+import com.sun.javafx.embed.EmbeddedSceneDTInterface;
+
+import java.awt.EventQueue;
+import java.awt.SecondaryLoop;
 import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
 
 import com.sun.javafx.tk.TKClipboard;
+
+import com.sun.javafx.tk.Toolkit;
 import javafx.application.Platform;
-import javafx.scene.input.Dragboard;
 import javafx.scene.input.TransferMode;
 
 final class EmbeddedSceneDnD {
 
     private final GlassSceneDnDEventHandler dndHandler;
 
-    private EmbeddedSceneDragStartListenerInterface dragStartListener;
-    private EmbeddedSceneDragSourceInterface fxDragSource;
-    private EmbeddedSceneDropTargetInterface fxDropTarget;
-    
-    private ClipboardAssistance clipboardAssistant;
-    
+    private HostDragStartListener dragStartListener;
+    private EmbeddedSceneDSInterface fxDragSource;
+    private EmbeddedSceneDTInterface fxDropTarget;
+
     private Thread hostThread;
 
     public EmbeddedSceneDnD(final GlassScene scene) {
@@ -54,14 +59,9 @@
     
     private void startDrag() {
         assert Platform.isFxApplicationThread();
+        assert fxDragSource != null;
 
-        assert fxDragSource == null;
-
-        fxDragSource = new EmbeddedSceneDragSource(this, dndHandler);
-        
-        final TransferMode dragAction = TransferMode.COPY;
-        
-        dragStartListener.dragStarted(fxDragSource, dragAction);
+        dragStartListener.dragStarted(fxDragSource, TransferMode.COPY);
     }
 
     private void setHostThread() {
@@ -74,189 +74,89 @@
         return (Thread.currentThread() == hostThread);
     }
     
-    public boolean isValid(EmbeddedSceneDragSourceInterface ds) {
+    public void onDragSourceReleased(final EmbeddedSceneDSInterface ds) {
+        assert fxDragSource == ds;
+
+        fxDragSource = null;
+        Toolkit.getToolkit().exitNestedEventLoop(this, null);
+    }
+
+    public void onDropTargetReleased(final EmbeddedSceneDTInterface dt) {
+        assert fxDropTarget == dt;
+
+        fxDropTarget = null;
+    }
+
+    /*
+     * This is a helper method to execute code on FX event thread. It
+     * can be implemented using AWT nested event loop, however it just
+     * blocks the current thread. This is done by intention, because
+     * we need to handle Swing events one by one. If we enter a nested
+     * event loop, various weird side-effects are observed, e.g.
+     * dragOver() in SwingDnD is executed before dragEnter() is finished
+     */
+    <T> T executeOnFXThread(final Callable<T> r) {
+        assert !Platform.isFxApplicationThread();
+
+        final AtomicReference<T> result = new AtomicReference<>();
+        final CountDownLatch l = new CountDownLatch(1);
+
+        Platform.runLater(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    result.set(r.call());
+                } catch (Exception z) {
+                    // ignore
+                } finally {
+                    l.countDown();
+                }
+            }
+        });
+
+        try {
+            l.await();
+        } catch (Exception z) {
+            // ignore
+        }
+
+        return result.get();
+    }
+
+    
+    // Should be called from Scene.DnDGesture.createDragboard only!
+    public TKClipboard createDragboard(boolean isDragSource) {
         assert Platform.isFxApplicationThread();
-        assert ds != null;
-        assert fxDragSource == ds;
-        assert clipboardAssistant != null;
-        return true;
+        assert fxDragSource == null;
+
+        assert isDragSource;
+        ClipboardAssistance assistant = new ClipboardAssistance("DND-Embedded") {
+            @Override
+            public void flush() {
+                super.flush();
+                startDrag(); // notify host
+                Toolkit.getToolkit().enterNestedEventLoop(EmbeddedSceneDnD.this); // block current thread
+            }
+        };
+        fxDragSource = new EmbeddedSceneDS(this, assistant, dndHandler);
+        return QuantumClipboard.getDragboardInstance(assistant, isDragSource);
+    }
+
+    public void setDragStartListener(HostDragStartListener l) {
+        setHostThread();
+        dragStartListener = l;
     }
     
-    public boolean isValid(EmbeddedSceneDropTargetInterface dt) {
-        assert Platform.isFxApplicationThread();
-        assert dt != null;
-        assert fxDropTarget == dt;
-        return true;
-    }
-    
-    public boolean isFxDragSource() {
-        assert Platform.isFxApplicationThread();
-
-        return (fxDragSource != null);
-    }
-
-    public void onDragSourceReleased(final EmbeddedSceneDragSourceInterface ds) {
-        assert isValid(ds);
-
-        fxDragSource = null;
-        clipboardAssistant = null;
-        
-        FxEventLoop.leaveNestedLoop();
-    }
-
-    public void onDropTargetReleased(final EmbeddedSceneDropTargetInterface dt) {
-        assert isValid(dt);
-
-        fxDropTarget = null;
-        if (!isFxDragSource()) {
-            clipboardAssistant = null;
-        }
-    }
-    
-    // Should be called from Scene.DnDGesture.createDragboard only!
-    public TKClipboard createDragboard() {
-        assert Platform.isFxApplicationThread();
-        assert fxDropTarget == null;
-        assert clipboardAssistant == null;
-        assert fxDragSource == null;
-        
-        clipboardAssistant = new ClipboardAssistanceImpl(null);
-        return QuantumClipboard.getDragboardInstance(clipboardAssistant);
-    }
-
-    public void setDragStartListener(EmbeddedSceneDragStartListenerInterface l) {
+    public EmbeddedSceneDTInterface createDropTarget() {
         setHostThread();
-        
-        assert isHostThread();
-        
-        this.dragStartListener = l;
-    }
-    
-    public EmbeddedSceneDropTargetInterface createDropTarget() {
-        setHostThread();
-
-        assert isHostThread();
-        assert fxDropTarget == null;
-
-        return FxEventLoop.sendEvent(new Callable<EmbeddedSceneDropTargetInterface>() {
-
+        return executeOnFXThread(new Callable<EmbeddedSceneDTInterface>() {
             @Override
-            public EmbeddedSceneDropTargetInterface call() {
-                fxDropTarget = new EmbeddedSceneDropTarget(EmbeddedSceneDnD.this,
-                                                           dndHandler);
-
+            public EmbeddedSceneDTInterface call() {
+                assert fxDropTarget == null;
+                fxDropTarget = new EmbeddedSceneDT(EmbeddedSceneDnD.this, dndHandler);
                 return fxDropTarget;
             }
         });
     }
-    
-    public ClipboardAssistance getClipboardAssistance(
-            final EmbeddedSceneDragSourceInterface source) {
-        assert Platform.isFxApplicationThread();
-        assert isFxDragSource() ? isValid(source) : true;
-        assert isFxDragSource() ? (clipboardAssistant != null) : true;
-        
-        if (clipboardAssistant == null) {
-            clipboardAssistant = new ClipboardAssistanceImpl(source);
-        }
-        return clipboardAssistant;
-    }
 
-    private class ClipboardAssistanceImpl extends ClipboardAssistance {
-        final EmbeddedSceneDragSourceInterface source;
-                
-        private boolean isValid() {
-            assert Platform.isFxApplicationThread();
-            assert EmbeddedSceneDnD.this.clipboardAssistant == this;
-            
-            return true;
-        }
-        
-        ClipboardAssistanceImpl(final EmbeddedSceneDragSourceInterface source) {
-            super("DND-Embedded");
-            
-            this.source = source;
-        }
-
-        @Override
-        public void flush() {
-            assert isValid();
-
-            super.flush();
-            
-            startDrag();
-
-            FxEventLoop.enterNestedLoop();
-        }
-
-        @Override
-        public void emptyCache() {
-            assert isValid();
-
-            super.emptyCache();
-        }
-
-        @Override
-        public Object getData(final String mimeType) {
-            assert isValid();
-
-            if (source == null) {
-                return super.getData(mimeType);
-            }
-
-            return source.getData(mimeType);
-        }
-
-        @Override
-        public void setData(final String mimeType, final Object data) {
-            assert isValid();
-            
-            if (source != null) {
-                return;
-            }
-
-            super.setData(mimeType, data);
-        }
-
-        @Override
-        public void setSupportedActions(final int supportedActions) {
-            assert isValid();
-            
-            if (source != null) {
-                return;
-            }
-
-            super.setSupportedActions(supportedActions);
-        }
-
-        @Override
-        public int getSupportedSourceActions() {
-            assert isValid();
-
-            if (source == null) {
-                return super.getSupportedSourceActions();
-            }
-
-            return QuantumClipboard.transferModesToClipboardActions(source.
-                    getSupportedActions());
-        }
-
-        @Override
-        public void setTargetAction(int actionDone) {
-            assert isValid();
-
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public String[] getMimeTypes() {
-            assert isValid();
-
-            if (source == null) {
-                return super.getMimeTypes();
-            }
-
-            return source.getMimeTypes();
-        }
-    }
 }
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/EmbeddedSceneDragSource.java	Thu Nov 14 10:49:15 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-/*
- * Copyright (c) 2012, 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 com.sun.javafx.tk.quantum;
-
-import com.sun.glass.ui.ClipboardAssistance;
-import com.sun.javafx.embed.EmbeddedSceneDragSourceInterface;
-import java.util.Arrays;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import javafx.scene.input.TransferMode;
-
-final class EmbeddedSceneDragSource implements EmbeddedSceneDragSourceInterface {
-
-    private final EmbeddedSceneDnD dnd;
-    private final GlassSceneDnDEventHandler dndHandler;
-
-    public EmbeddedSceneDragSource(final EmbeddedSceneDnD dnd,
-                                   final GlassSceneDnDEventHandler dndHandler) {
-        this.dnd = dnd;
-        this.dndHandler = dndHandler;
-    }
-
-    private ClipboardAssistance getClipboardAssistance() {
-        assert dnd.isValid(this);
-        return dnd.getClipboardAssistance(this);
-    }
-
-    @Override
-    public Set<TransferMode> getSupportedActions() {
-        assert dnd.isHostThread();
-        return FxEventLoop.sendEvent(new Callable<Set<TransferMode>>() {
-
-            @Override
-            public Set<TransferMode> call() {
-                return QuantumClipboard.clipboardActionsToTransferModes(getClipboardAssistance().
-                        getSupportedSourceActions());
-            }
-        });
-    }
-
-    @Override
-    public Object getData(final String mimeType) {
-        assert dnd.isHostThread();
-        return FxEventLoop.sendEvent(new Callable() {
-
-            @Override
-            public Object call() {
-                return getClipboardAssistance().getData(mimeType);
-            }
-        });
-    }
-
-    @Override
-    public String[] getMimeTypes() {
-        assert dnd.isHostThread();
-        return FxEventLoop.sendEvent(new Callable<String[]>() {
-
-            @Override
-            public String[] call() {
-                return getClipboardAssistance().getMimeTypes();
-            }
-        });
-    }
-
-    @Override
-    public boolean isMimeTypeAvailable(final String mimeType) {
-        assert dnd.isHostThread();
-        return (boolean) FxEventLoop.sendEvent(new Callable<Boolean>() {
-
-            @Override
-            public Boolean call() {
-                return Arrays.asList(getClipboardAssistance().getMimeTypes()).
-                        contains(mimeType);
-            }
-        });
-    }
-
-    @Override
-    public void dragDropEnd(final TransferMode performedAction) {
-        assert dnd.isHostThread();
-        FxEventLoop.sendEvent(new Runnable() {
-
-            @Override
-            public void run() {
-                try {
-                    dndHandler.handleDragEnd(performedAction,
-                                             getClipboardAssistance());
-                } finally {
-                    dnd.onDragSourceReleased(EmbeddedSceneDragSource.this);
-                }
-            }
-        });
-    }
-}
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/EmbeddedSceneDropTarget.java	Thu Nov 14 10:49:15 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,149 +0,0 @@
-/*
- * Copyright (c) 2012, 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 com.sun.javafx.tk.quantum;
-
-import com.sun.glass.ui.ClipboardAssistance;
-import com.sun.javafx.embed.EmbeddedSceneDragSourceInterface;
-import com.sun.javafx.embed.EmbeddedSceneDropTargetInterface;
-import java.util.concurrent.Callable;
-import javafx.application.Platform;
-import javafx.scene.input.TransferMode;
-
-final class EmbeddedSceneDropTarget implements EmbeddedSceneDropTargetInterface {
-
-    private final EmbeddedSceneDnD dnd;
-    private final GlassSceneDnDEventHandler dndHandler;
-    private EmbeddedSceneDragSourceInterface dragSource;
-    private int dndCounter;
-
-    public EmbeddedSceneDropTarget(final EmbeddedSceneDnD dnd,
-                                   final GlassSceneDnDEventHandler dndHandler) {
-        this.dnd = dnd;
-        this.dndHandler = dndHandler;
-    }
-
-    private boolean isDnDCounterValid() {
-        assert Platform.isFxApplicationThread();
-        assert dndCounter == 1;
-
-        return true;
-    }
-
-    private ClipboardAssistance getClipboardAssistance() {
-        assert isDnDCounterValid();
-        assert dnd.isValid(this);
-
-        return dnd.getClipboardAssistance(dragSource);
-    }
-
-    private void close() {
-        assert isDnDCounterValid();
-
-        --dndCounter;
-
-        dnd.onDropTargetReleased(this);
-    }
-
-    @Override
-    public TransferMode handleDragEnter(final int x, final int y, final int xAbs,
-                                        final int yAbs,
-                                        final TransferMode recommendedDropAction,
-                                        final EmbeddedSceneDragSourceInterface dragSource) {
-        assert dnd.isHostThread();
-
-        return FxEventLoop.sendEvent(new Callable<TransferMode>() {
-
-            @Override
-            public TransferMode call() {
-                ++dndCounter;
-
-                assert dnd.isFxDragSource() ? true
-                        : EmbeddedSceneDropTarget.this.dragSource == null;
-
-                EmbeddedSceneDropTarget.this.dragSource = dragSource;
-
-                return dndHandler.handleDragEnter(x, y, xAbs, yAbs,
-                                                  recommendedDropAction,
-                                                  getClipboardAssistance());
-            }
-        });
-    }
-
-    @Override
-    public void handleDragLeave() {
-        assert dnd.isHostThread();
-
-        FxEventLoop.sendEvent(new Runnable() {
-
-            @Override
-            public void run() {
-                try {
-                    dndHandler.handleDragLeave(getClipboardAssistance());
-                } finally {
-                    close();
-                }
-            }
-        });
-    }
-
-    @Override
-    public TransferMode handleDragDrop(final int x, final int y, final int xAbs,
-                                       final int yAbs,
-                                       final TransferMode recommendedDropAction) {
-        assert dnd.isHostThread();
-
-        return FxEventLoop.sendEvent(new Callable<TransferMode>() {
-
-            @Override
-            public TransferMode call() {
-                try {
-                    return dndHandler.handleDragDrop(x, y, xAbs, yAbs,
-                                                     recommendedDropAction,
-                                                     getClipboardAssistance());
-                } finally {
-                    close();
-                }
-            }
-        });
-    }
-
-    @Override
-    public TransferMode handleDragOver(final int x, final int y, final int xAbs,
-                                       final int yAbs,
-                                       final TransferMode recommendedDropAction) {
-        assert dnd.isHostThread();
-
-        return FxEventLoop.sendEvent(new Callable<TransferMode>() {
-
-            @Override
-            public TransferMode call() {
-                return dndHandler.handleDragOver(x, y, xAbs, yAbs,
-                                                 recommendedDropAction,
-                                                 getClipboardAssistance());
-            }
-        });
-    }
-}
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/FxEventLoop.java	Thu Nov 14 10:49:15 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,136 +0,0 @@
-/*
- * Copyright (c) 2012, 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 com.sun.javafx.tk.quantum;
-
-import com.sun.javafx.tk.Toolkit;
-import javafx.application.Platform;
-
-import java.util.concurrent.Callable;
-
-final class FxEventLoop {
-
-    private final static class Impl extends AbstractEventLoop {
-
-        private final Object NESTED_EVENT_LOOP_KEY = new Object();
-
-        private Object nestedEventLoopToken;
-        private int depth;
-
-        @Override
-        public void send(final Runnable r) {
-            if (Platform.isFxApplicationThread()) {
-                r.run();
-                return;
-            }
-            super.send(r);
-        }
-
-        @Override
-        public <V> V send(final Callable<V> c) {
-            if (Platform.isFxApplicationThread()) {
-                try {
-                    return c.call();
-                } catch (Exception e) {
-                    throw new RuntimeException(e);
-                }
-            }
-            return super.send(c);
-        }
-
-        @Override
-        public void start() {
-            if (Platform.isFxApplicationThread()) {
-                // Don't allow nested nested loops
-                assert (depth == 0);
-
-                ++depth;
-                try {
-                    nestedEventLoopToken = Toolkit.getToolkit().
-                            enterNestedEventLoop(NESTED_EVENT_LOOP_KEY);
-                } finally {
-                    --depth;
-                }
-            } else {
-                Platform.runLater(new Runnable() {
-
-                    @Override
-                    public void run() {
-                        enterNestedLoop();
-                    }
-                });
-            }
-        }
-
-        @Override
-        public void stop() {
-            if (Platform.isFxApplicationThread()) {
-                Toolkit.getToolkit().exitNestedEventLoop(NESTED_EVENT_LOOP_KEY,
-                                                         nestedEventLoopToken);
-                nestedEventLoopToken = null;
-            } else {
-                send(new Runnable() {
-
-                    @Override
-                    public void run() {
-                        leaveNestedLoop();
-                    }
-                });
-            }
-        }
-
-        @Override
-        protected void schedule(Runnable r) {
-            Platform.runLater(r);
-        }
-
-        boolean isNestedLoopRunning() {
-            assert Platform.isFxApplicationThread();
-
-            return (depth != 0);
-        }
-    }
-    private final static Impl impl = new Impl();
-
-    public static void enterNestedLoop() {
-        impl.start();
-    }
-
-    public static void leaveNestedLoop() {
-        impl.stop();
-    }
-
-    public static void sendEvent(final Runnable e) {
-        impl.send(e);
-    }
-
-    public static <V> V sendEvent(final Callable<V> e) {
-        return impl.send(e);
-    }
-
-    public static boolean isNestedLoopRunning() {
-        return impl.isNestedLoopRunning();
-    }
-}
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/GlassScene.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/GlassScene.java	Mon Nov 18 22:06:51 2013 -0800
@@ -65,8 +65,6 @@
     protected InputMethodRequests inputMethodRequests;
     private TKScenePaintListener scenePaintListener;
 
-    private TKClipboard dragSourceClipboard;
-
     private NGNode root;
     private NGCamera camera;
     protected Paint fillPaint;
@@ -241,25 +239,26 @@
     @Override
     public TKClipboard createDragboard(boolean isDragSource) {
         ClipboardAssistance assistant = new ClipboardAssistance(Clipboard.DND) {
-            @Override public void actionPerformed(final int performedAction) {
+            @Override
+            public void actionPerformed(final int performedAction) {
+                super.actionPerformed(performedAction);
                 AccessController.doPrivileged(new PrivilegedAction<Void>() {
                     @Override
                     public Void run() {
-                        if ((dragSourceClipboard != null) && (dragSourceListener != null)) {
-                            dragSourceListener.dragDropEnd(0, 0, 0, 0,
-                                    QuantumToolkit.clipboardActionToTransferMode(performedAction));
+                        try {
+                            if (dragSourceListener != null) {
+                                dragSourceListener.dragDropEnd(0, 0, 0, 0,
+                                        QuantumToolkit.clipboardActionToTransferMode(performedAction));
+                            }
+                        } finally {
+                            QuantumClipboard.releaseCurrentDragboard();
                         }
-                        dragSourceClipboard = null;
                         return null;
                     }
                 }, getAccessControlContext());
             }
         };
-        QuantumClipboard dragboard = QuantumClipboard.getDragboardInstance(assistant);
-        if (isDragSource) {
-            dragSourceClipboard = dragboard;
-        }
-        return dragboard;
+        return QuantumClipboard.getDragboardInstance(assistant, isDragSource);
     }
 
     protected final GlassStage getStage() {
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/GlassSceneDnDEventHandler.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/GlassSceneDnDEventHandler.java	Mon Nov 18 22:06:51 2013 -0800
@@ -43,6 +43,8 @@
         this.scene = scene;
     }
 
+    // Drop target handlers
+
     public TransferMode handleDragEnter(final int x, final int y, final int xAbs, final int yAbs,
                                         final TransferMode recommendedTransferMode,
                                         final ClipboardAssistance dropTargetAssistant)
@@ -52,7 +54,8 @@
             @Override
             public TransferMode run() {
                 if (scene.dropTargetListener != null) {
-                    QuantumClipboard dragboard = QuantumClipboard.getDragboardInstance(dropTargetAssistant);
+                    QuantumClipboard dragboard =
+                            QuantumClipboard.getDragboardInstance(dropTargetAssistant, false);
                     return scene.dropTargetListener.dragEnter(x, y, xAbs, yAbs,
                             recommendedTransferMode, dragboard);
                 }
@@ -108,6 +111,12 @@
         }, scene.getAccessControlContext());
     }
 
+    // Drag source handlers
+
+    // This is a callback from the native platform, when a drag gesture is
+    // detected. This mechanism is currently not used in FX, as we have
+    // a custom gesture recognizer in Scene, and DnD is started with
+    // Toolkit.startDrag().
     public void handleDragStart(final int button, final int x, final int y, final int xAbs, final int yAbs,
                                 final ClipboardAssistance dragSourceAssistant)
     {
@@ -116,7 +125,8 @@
             @Override
             public Void run() {
                 if (scene.dragGestureListener != null) {
-                    QuantumClipboard dragboard = QuantumClipboard.getDragboardInstance(dragSourceAssistant);
+                    QuantumClipboard dragboard =
+                            QuantumClipboard.getDragboardInstance(dragSourceAssistant, true);
                     scene.dragGestureListener.dragGestureRecognized(
                             x, y, xAbs, yAbs, button, dragboard);
                 }
@@ -125,9 +135,9 @@
         }, scene.getAccessControlContext());
     }
 
-    // Used in case the drag has started from the handleDragStart() above - 
-    // it's delivered by Glass itself.
-    // Otherwise, see QuantumToolkit.createDragboard() and startDrag()
+    // This is a callback from the native platform, when the drag was started
+    // from handleDragStart() above, or when FX as a drag source is embedded
+    // to Swing/SWT.
     public void handleDragEnd(final TransferMode performedTransferMode,
                               final ClipboardAssistance dragSourceAssistant)
     {
@@ -135,9 +145,12 @@
         AccessController.doPrivileged(new PrivilegedAction<Void>() {
             @Override
             public Void run() {
-                if (scene.dragSourceListener != null) {
-                    scene.dragSourceListener.dragDropEnd(0, 0, 0, 0,
-                            performedTransferMode);
+                try {
+                    if (scene.dragSourceListener != null) {
+                        scene.dragSourceListener.dragDropEnd(0, 0, 0, 0, performedTransferMode);
+                    }
+                } finally {
+                    QuantumClipboard.releaseCurrentDragboard();
                 }
                 return null;
             }
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/QuantumClipboard.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/QuantumClipboard.java	Mon Nov 18 22:06:51 2013 -0800
@@ -30,6 +30,7 @@
 import java.io.File;
 import java.io.FilePermission;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.ObjectInput;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutput;
@@ -40,7 +41,6 @@
 import java.net.URL;
 import java.nio.ByteBuffer;
 import java.security.AccessControlContext;
-import java.security.AccessController;
 import java.security.AllPermission;
 import java.security.Permission;
 import java.util.ArrayList;
@@ -88,26 +88,6 @@
     private AccessControlContext accessContext = null;
 
     /**
-     * Disallow direct creation of QuantumClipboard
-     */
-    private QuantumClipboard() {
-    }
-
-    @Override public void setSecurityContext(AccessControlContext acc) {
-        if (accessContext != null) {
-            throw new RuntimeException("Clipboard security context has been already set!");
-        }
-        accessContext = acc;
-    }
-
-    private AccessControlContext getAccessControlContext() {
-        if (accessContext == null) {
-            throw new RuntimeException("Clipboard security context has not been set!");
-        }
-        return accessContext;
-    }
-
-    /**
      * Distinguishes between clipboard and dragboard. This is needed
      * because dragboard's flush() starts DnD operation so it mustn't be
      * called too early.
@@ -138,6 +118,28 @@
     private double dragOffsetX = 0;
     private double dragOffsetY = 0;
 
+    private static ClipboardAssistance currentDragboard;
+
+    /**
+     * Disallow direct creation of QuantumClipboard
+     */
+    private QuantumClipboard() {
+    }
+
+    @Override public void setSecurityContext(AccessControlContext acc) {
+        if (accessContext != null) {
+            throw new RuntimeException("Clipboard security context has been already set!");
+        }
+        accessContext = acc;
+    }
+
+    private AccessControlContext getAccessControlContext() {
+        if (accessContext == null) {
+            throw new RuntimeException("Clipboard security context has not been set!");
+        }
+        return accessContext;
+    }
+
     /**
      * Gets an instance of QuantumClipboard for the given assistant. This may be
      * a new instance after each call.
@@ -151,6 +153,15 @@
         return c;
     }
 
+    static ClipboardAssistance getCurrentDragboard() {
+        return currentDragboard;
+    }
+
+    static void releaseCurrentDragboard() {
+        assert currentDragboard != null;
+        currentDragboard = null;
+    }
+
     /**
      * Gets an instance of QuantumClipboard for the given assistant for usage
      * as dragboard during drag and drop. It doesn't flush the data implicitly
@@ -159,10 +170,13 @@
      * @param assistant
      * @return
      */
-    public static QuantumClipboard getDragboardInstance(ClipboardAssistance assistant) {
+    public static QuantumClipboard getDragboardInstance(ClipboardAssistance assistant, boolean isDragSource) {
         QuantumClipboard c = new QuantumClipboard();
         c.systemAssistant = assistant;
         c.isCaching = true;
+        if (isDragSource) {
+            currentDragboard = assistant;
+        }
         return c;
     }
 
@@ -212,12 +226,12 @@
     }
 
     @Override public Set<TransferMode> getTransferModes() {
-
         if (transferModesCache != null) {
             return EnumSet.copyOf(transferModesCache);
         }
 
-        final Set<TransferMode> tms = clipboardActionsToTransferModes(systemAssistant.getSupportedSourceActions());
+        ClipboardAssistance assistant = (currentDragboard != null) ? currentDragboard : systemAssistant;
+        final Set<TransferMode> tms = clipboardActionsToTransferModes(assistant.getSupportedSourceActions());
 
         return tms;
     }
@@ -270,12 +284,15 @@
             return null;
         }
 
+        ClipboardAssistance assistant =
+                (currentDragboard != null) ? currentDragboard : systemAssistant;
+
         if (dataFormat == DataFormat.IMAGE) {
             return readImage();
         } else if (dataFormat == DataFormat.URL) {
-            return systemAssistant.getData(Clipboard.URI_TYPE);
+            return assistant.getData(Clipboard.URI_TYPE);
         } else if (dataFormat == DataFormat.FILES) {
-            Object data = systemAssistant.getData(Clipboard.FILE_LIST_TYPE);
+            Object data = assistant.getData(Clipboard.FILE_LIST_TYPE);
             if (data == null) return Collections.emptyList();
             String[] paths = (String[]) data;
             List<File> list = new ArrayList<File>(paths.length);
@@ -286,7 +303,7 @@
         }
 
         for (String mimeType : dataFormat.getIdentifiers()) {
-            Object data = systemAssistant.getData(mimeType);
+            Object data = assistant.getData(mimeType);
             if (data instanceof ByteBuffer) {
                 try {
                     ByteBuffer bb = (ByteBuffer) data;
@@ -346,9 +363,12 @@
     }
 
     private Image readImage() {
-        Object rawData = systemAssistant.getData(Clipboard.RAW_IMAGE_TYPE);
+        ClipboardAssistance assistant =
+                (currentDragboard != null) ? currentDragboard : systemAssistant;
+
+        Object rawData = assistant.getData(Clipboard.RAW_IMAGE_TYPE);
         if (rawData == null) {
-            Object htmlData = systemAssistant.getData(Clipboard.HTML_TYPE);
+            Object htmlData = assistant.getData(Clipboard.HTML_TYPE);
             if (htmlData != null) {
                 String url = parseIMG(htmlData);
                 if (url != null) {
@@ -433,7 +453,6 @@
     }
 
     @Override public Set<DataFormat> getContentTypes() {
-
         Set<DataFormat> set = new HashSet<DataFormat>();
 
         if (dataCache != null) {
@@ -443,7 +462,10 @@
             return set;
         }
 
-        String[] types = systemAssistant.getMimeTypes();
+        ClipboardAssistance assistant =
+                (currentDragboard != null) ? currentDragboard : systemAssistant;
+
+        String[] types = assistant.getMimeTypes();
         if (types == null) {
             return set;
         }
@@ -459,7 +481,7 @@
                 // RT-16812 - IE puts images on the clipboard in a HTML IMG url
                 try {
                     //HTML header could be improperly formatted and we can get an exception here
-                    if (parseIMG(systemAssistant.getData(Clipboard.HTML_TYPE)) != null) {
+                    if (parseIMG(assistant.getData(Clipboard.HTML_TYPE)) != null) {
                         set.add(DataFormat.IMAGE);
                     }
                 } catch (Exception ex) {
@@ -487,7 +509,10 @@
             return false;
         }
 
-        String[] stypes = systemAssistant.getMimeTypes();
+        ClipboardAssistance assistant =
+                (currentDragboard != null) ? currentDragboard : systemAssistant;
+
+        String[] stypes = assistant.getMimeTypes();
         if (stypes == null) {
             return false;
         }
@@ -500,7 +525,7 @@
                 return true;
             } else if (dataFormat == DataFormat.IMAGE &&
                        t.equalsIgnoreCase(Clipboard.HTML_TYPE) &&
-                       parseIMG(systemAssistant.getData(Clipboard.HTML_TYPE)) != null) {
+                       parseIMG(assistant.getData(Clipboard.HTML_TYPE)) != null) {
                 return true;
             } else if (dataFormat == DataFormat.FILES &&
                     t.equalsIgnoreCase(Clipboard.FILE_LIST_TYPE)) {
@@ -587,9 +612,9 @@
                 }
             } else {
                 if (data instanceof Serializable) {
-                    if ((dataFormat != DataFormat.PLAIN_TEXT &&
-                            dataFormat != DataFormat.HTML) ||
-                            ! (data instanceof String)) {
+                    if ((dataFormat != DataFormat.PLAIN_TEXT && dataFormat != DataFormat.HTML) ||
+                        !(data instanceof String))
+                    {
                         try {
                             ByteArrayOutputStream bos = new ByteArrayOutputStream();
                             ObjectOutput out = new ObjectOutputStream(bos);
@@ -597,10 +622,22 @@
                             out.close();
                             data = ByteBuffer.wrap(bos.toByteArray());
                         } catch (IOException e) {
-                            throw new IllegalArgumentException("Could not "
-                                    + "serialize the data", e);
+                            throw new IllegalArgumentException("Could not serialize the data", e);
                         }
                     }
+                } else if (data instanceof InputStream) {
+                    ByteArrayOutputStream bout = new ByteArrayOutputStream();
+                    try (InputStream is = (InputStream)data) {
+                        // TODO: performance
+                        int i = is.read();
+                        while (i != -1) {
+                            bout.write(i);
+                            i = is.read();
+                        }
+                    } catch (IOException e) {
+                        throw new IllegalArgumentException("Could not serialize the data", e);
+                    }
+                    data = ByteBuffer.wrap(bout.toByteArray());
                 } else if (!(data instanceof ByteBuffer)) {
                     throw new IllegalArgumentException("Only serializable "
                             + "objects or ByteBuffer can be used as data "
--- a/modules/graphics/src/main/java/com/sun/prism/impl/PrismSettings.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/java/com/sun/prism/impl/PrismSettings.java	Mon Nov 18 22:06:51 2013 -0800
@@ -52,7 +52,6 @@
     public static final boolean cacheComplexShapes;
     public static final boolean useNewImageLoader;
     public static final List<String> tryOrder;
-    public static final int numSamples;
     public static final int prismStatFrequency;
     public static final boolean doPiscesText;
     public static final boolean doOpenPiscesText;
@@ -215,14 +214,6 @@
 
         tryOrder = Collections.unmodifiableList(Arrays.asList(tryOrderArr));
 
-        /* Multisampling in the form -Dprism.multisample=<true|2|4|8> */
-        numSamples = getInt(systemProperties, "prism.multisample",
-                            0, 2, "Try -Dprism.multisample=<true|2|4|8>");
-        if (numSamples > 0) {
-            System.out.println("Enabling multisampling with " +
-                               numSamples + " samples per pixel");
-        }
-
         String npprop = systemProperties.getProperty("prism.nativepisces");
         if (npprop == null) {
             doNativePisces = PlatformUtil.isEmbedded() || !PlatformUtil.isLinux();
--- a/modules/graphics/src/main/java/javafx/print/Printer.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/java/javafx/print/Printer.java	Mon Nov 18 22:06:51 2013 -0800
@@ -348,6 +348,11 @@
         double ptm = imgArea.getMinY();
         double prm = width - imgArea.getMaxX();
         double pbm = height - imgArea.getMaxY();
+        
+        lMargin /= 72.0;
+        rMargin /= 72.0;
+        tMargin /= 72.0;
+        bMargin /= 72.0;
 
         // Check if the requested margins exceed the paper and
         // if they do, ignore them.
@@ -379,10 +384,15 @@
         default: lm = plm; rm = prm; tm = ptm; bm = pbm;
         }
 
-        lm = (lMargin <= lm) ? lMargin : lm;
-        rm = (rMargin <= rm) ? rMargin : rm;
-        tm = (tMargin <= tm) ? tMargin : tm;
-        bm = (bMargin <= bm) ? bMargin : bm;
+        lm = (lMargin >= lm) ? lMargin : lm;
+        rm = (rMargin >= rm) ? rMargin : rm;
+        tm = (tMargin >= tm) ? tMargin : tm;
+        bm = (bMargin >= bm) ? bMargin : bm;
+
+        lm *= 72;
+        rm *= 72;
+        tm *= 72;
+        bm *= 72;
 
         return new PageLayout(paper, orient, lm, rm, tm, bm);
     }
--- a/modules/graphics/src/main/java/javafx/scene/Parent.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/java/javafx/scene/Parent.java	Mon Nov 18 22:06:51 2013 -0800
@@ -1053,12 +1053,25 @@
 
     /**
      * Executes a top-down layout pass on the scene graph under this parent.
+     * 
+     * Calling this method while the Parent is doing layout is a no-op.
      */
     public final void layout() {
         switch(layoutFlag) {
             case CLEAN:
                 break;
             case NEEDS_LAYOUT:
+                if (performingLayout) {
+                    /* This code is here mainly to avoid infinite loops as layout() is public and the call might be (indirectly) invoked accidentally
+                     * while doing the layout.
+                     * One example might be an invocation from Group layout bounds recalculation
+                     *  (e.g. during the localToScene/localToParent calculation).
+                     * The layout bounds will thus return layout bounds that are "old" (i.e. before the layout changes, that are just being done), 
+                     * which is likely what the code would expect.
+                     * The changes will invalidate the layout bounds again however, so the layout bounds query after layout pass will return correct answer.
+                     */
+                    break;
+                }
                 performingLayout = true;
                 layoutChildren();
                 // Intended fall-through
--- a/modules/graphics/src/main/java/javafx/scene/Scene.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/java/javafx/scene/Scene.java	Mon Nov 18 22:06:51 2013 -0800
@@ -3046,6 +3046,11 @@
         }
 
         private void processTargetExit(DragEvent de) {
+            if (dragboard == null) {
+                // dragboard should have been created in processTargetEnterOver()
+                throw new NullPointerException("dragboard is null in processTargetExit()");
+            }
+
             if (currentTargets.size() > 0) {
                 potentialTarget = null;
                 tmpTargetWrapper.clear();
@@ -3063,7 +3068,8 @@
                     acceptedTransferMode, source, potentialTarget, de.getPickResult());
 
             if (dragboard == null) {
-                dragboard = createDragboard(de, false);
+                // dragboard should have been created in processTargetEnterOver()
+                throw new NullPointerException("dragboard is null in processTargetDrop()");
             }
 
             handleExitEnter(de, tmpTargetWrapper);
@@ -5649,24 +5655,19 @@
     }
 
 
-    Dragboard startDragAndDrop(EventTarget source,
-            TransferMode... transferModes) {
-
-        if (dndGesture.dragDetected != DragDetectedState.PROCESSING) {
+    Dragboard startDragAndDrop(EventTarget source, TransferMode... transferModes) {
+        if (dndGesture == null ||
+            (dndGesture.dragDetected != DragDetectedState.PROCESSING))
+        {
             throw new IllegalStateException("Cannot start drag and drop " +
                     "outside of DRAG_DETECTED event handler");
         }
 
-        if (dndGesture != null) {
-            Set<TransferMode> set = EnumSet.noneOf(TransferMode.class);
-            for (TransferMode tm : InputEventUtils.safeTransferModes(transferModes)) {
-                set.add(tm);
-            }
-            return dndGesture.startDrag(source, set);
-        }
-
-        throw new IllegalStateException("Cannot start drag and drop when "
-                + "mouse button is not pressed");
+        Set<TransferMode> set = EnumSet.noneOf(TransferMode.class);
+        for (TransferMode tm : InputEventUtils.safeTransferModes(transferModes)) {
+            set.add(tm);
+        }
+        return dndGesture.startDrag(source, set);
     }
 
     void startFullDrag(EventTarget source) {
--- a/modules/graphics/src/main/java/javafx/scene/shape/Box.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/java/javafx/scene/shape/Box.java	Mon Nov 18 22:06:51 2013 -0800
@@ -411,8 +411,9 @@
 
         float texCoords[] = {0, 0, 1, 0, 1, 1, 0, 1};
 
+        // Specifies hard edges.
         int faceSmoothingGroups[] = {
-            1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4
+            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
         };
 
         int faces[] = {
--- a/modules/graphics/src/main/native-glass/gtk/glass_general.cpp	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/native-glass/gtk/glass_general.cpp	Mon Nov 18 22:06:51 2013 -0800
@@ -107,6 +107,13 @@
 jfieldID jApplicationVisualID;
 jmethodID jApplicationReportException;
 
+void init_threads() {
+    if (!g_thread_supported()) {
+        g_thread_init(NULL);
+    }
+    gdk_threads_init();
+}
+
 JNIEXPORT jint JNICALL
 JNI_OnLoad(JavaVM *jvm, void *reserved)
 {
@@ -212,8 +219,24 @@
     jApplicationReportException = env->GetStaticMethodID(
         jApplicationCls, "reportException", "(Ljava/lang/Throwable;)V");
 
-    g_thread_init(NULL);
-    gdk_threads_init();
+    clazz = env->FindClass("sun/misc/GThreadHelper");
+    if (clazz) {
+        jmethodID mid_getAndSetInitializationNeededFlag = env->GetStaticMethodID(clazz, "getAndSetInitializationNeededFlag", "()Z");
+        jmethodID mid_lock = env->GetStaticMethodID(clazz, "lock", "()V");
+        jmethodID mid_unlock = env->GetStaticMethodID(clazz, "unlock", "()V");
+
+        env->CallStaticVoidMethod(clazz, mid_lock);
+
+        if (!env->CallStaticBooleanMethod(clazz, mid_getAndSetInitializationNeededFlag)) {
+            init_threads();
+        }
+
+        env->CallStaticVoidMethod(clazz, mid_unlock);
+    } else {
+        env->ExceptionClear();
+        init_threads();
+    }
+
     gdk_threads_enter();
     gtk_init(NULL, NULL);
 
--- a/modules/graphics/src/main/native-glass/lens/input/udev/udevInput.c	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/native-glass/lens/input/udev/udevInput.c	Mon Nov 18 22:06:51 2013 -0800
@@ -589,7 +589,8 @@
         device->isPointer = JNI_TRUE;
         isValidDevice = JNI_TRUE;
         GLASS_LOG_FINE("Device is a pointer");
-    } else if (!strcmp(key, "ID_INPUT_TOUCHSCREEN")) {
+    } else if (!strcmp(key, "ID_INPUT_TOUCHSCREEN")
+               || !strcmp(key, "ID_INPUT_TABLET")) {
         device->isTouch = JNI_TRUE;
         //default touch protocol to ST (single touch), which is always supported 
         //by touch devices. multi touch support protocol is checked in 
--- a/modules/graphics/src/main/native-glass/lens/wm/LensWindowManager.c	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/native-glass/lens/wm/LensWindowManager.c	Mon Nov 18 22:06:51 2013 -0800
@@ -41,7 +41,6 @@
 static int _mousePosX;
 static int _mousePosY;
 
-static jboolean _mousePressed = JNI_FALSE;
 static jboolean _onDraggingAction = JNI_FALSE;
 static NativeWindow _dragGrabbingWindow = NULL;
 static int _mousePressedButton = com_sun_glass_events_MouseEvent_BUTTON_NONE;
@@ -1088,74 +1087,36 @@
     jboolean allReleased;    
 
     //set the touch window on first touch event
-    if (touchWindow == NULL && primaryPointIndex >= 0) {
+    if (touchWindow == NULL && primaryPointIndex >= 0 && !_onDraggingAction) {
         //find the touch window for first event
         touchWindow = glass_window_findWindowAtLocation(xabs[primaryPointIndex],
                                                         yabs[primaryPointIndex],
                                                         &relX, &relY);
+        
         if (touchWindow) {
-            //As this is the first time we find a window to report to, we need to
-            //transform all points states to 'press' and ignore release events, as 
-            //the input driver state calculation is done without a window context.
-            //An example for a wrong state -  tapping on an 'open space' and then
-            //dragging the finger over a window. The touch events will be 
-            //reported as move, from the input driver, but the window expect them to be
-            //pressed event as it the first time it get a notification for those
-            //points
+            GLASS_IF_LOG_FINEST("[touch event -> window] touch event on window %d[%p]",
+                                touchWindow->id,
+                                touchWindow);
+            //we have a touch point over a window, we need to check that its the
+            //starting point of the touch event sequence (all points pressed and
+            // we are not in the a middle of a drag), if not ignore the event.
+            //
+            //example scenario - touch outside a window and drag the finger
+            //into the window - same as press with a mouse outside a window, hold the
+            //button and drag mouse into the window
 
-            GLASS_LOG_FINEST("[touch window] window %d[%p] own the touch sequence",
-                             touchWindow->id,
-                             touchWindow);
 
-            int actualCount = 0;
             for (i = 0; i < count; i++) {
-                if (states[i] == com_sun_glass_events_TouchEvent_TOUCH_RELEASED) {
-                    //skip and drop release events
-                    GLASS_LOG_FINEST("[touch window] Dropping touch point (index %d id %d)",
-                                     i,
-                                     (int)ids[i]);
-                    continue;
-                } else {
-                    //copy 
-                    ids[actualCount] = ids[i];
-                    states[actualCount] = com_sun_glass_events_TouchEvent_TOUCH_PRESSED;
-                    xabs[actualCount] = xabs[i];
-                    yabs[actualCount] = yabs[i];
-
-                    //update the index of the primary point 
-                    if (primaryPointIndex == i) {
-                        primaryPointIndex = actualCount;
-                    }
-
-                    actualCount ++;
+                if (states[i] != com_sun_glass_events_TouchEvent_TOUCH_PRESSED) {
+                    GLASS_IF_LOG_FINEST("[touch event -> window] in middle of touch sequance (states[%d]=%d) - ignore",
+                                        i,
+                                        states[i]);
+                    touchWindow = NULL;
+                    break;
                 }
             }
+        }
 
-            GLASS_IF_LOG_FINEST {
-                if (count != actualCount) {                    
-                    GLASS_LOG_FINEST("[touch window] points array have been updated to:");
-                        for (i = 0; i < actualCount; i++) {
-                            const char *isPrimary = primaryPointIndex == i?
-                                                    "[Primary]":
-                                                    "";
-                            GLASS_LOG_FINEST("[touch window] point %d / %d id=%d state=%d, x=%d y=%d %s",
-                                             i+1,
-                                             actualCount,
-                                             (int)ids[i],
-                                             states[i],
-                                             xabs[i], yabs[i],
-                                             isPrimary);
-                        }
-                        GLASS_LOG_FINEST(" "); //make it easier to read the log
-                }
-
-            }
-            //update count
-            count = actualCount;
-
-            lens_wm_setMouseWindow(touchWindow);
-        }
-        
     }
 
     GLASS_LOG_FINEST("touch window %d, indexPoint = %d",
@@ -1237,10 +1198,13 @@
 
     fbCursorSetPosition(mousePosX, mousePosY);
     
-    if (_mousePressed && !_onDraggingAction && !isDnDStarted) {
-        GLASS_LOG_FINE("Starting native mouse drag");
+    if (_mousePressedButton != com_sun_glass_events_MouseEvent_BUTTON_NONE &&
+         !_onDraggingAction && !isDnDStarted) {
         _onDraggingAction = JNI_TRUE;
         _dragGrabbingWindow = lens_wm_getMouseWindow();
+        GLASS_LOG_FINE("Starting native mouse drag on windown %d[%p]",
+                       _dragGrabbingWindow?_dragGrabbingWindow->id : -1,
+                       _dragGrabbingWindow);
     }
     NativeWindow window = glass_window_findWindowAtLocation(_mousePosX, _mousePosY,
                                                             &relX, &relY);
--- a/modules/graphics/src/main/native-glass/mac/GlassView3D.m	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/native-glass/mac/GlassView3D.m	Mon Nov 18 22:06:51 2013 -0800
@@ -757,9 +757,9 @@
 
 - (NSRect) firstRectForCharacterRange:(NSRange)theRange actualRange:(NSRangePointer)actualRange
 {
-    IMLOG("firstRectForCharacterRange called %lu %lu", 
-            (unsigned long)theRange.location, (unsigned long)theRange.length);    
-    NSRect result = [self->_delegate getInputMethodCandidatePosRequest:(int)theRange.length];
+    IMLOG("firstRectForCharacterRange called %lu %lu",
+          (unsigned long)theRange.location, (unsigned long)theRange.length);
+    NSRect result = [self->_delegate getInputMethodCandidatePosRequest:0];
     NSRect screenFrame = [[NSScreen mainScreen] frame];
     result.origin.y = screenFrame.size.height - result.origin.y;
     return result;
--- a/modules/graphics/src/main/native-prism-d3d/D3DBadHardware.h	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/native-prism-d3d/D3DBadHardware.h	Mon Nov 18 22:06:51 2013 -0800
@@ -120,37 +120,74 @@
     { 0x8086, 0x2A03, NO_VERSION, OS_ALL },
     { 0x8086, 0x2A12, NO_VERSION, OS_ALL },
     { 0x8086, 0x2A13, NO_VERSION, OS_ALL },
+
+    // ATI Radeon X1000 series
+    // Reason: RT-33212 - This series of low to medium range cards
+    //                    are too old to be usable for JavaFX
+    { 0x1002, 0x7140, NO_VERSION, OS_ALL},
+    { 0x1002, 0x7142, NO_VERSION, OS_ALL},
+    { 0x1002, 0x7143, NO_VERSION, OS_ALL},
+    { 0x1002, 0x7145, NO_VERSION, OS_ALL},
+    { 0x1002, 0x7146, NO_VERSION, OS_ALL},
+    { 0x1002, 0x7147, NO_VERSION, OS_ALL},
+    { 0x1002, 0x7149, NO_VERSION, OS_ALL},
+    { 0x1002, 0x714A, NO_VERSION, OS_ALL},
+    { 0x1002, 0x714B, NO_VERSION, OS_ALL},
+    { 0x1002, 0x714C, NO_VERSION, OS_ALL},
+    { 0x1002, 0x714D, NO_VERSION, OS_ALL},
+    { 0x1002, 0x714E, NO_VERSION, OS_ALL},
+    { 0x1002, 0x715E, NO_VERSION, OS_ALL},
+    { 0x1002, 0x715F, NO_VERSION, OS_ALL},
+    { 0x1002, 0x7160, NO_VERSION, OS_ALL},
+    { 0x1002, 0x7162, NO_VERSION, OS_ALL},
+    { 0x1002, 0x7163, NO_VERSION, OS_ALL},
+    { 0x1002, 0x7166, NO_VERSION, OS_ALL},
+    { 0x1002, 0x7167, NO_VERSION, OS_ALL},
+    { 0x1002, 0x716D, NO_VERSION, OS_ALL},
+    { 0x1002, 0x716E, NO_VERSION, OS_ALL},
+    { 0x1002, 0x717E, NO_VERSION, OS_ALL},
+    { 0x1002, 0x717F, NO_VERSION, OS_ALL},
+    { 0x1002, 0x7180, NO_VERSION, OS_ALL},
+    { 0x1002, 0x7181, NO_VERSION, OS_ALL},
+    { 0x1002, 0x7183, NO_VERSION, OS_ALL},
+    { 0x1002, 0x7186, NO_VERSION, OS_ALL},
+    { 0x1002, 0x7187, NO_VERSION, OS_ALL},
+    { 0x1002, 0x718B, NO_VERSION, OS_ALL},
+    { 0x1002, 0x718C, NO_VERSION, OS_ALL},
+    { 0x1002, 0x718D, NO_VERSION, OS_ALL},
+    { 0x1002, 0x718F, NO_VERSION, OS_ALL},
+    { 0x1002, 0x7193, NO_VERSION, OS_ALL},
+    { 0x1002, 0x7196, NO_VERSION, OS_ALL},
+    { 0x1002, 0x719F, NO_VERSION, OS_ALL},
+    { 0x1002, 0x71A0, NO_VERSION, OS_ALL},
+    { 0x1002, 0x71A1, NO_VERSION, OS_ALL},
+    { 0x1002, 0x71A3, NO_VERSION, OS_ALL},
+    { 0x1002, 0x71A7, NO_VERSION, OS_ALL},
+    { 0x1002, 0x71AF, NO_VERSION, OS_ALL},
+    { 0x1002, 0x71B3, NO_VERSION, OS_ALL},
+    { 0x1002, 0x71C0, NO_VERSION, OS_ALL},
+    { 0x1002, 0x71C1, NO_VERSION, OS_ALL},
+    { 0x1002, 0x71C2, NO_VERSION, OS_ALL},
+    { 0x1002, 0x71C3, NO_VERSION, OS_ALL},
+    { 0x1002, 0x71C5, NO_VERSION, OS_ALL},
+    { 0x1002, 0x71C6, NO_VERSION, OS_ALL},
+    { 0x1002, 0x71C7, NO_VERSION, OS_ALL},
+    { 0x1002, 0x71CD, NO_VERSION, OS_ALL},
+    { 0x1002, 0x71CE, NO_VERSION, OS_ALL},
+    { 0x1002, 0x71E0, NO_VERSION, OS_ALL},
+    { 0x1002, 0x71E2, NO_VERSION, OS_ALL},
+    { 0x1002, 0x71E3, NO_VERSION, OS_ALL},
+    { 0x1002, 0x71E6, NO_VERSION, OS_ALL},
+    { 0x1002, 0x71E7, NO_VERSION, OS_ALL},
+    { 0x1002, 0x71ED, NO_VERSION, OS_ALL},
+    { 0x1002, 0x71EE, NO_VERSION, OS_ALL},
+    { 0x1002, 0x7291, NO_VERSION, OS_ALL},
+    { 0x1002, 0x7293, NO_VERSION, OS_ALL},
+    { 0x1002, 0x72B1, NO_VERSION, OS_ALL},
+    { 0x1002, 0x72B3, NO_VERSION, OS_ALL},
+    { 0x1002, 0x791E, NO_VERSION, OS_ALL},
+    { 0x1002, 0x791F, NO_VERSION, OS_ALL},
     
-    // ATI Mobility Radeon X1600, X1400, X1450, X1300, X1350
-    // Reason: workaround for 6613066, 6687166
-    // X1300 (four sub ids)
-    { 0x1002, 0x714A, D_VERSION(6,14,10,6706), OS_WINXP },
-    { 0x1002, 0x714A, D_VERSION(7,14,10,0567), OS_VISTA },
-    { 0x1002, 0x7149, D_VERSION(6,14,10,6706), OS_WINXP },
-    { 0x1002, 0x7149, D_VERSION(7,14,10,0567), OS_VISTA },
-    { 0x1002, 0x714B, D_VERSION(6,14,10,6706), OS_WINXP },
-    { 0x1002, 0x714B, D_VERSION(7,14,10,0567), OS_VISTA },
-    { 0x1002, 0x714C, D_VERSION(6,14,10,6706), OS_WINXP },
-    { 0x1002, 0x714C, D_VERSION(7,14,10,0567), OS_VISTA },
-    // X1350 (three sub ids)
-    { 0x1002, 0x718B, D_VERSION(6,14,10,6706), OS_WINXP },
-    { 0x1002, 0x718B, D_VERSION(7,14,10,0567), OS_VISTA },
-    { 0x1002, 0x718C, D_VERSION(6,14,10,6706), OS_WINXP },
-    { 0x1002, 0x718C, D_VERSION(7,14,10,0567), OS_VISTA },
-    { 0x1002, 0x7196, D_VERSION(6,14,10,6706), OS_WINXP },
-    { 0x1002, 0x7196, D_VERSION(7,14,10,0567), OS_VISTA },
-    // X1400
-    { 0x1002, 0x7145, D_VERSION(6,14,10,6706), OS_WINXP },
-    { 0x1002, 0x7145, D_VERSION(7,14,10,0567), OS_VISTA },
-    // X1450 (two sub ids)
-    { 0x1002, 0x7186, D_VERSION(6,14,10,6706), OS_WINXP },
-    { 0x1002, 0x7186, D_VERSION(7,14,10,0567), OS_VISTA },
-    { 0x1002, 0x718D, D_VERSION(6,14,10,6706), OS_WINXP },
-    { 0x1002, 0x718D, D_VERSION(7,14,10,0567), OS_VISTA },
-    // X1600
-    { 0x1002, 0x71C5, D_VERSION(6,14,10,6706), OS_WINXP },
-    { 0x1002, 0x71C5, D_VERSION(7,14,10,0567), OS_VISTA },
-
     // ATI Mobility Radeon 9700
     // Reason: workaround for 6773336
     { 0x1002, 0x4E50, D_VERSION(6,14,10,6561), OS_WINXP },
--- a/modules/graphics/src/main/native-prism-d3d/D3DContext.cc	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/native-prism-d3d/D3DContext.cc	Mon Nov 18 22:06:51 2013 -0800
@@ -761,6 +761,7 @@
         IDirect3DSurface9 *pCurrentDepth = NULL;
         pd3dDevice->GetDepthStencilSurface(&pCurrentDepth);
         clearDepth = pCurrentDepth == NULL ? FALSE : clearDepth;
+        SAFE_RELEASE(pCurrentDepth);
     }
     if (clearDepth) {
         flags |= D3DCLEAR_ZBUFFER;
@@ -919,7 +920,6 @@
         }
         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
@@ -932,8 +932,10 @@
                 }
             }
         } else if (!renderTargetChanged) {
+            SAFE_RELEASE(pCurrentDepth);
             return res; // Render target has not changed
         }
+        SAFE_RELEASE(pCurrentDepth);
         pd3dDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, msaa);
     }
     // NOTE PRISM: changed to only recalculate the matrix if current target is
--- a/modules/graphics/src/main/native-prism-d3d/D3DGraphics.cc	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/native-prism-d3d/D3DGraphics.cc	Mon Nov 18 22:06:51 2013 -0800
@@ -194,7 +194,7 @@
     RECT dstRect = {dstX0, dstY0, dstX1, dstY1};
     res = pd3dDevice->StretchRect(pSrcSurface, &srcRect, pDst, &dstRect, D3DTEXF_NONE);
     if (FAILED(res)) {
-        DebugPrintD3DError(res, "D3DContext::strechRect: error StretchRect");
+        DebugPrintD3DError(res, "D3DContext::stretchRect: error StretchRect");
     }
 }
 
--- a/modules/graphics/src/main/native-prism-d3d/D3DLight.h	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/native-prism-d3d/D3DLight.h	Mon Nov 18 22:06:51 2013 -0800
@@ -26,9 +26,6 @@
 #ifndef D3DLIGHT_H
 #define D3DLIGHT_H
 
-#include <windows.h>
-#include <d3d9.h>
-#include <stddef.h>
 #include "D3DContext.h"
 
 // See     Light.h
--- a/modules/graphics/src/main/native-prism-d3d/D3DMesh.cc	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/native-prism-d3d/D3DMesh.cc	Mon Nov 18 22:06:51 2013 -0800
@@ -105,14 +105,16 @@
 //            << ", indexBufferSize = " << ibSize << endl;
 
     IDirect3DDevice9 *device = context->Get3DDevice();
-    UINT size = vbSize * sizeof (float);
+    D3DPOOL pool = context->getResourcePool();
+    UINT size = vbSize * sizeof (float); // in bytes
+    UINT vbCount = size / PRIMITIVE_VERTEX_SIZE; // in vertices
     HRESULT result = D3D_OK;
 
-    if (numVertices != vbSize) {
+    if (numVertices != vbCount) {
         releaseVertexBuffer();
         result = device->CreateVertexBuffer(size, D3DUSAGE_WRITEONLY, fvf,
-                D3DPOOL_DEFAULT, &vertexBuffer, NULL);
-        numVertices = vbSize;
+                pool, &vertexBuffer, NULL);
+        numVertices = vbCount;
     }
 
     if (SUCCEEDED(result) && (vertexBuffer != NULL)) {
@@ -129,7 +131,7 @@
     if (SUCCEEDED(result) && (numIndices != ibSize)) {
         releaseIndexBuffer();
         result = device->CreateIndexBuffer(size, D3DUSAGE_WRITEONLY,
-                D3DFMT_INDEX16, D3DPOOL_DEFAULT, &indexBuffer, NULL);
+                D3DFMT_INDEX16, pool, &indexBuffer, NULL);
         numIndices = ibSize;
     }
 
@@ -151,14 +153,16 @@
 //            << ", indexBufferSize = " << ibSize << endl;
 
     IDirect3DDevice9 *device = context->Get3DDevice();
-    UINT size = vbSize * sizeof (float);
+    D3DPOOL pool = context->getResourcePool();
+    UINT size = vbSize * sizeof (float); // in bytes
+    UINT vbCount = size / PRIMITIVE_VERTEX_SIZE; // in vertices
     HRESULT result = D3D_OK;
 
-    if (numVertices != vbSize) {
+    if (numVertices != vbCount) {
         releaseVertexBuffer();
         result = device->CreateVertexBuffer(size, D3DUSAGE_WRITEONLY, fvf,
-                D3DPOOL_DEFAULT, &vertexBuffer, NULL);
-        numVertices = vbSize;
+                pool, &vertexBuffer, NULL);
+        numVertices = vbCount;
     }
 
     if (SUCCEEDED(result) && (vertexBuffer != NULL)) {
@@ -175,7 +179,7 @@
     if (SUCCEEDED(result) && (numIndices != ibSize)) {
         releaseIndexBuffer();
         result = device->CreateIndexBuffer(size, D3DUSAGE_WRITEONLY,
-                D3DFMT_INDEX32, D3DPOOL_DEFAULT, &indexBuffer, NULL);
+                D3DFMT_INDEX32, pool, &indexBuffer, NULL);
         numIndices = ibSize;
     }
 
--- a/modules/graphics/src/main/native-prism-d3d/D3DMesh.h	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/native-prism-d3d/D3DMesh.h	Mon Nov 18 22:06:51 2013 -0800
@@ -26,9 +26,6 @@
 #ifndef D3DMESH_H
 #define D3DMESH_H
 
-#include <windows.h>
-#include <d3d9.h>
-#include <stddef.h>
 #include "D3DContext.h"
 
 // See     MeshVbIb.h
--- a/modules/graphics/src/main/native-prism-d3d/D3DMeshView.cc	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/native-prism-d3d/D3DMeshView.cc	Mon Nov 18 22:06:51 2013 -0800
@@ -87,24 +87,11 @@
     }
 }
 
-void D3DMeshView::sortLights() {
+void D3DMeshView::computeNumLights() {
     if (!lightsDirty)
         return;
     lightsDirty = false;
 
-    lightsOrder[0] = 0;
-    lightsOrder[1] = 1;
-    lightsOrder[2] = 2;
-
-    // bubble sort ;)
-    for (int i = 0; i < 2; ++i)
-        for (int j = 2; j > i; --j)
-            if (lights[lightsOrder[j - 1]].w < lights[lightsOrder[j]].w) {
-                int t = lightsOrder[j - 1];
-                lightsOrder[j - 1] = lightsOrder[j];
-                lightsOrder[j] = t;
-            }
-
     int n = 0;
     for (int i = 0; i != 3; ++i)
         n += lights[i].w ? 1 : 0;
@@ -143,11 +130,10 @@
         return;
     }
 
-    // TODO: 3D - Use Java layer sorting instead of the local sort.
-    sortLights();
+    computeNumLights();
     // 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, 1));
+        status = SUCCEEDED(device->SetVertexShaderConstantF(VSR_LIGHTS + i*2, lights[i].position, 1));
     }
 
     status = SUCCEEDED(device->SetVertexShaderConstantF(VSR_AMBIENTCOLOR, ambientLightColor, 1));
--- a/modules/graphics/src/main/native-prism-d3d/D3DMeshView.h	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/native-prism-d3d/D3DMeshView.h	Mon Nov 18 22:06:51 2013 -0800
@@ -26,9 +26,6 @@
 #ifndef D3DMESHVIEW_H
 #define D3DMESHVIEW_H
 
-#include <windows.h>
-#include <d3d9.h>
-#include <stddef.h>
 #include "D3DContext.h"
 #include "D3DLight.h"
 #include "D3DMesh.h"
@@ -44,7 +41,7 @@
     void setAmbientLight(float r, float g, float b);
     void setPointLight(int index, float x, float y, float z,
     float r, float g, float b, float w);
-    void sortLights();
+    void computeNumLights();
     void render();
 
 private:
@@ -52,7 +49,6 @@
     D3DMesh *mesh;
     D3DPhongMaterial *material;
     D3DLight lights[3];
-    int lightsOrder[3];
     float ambientLightColor[3];
     int  numLights;
     bool lightsDirty;
--- a/modules/graphics/src/main/native-prism-d3d/D3DPhongMaterial.h	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/native-prism-d3d/D3DPhongMaterial.h	Mon Nov 18 22:06:51 2013 -0800
@@ -26,9 +26,6 @@
 #ifndef D3DPHONGMATERIAL_H
 #define D3DPHONGMATERIAL_H
 
-#include <windows.h>
-#include <d3d9.h>
-#include <stddef.h>
 #include "D3DContext.h"
 
 // See MaterialPhong.h, MaterialPhongShaders.h
--- a/modules/graphics/src/main/native-prism-d3d/D3DPhongShader.cc	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/native-prism-d3d/D3DPhongShader.cc	Mon Nov 18 22:06:51 2013 -0800
@@ -24,8 +24,8 @@
  */
 
 #include <iostream>
+#include "D3DContext.h"
 #include "D3DPhongShader.h"
-#include "D3DContext.h"
 
 using std::cout;
 using std::cerr;
--- a/modules/graphics/src/main/native-prism-d3d/D3DPhongShader.h	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/native-prism-d3d/D3DPhongShader.h	Mon Nov 18 22:06:51 2013 -0800
@@ -25,9 +25,6 @@
 
 #ifndef D3DPHONGSHADER_H
 #define D3DPHONGSHADER_H
-#include <windows.h>
-#include <d3d9.h>
-#include <stddef.h>
 
 // VSR implies Vertex Shader Registers
 #define VSR_VIEWPROJMATRIX  0  // 4 total
--- a/modules/graphics/src/main/native-prism-d3d/D3DPhongShaderGen.cc	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/native-prism-d3d/D3DPhongShaderGen.cc	Mon Nov 18 22:06:51 2013 -0800
@@ -23,6 +23,7 @@
  * questions.
  */
 
+#include "D3DPipeline.h"
 #include "D3DPhongShader.h"
 
 #define shader(name) ShaderFunction name() { static
--- a/modules/graphics/src/main/native-prism-d3d/D3DPipeline.h	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/native-prism-d3d/D3DPipeline.h	Mon Nov 18 22:06:51 2013 -0800
@@ -33,7 +33,6 @@
     #define D3D_DEBUG_INFO
 #endif
 
-#define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 #include <d3d9.h>
 #include <stddef.h>
--- a/modules/graphics/src/main/native-prism-d3d/D3DPipelineManager.cc	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/native-prism-d3d/D3DPipelineManager.cc	Mon Nov 18 22:06:51 2013 -0800
@@ -75,31 +75,6 @@
 
     devType = SelectDeviceType();
 
-    // Partial fix to RT-5534
-    // Cache the value set to prism.multisample (in the Java land)
-
-    int numSamples = cfg.getInt("numSamples");
-
-    switch (numSamples) {
-        case 0:
-            userMultiSampleType = D3DMULTISAMPLE_NONE;
-            break;
-        case 2:
-            userMultiSampleType = D3DMULTISAMPLE_2_SAMPLES;
-            RlsTrace(NWT_TRACE_INFO, "Multisample == D3DMULTISAMPLE_2_SAMPLES\n");
-            break;
-        case 4:
-            userMultiSampleType = D3DMULTISAMPLE_4_SAMPLES;
-            RlsTrace(NWT_TRACE_INFO, "Multisample == D3DMULTISAMPLE_4_SAMPLES\n");
-            break;
-        case 8:
-            userMultiSampleType = D3DMULTISAMPLE_8_SAMPLES;
-            RlsTrace(NWT_TRACE_INFO, "Multisample == D3DMULTISAMPLE_8_SAMPLES\n");
-            break;
-        default:
-            userMultiSampleType = D3DMULTISAMPLE_NONE;
-            RlsTrace(NWT_TRACE_INFO, "Only support multisample value of 2|4|8, forcing to D3DMULTISAMPLE_0_SAMPLES\n");
-    }
 }
 
 HRESULT D3DPipelineManager::ReleaseD3D()
@@ -197,18 +172,14 @@
 HRESULT
 D3DPipelineManager::CheckOSVersion()
 {
-    // require Windows XP or newer client-class OS
-    if (OS::isWindowsXPorNewer() &&
-        !D3DPPLM_OsVersionMatches(OS_WINSERV_2008|OS_WINSERV_2003))
-    {
+    // require Windows XP or newer OS
+    if (OS::isWindowsXPorNewer()) {
         TraceLn(NWT_TRACE_INFO,
-                   "D3DPPLM::CheckOSVersion: Windows XP or newer client-classs"\
-                   " OS detected, passed");
+                   "D3DPPLM::CheckOSVersion: Windows XP or newer OS detected, passed");
         return S_OK;
     }
     RlsTraceLn(NWT_TRACE_ERROR,
-                  "D3DPPLM::CheckOSVersion: Windows 2000 or earlier (or a "\
-                  "server) OS detected, failed");
+                  "D3DPPLM::CheckOSVersion: Windows 2000 or earlier OS detected, failed");
     if (bNoHwCheck) {
         RlsTraceLn(NWT_TRACE_WARNING,
                       "  OS check overridden via NEWT_D3D_NO_HWCHECK");
--- a/modules/graphics/src/main/native-prism-d3d/D3DPipelineManager.h	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/native-prism-d3d/D3DPipelineManager.h	Mon Nov 18 22:06:51 2013 -0800
@@ -83,8 +83,6 @@
     LPDIRECT3D9 GetD3DObject() { return pd3d9; }
     D3DDEVTYPE GetDeviceType() { return devType; }
 
-    D3DMULTISAMPLE_TYPE GetUserMultiSampleType() { return userMultiSampleType; };
-
     // returns adapterOrdinal given a HMONITOR handle
     UINT GetAdapterOrdinalByHmon(HMONITOR hMon);
 
@@ -146,7 +144,6 @@
     // instance of this object
     static D3DPipelineManager* pMgr;
 
-    D3DMULTISAMPLE_TYPE userMultiSampleType;
 };
 
 #define OS_UNDEFINED    (0 << 0)
--- a/modules/graphics/src/main/native-prism-d3d/D3DResourceManager.cc	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/main/native-prism-d3d/D3DResourceManager.cc	Mon Nov 18 22:06:51 2013 -0800
@@ -106,6 +106,7 @@
     SAFE_PRINTLN(pSurface);
     SAFE_PRINTLN(pTexture);
     SAFE_PRINTLN(pSwapChain);
+    SAFE_PRINTLN(pDepthSurface);
 
     // note that it is normal for the SAFE_RELEASE here to complain about
     // remaining references (with debug build and tracing enabled) as long as
@@ -117,6 +118,7 @@
     SAFE_RELEASE(pTexture);
     SAFE_RELEASE(pResource);
     SAFE_RELEASE(pSwapChain);
+    SAFE_RELEASE(pDepthSurface);
 }
 
 D3DPixelShaderResource::D3DPixelShaderResource(IDirect3DPixelShader9 *pShader)
--- a/modules/graphics/src/test/java/com/sun/javafx/sg/prism/NGNodeTest.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/graphics/src/test/java/com/sun/javafx/sg/prism/NGNodeTest.java	Mon Nov 18 22:06:51 2013 -0800
@@ -406,11 +406,12 @@
             n.getOpaqueRegion();
             assertTrue(n.opaqueRegionRecomputed);
 
-            // Set to SRC_OVER (nothing should happen)
+            // Set to SRC_OVER (should recompute even though it may be a NOP)
+            // For leaf nodes it is a NOP, but for groups there is a difference
             n.opaqueRegionRecomputed = false;
             n.setNodeBlendMode(Blend.Mode.SRC_OVER);
             n.getOpaqueRegion();
-            assertFalse(n.opaqueRegionRecomputed);
+            assertTrue(n.opaqueRegionRecomputed);
 
             // Set to blend mode (should do it)
             n.opaqueRegionRecomputed = false;
@@ -428,7 +429,7 @@
             n.opaqueRegionRecomputed = false;
             n.setNodeBlendMode(null);
             n.getOpaqueRegion();
-            assertFalse(n.opaqueRegionRecomputed);
+            assertTrue(n.opaqueRegionRecomputed);
         }
     }
 
--- a/modules/swing/src/main/java/javafx/embed/swing/DataFlavorUtils.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/swing/src/main/java/javafx/embed/swing/DataFlavorUtils.java	Mon Nov 18 22:06:51 2013 -0800
@@ -25,6 +25,9 @@
 
 package javafx.embed.swing;
 
+import javafx.scene.input.DataFormat;
+
+import java.io.ByteArrayOutputStream;
 import java.util.Set;
 import java.util.Map;
 import java.util.List;
@@ -35,19 +38,23 @@
 import java.awt.datatransfer.DataFlavor;
 import java.awt.datatransfer.Transferable;
 import java.awt.datatransfer.UnsupportedFlavorException;
+
 import java.io.ByteArrayInputStream;
+import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
-import java.io.File;
 
 
 final class DataFlavorUtils {
+
     static String getFxMimeType(final DataFlavor flavor) {
         return flavor.getPrimaryType() + "/" + flavor.getSubType();
     }
 
     static Object adjustFxData(final DataFlavor flavor, final Object fxData)
-            throws UnsupportedEncodingException {
+            throws UnsupportedEncodingException
+    {
         // TBD: Handle more data types!!!
         if (fxData instanceof String) {
             if (flavor.isRepresentationClassInputStream()) {
@@ -56,12 +63,17 @@
                         ? ((String) fxData).getBytes(encoding)
                         : ((String) fxData).getBytes());
             }
+            if (flavor.isRepresentationClassByteBuffer()) {
+                // ...
+            }
         }
         return fxData;
     }
 
     static Object adjustSwingData(final DataFlavor flavor,
-                                  final Object swingData) {
+                                  final String mimeType,
+                                  final Object swingData)
+    {
         if (flavor.isFlavorJavaFileListType()) {
             // RT-12663
             final List<File> fileList = (List<File>)swingData;
@@ -72,17 +84,37 @@
             }
             return paths;
         }
+        DataFormat dataFormat = DataFormat.lookupMimeType(mimeType);
+        if (DataFormat.PLAIN_TEXT.equals(dataFormat)) {
+            if (flavor.isFlavorTextType()) {
+                if (swingData instanceof InputStream) {
+                    InputStream in = (InputStream)swingData;
+                    // TBD: charset
+                    ByteArrayOutputStream out = new ByteArrayOutputStream();
+                    byte[] bb = new byte[64];
+                    try {
+                        int len = in.read(bb);
+                        while (len != -1) {
+                            out.write(bb, 0, len);
+                            len = in.read(bb);
+                        }
+                        out.close();
+                        return new String(out.toByteArray());
+                    } catch (Exception z) {
+                        // ignore
+                    }
+                }
+            } else if (swingData != null) {
+                return swingData.toString();
+            }
+        }
         return swingData;
     }
 
-    static Map<String, DataFlavor> adjustSwingDataFlavors(
-            final DataFlavor[] flavors) {
-
-        //
+    static Map<String, DataFlavor> adjustSwingDataFlavors(final DataFlavor[] flavors) {
         // Group data flavors by FX mime type.
-        //
         final Map<String, Set<DataFlavor>> mimeType2Flavors =
-                new HashMap<String, Set<DataFlavor>>(flavors.length);
+                new HashMap<>(flavors.length);
         for (DataFlavor flavor : flavors) {
             final String mimeType = getFxMimeType(flavor);
             if (mimeType2Flavors.containsKey(mimeType)) {
@@ -112,11 +144,8 @@
             }
         }
 
-        //
         // Choose the best data flavor corresponding to the given FX mime type
-        //
-        final Map<String, DataFlavor> mimeType2Flavor =
-                new HashMap<String, DataFlavor>();
+        final Map<String, DataFlavor> mimeType2Flavor = new HashMap<>();
         for (String mimeType : mimeType2Flavors.keySet()) {
             final DataFlavor[] mimeTypeFlavors = mimeType2Flavors.get(mimeType).
                     toArray(new DataFlavor[0]);
@@ -131,29 +160,38 @@
         return mimeType2Flavor;
     }
 
-    static Map<String, Object> readAllData(final Transferable t) {
-        final Map<String, DataFlavor> fxMimeType2DataFlavor =
-                adjustSwingDataFlavors(t.getTransferDataFlavors());
-        return readAllData(t, fxMimeType2DataFlavor);
+    private static Object readData(final Transferable t, final DataFlavor flavor) {
+        Object obj = null;
+        try {
+            obj = t.getTransferData(flavor);
+        } catch (UnsupportedFlavorException ex) {
+            // FIXME: report error
+            ex.printStackTrace(System.err);
+        } catch (IOException ex) {
+            // FIXME: report error
+            ex.printStackTrace(System.err);
+        }
+        return obj;
     }
-    
+
     static Map<String, Object> readAllData(final Transferable t,
-                                           final Map<String, DataFlavor> fxMimeType2DataFlavor) {
-        final Map<String, Object> fxMimeType2Data =
-                new HashMap<String, Object>();
-        
+                                           final Map<String, DataFlavor> fxMimeType2DataFlavor)
+    {
+        final Map<String, Object> fxMimeType2Data = new HashMap<>();
+        for (DataFlavor flavor : t.getTransferDataFlavors()) {
+            Object obj = readData(t, flavor);
+            if (obj != null) {
+                String mimeType = getFxMimeType(flavor);
+                obj = adjustSwingData(flavor, mimeType, obj);
+                fxMimeType2Data.put(mimeType, obj);
+            }
+        }
         for (Map.Entry<String, DataFlavor> e: fxMimeType2DataFlavor.entrySet()) {
-            Object obj = null;
-            try {
-                obj = t.getTransferData(e.getValue());
-            } catch (UnsupportedFlavorException ex) {
-                // FIXME: report error
-            } catch (IOException ex) {
-                // FIXME: report error
-            }
-
+            String mimeType = e.getKey();
+            DataFlavor flavor = e.getValue();
+            Object obj = readData(t, flavor);
             if (obj != null) {
-                obj = adjustSwingData(e.getValue(), obj);
+                obj = adjustSwingData(flavor, mimeType, obj);
                 fxMimeType2Data.put(e.getKey(), obj);
             }
         }
--- a/modules/swing/src/main/java/javafx/embed/swing/JFXPanel.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/swing/src/main/java/javafx/embed/swing/JFXPanel.java	Mon Nov 18 22:06:51 2013 -0800
@@ -134,7 +134,8 @@
     private volatile EmbeddedWindow stage;
     private volatile Scene scene;
 
-    private final SwingDnD dnd;
+    // Accessed on EDT only
+    private SwingDnD dnd;
 
     private EmbeddedStageInterface stagePeer;
     private EmbeddedSceneInterface scenePeer;
@@ -156,7 +157,7 @@
     private volatile int screenX = 0;
     private volatile int screenY = 0;
 
-    // accessed on EDT only
+    // Accessed on EDT only
     private BufferedImage pixelsIm;
 
     private volatile float opacity = 1.0f;
@@ -227,13 +228,6 @@
 
         setFocusable(true);
         setFocusTraversalKeysEnabled(false);
-
-        this.dnd = new SwingDnD(this, new SwingDnD.JFXPanelFacade() {
-            @Override
-            public EmbeddedSceneInterface getScene() {
-                return isFxEnabled() ? scenePeer : null;
-            }
-        });
     }
 
     /**
@@ -705,13 +699,21 @@
 
     private void setFxEnabled(boolean enabled) {
         if (!enabled) {
-            disableCount.incrementAndGet();
+            if (disableCount.incrementAndGet() == 1) {
+                if (dnd != null) {
+                    dnd.removeNotify();
+                }
+            }
         } else {
             if (disableCount.get() == 0) {
                 //should report a warning about an extra enable call ?
                 return;
             }
-            disableCount.decrementAndGet();
+            if (disableCount.decrementAndGet() == 0) {
+                if (dnd != null) {
+                    dnd.addNotify();
+                }
+            }
         }
     }
 
@@ -741,7 +743,6 @@
         super.addNotify();
 
         registerFinishListener();
-        dnd.addNotify();
         AccessController.doPrivileged(new PrivilegedAction<Void>() {
             public Void run() {
                 JFXPanel.this.getToolkit().addAWTEventListener(ungrabListener,
@@ -797,8 +798,6 @@
             }
         });
 
-        dnd.removeNotify();
-
         /* see CR 4867453 */
         getInputContext().removeNotify(this);
 
@@ -824,19 +823,28 @@
 
         @Override
         public void setEmbeddedScene(EmbeddedSceneInterface embeddedScene) {
+            if (scenePeer == embeddedScene) {
+                return;
+            }
             scenePeer = embeddedScene;
             if (scenePeer == null) {
+                SwingUtilities.invokeLater(new Runnable() {
+                    @Override
+                    public void run() {
+                        dnd.removeNotify();
+                        dnd = null;
+                    }
+                });
                 return;
             }
             if (pWidth > 0 && pHeight > 0) {
                 scenePeer.setSize(pWidth, pHeight);
             }
-
-            // DnD-related calls on 'scenePeer' should go from AWT EDT.
             SwingUtilities.invokeLater(new Runnable() {
-
                 @Override
                 public void run() {
+                    dnd = new SwingDnD(JFXPanel.this, scenePeer);
+                    dnd.addNotify();
                     if (scenePeer != null) {
                         scenePeer.setDragStartListener(dnd.getDragStartListener());
                     }
--- a/modules/swing/src/main/java/javafx/embed/swing/SwingDnD.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/swing/src/main/java/javafx/embed/swing/SwingDnD.java	Mon Nov 18 22:06:51 2013 -0800
@@ -25,7 +25,8 @@
 
 package javafx.embed.swing;
 
-import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+
 import java.util.Collections;
 import java.util.ArrayList;
 import java.util.EnumSet;
@@ -33,12 +34,12 @@
 import java.util.List;
 import java.util.Set;
 
+import com.sun.javafx.embed.EmbeddedSceneDSInterface;
+import com.sun.javafx.embed.HostDragStartListener;
 import javafx.scene.input.TransferMode;
 
 import com.sun.javafx.embed.EmbeddedSceneInterface;
-import com.sun.javafx.embed.EmbeddedSceneDragSourceInterface;
-import com.sun.javafx.embed.EmbeddedSceneDragStartListenerInterface;
-import com.sun.javafx.embed.EmbeddedSceneDropTargetInterface;
+import com.sun.javafx.embed.EmbeddedSceneDTInterface;
 import com.sun.javafx.tk.Toolkit;
 
 import javax.swing.JComponent;
@@ -48,7 +49,6 @@
 
 import java.awt.datatransfer.DataFlavor;
 import java.awt.datatransfer.Transferable;
-import java.awt.datatransfer.UnsupportedFlavorException;
 import java.awt.dnd.DnDConstants;
 import java.awt.dnd.DragGestureEvent;
 import java.awt.dnd.DragGestureRecognizer;
@@ -61,6 +61,7 @@
 import java.awt.dnd.DropTargetDragEvent;
 import java.awt.dnd.DropTargetDropEvent;
 import java.awt.dnd.DropTargetEvent;
+import java.awt.dnd.DropTargetListener;
 
 import java.awt.event.InputEvent;
 import java.awt.event.MouseAdapter;
@@ -71,102 +72,89 @@
  */
 final class SwingDnD {
 
-    private final JFXPanelFacade facade;
     private final Transferable dndTransferable = new DnDTransferable();
+
+    private final DragSource dragSource;
     private final DragSourceListener dragSourceListener;
+
+    // swingDragSource and fxDropTarget are used when DnD is initiated from
+    // Swing or external process, i.e. this SwingDnD is used as a drop target
     private SwingDragSource swingDragSource;
-    private EmbeddedSceneDragSourceInterface fxDragSource;
-    private EmbeddedSceneDropTargetInterface dropTarget;
+    private EmbeddedSceneDTInterface fxDropTarget;
+
+    // fxDragSource is used when DnD is initiated from FX, i.e. this
+    // SwingDnD acts as a drag source
+    private EmbeddedSceneDSInterface fxDragSource;
+
     private MouseEvent me;
 
-    interface JFXPanelFacade {
-
-        EmbeddedSceneInterface getScene();
-    }
-
-    SwingDnD(final JComponent comp, final JFXPanelFacade facade) {
-        this.facade = facade;
+    SwingDnD(final JComponent comp, final EmbeddedSceneInterface embeddedScene) {
 
         comp.addMouseListener(new MouseAdapter() {
-
             @Override
             public void mouseClicked(MouseEvent me) {
                 storeMouseEvent(me);
             }
-
             @Override
             public void mouseDragged(MouseEvent me) {
                 storeMouseEvent(me);
             }
-
             @Override
             public void mousePressed(MouseEvent me) {
                 storeMouseEvent(me);
             }
-
             @Override
             public void mouseReleased(MouseEvent me) {
                 storeMouseEvent(me);
             }
         });
 
+        dragSource = new DragSource();
         dragSourceListener = new DragSourceAdapter() {
-
             @Override
             public void dragDropEnd(final DragSourceDropEvent dsde) {
-                // Fix for RT-21836
-                if (fxDragSource == null) {
-                    return;
-                }
-
-                assert hasFxScene();
-
+                assert fxDragSource != null;
                 try {
-                    fxDragSource.dragDropEnd(dropActionToTransferMode(dsde.
-                            getDropAction()));
+                    fxDragSource.dragDropEnd(dropActionToTransferMode(dsde.getDropAction()));
                 } finally {
                     fxDragSource = null;
                 }
             }
         };
 
-        new DropTarget(comp, DnDConstants.ACTION_COPY | DnDConstants.ACTION_MOVE |
-                DnDConstants.ACTION_LINK, new DropTargetAdapter() {
-
+        DropTargetListener dtl = new DropTargetAdapter() {
             @Override
             public void dragEnter(final DropTargetDragEvent e) {
-                if (!hasFxScene()) {
-                    e.rejectDrag();
+                // This is a temporary workaround for JDK-8027913
+                if ((swingDragSource != null) || (fxDropTarget != null)) {
                     return;
                 }
 
-                if (fxDragSource == null) {
-                    // There is no FX drag source, create wrapper for external
-                    // drag source.
-                    assert swingDragSource == null;
-                    swingDragSource = new SwingDragSource(e);
-                }
+                assert swingDragSource == null;
+                swingDragSource = new SwingDragSource();
+                swingDragSource.updateContents(e);
+
+                assert fxDropTarget == null;
+                // Cache the Transferable data in advance, as it cannot be
+                // queried from drop(). See comments in dragOver() and in
+                // drop() below
+                fxDropTarget = embeddedScene.createDropTarget();
 
                 final Point orig = e.getLocation();
                 final Point screen = new Point(orig);
                 SwingUtilities.convertPointToScreen(screen, comp);
-                applyDragResult(getDropTarget().handleDragEnter(orig.x, orig.y,
-                                                                screen.x,
-                                                                screen.y,
-                                                                dropActionToTransferMode(e.
-                        getDropAction()), getDragSource()), e);
+                final TransferMode dr = fxDropTarget.handleDragEnter(
+                        orig.x, orig.y, screen.x, screen.y,
+                        dropActionToTransferMode(e.getDropAction()), swingDragSource);
+                applyDragResult(dr, e);
             }
 
             @Override
             public void dragExit(final DropTargetEvent e) {
-                if (!hasFxScene()) {
-                    // The drag has been already rejected in dragEnter(), but it doesn't
-                    // prevent dragExit(), dragOver() and drop() from being called
-                    return;
-                }
-                
+                assert swingDragSource != null;
+                assert fxDropTarget != null;
                 try {
-                    dropTarget.handleDragLeave();
+                    fxDropTarget.handleDragLeave();
                 } finally {
                     endDnD();
                 }
@@ -174,91 +162,90 @@
 
             @Override
             public void dragOver(final DropTargetDragEvent e) {
-                if (!hasFxScene()) {
-                    // The drag has been already rejected in dragEnter(), but it doesn't
-                    // prevent dragExit(), dragOver() and drop() from being called
-                    return;
-                }
+                assert swingDragSource != null;
+                // We cache Transferable data in advance, as we can't fetch
+                // it from drop(), see comments in drop() below. However,
+                // caching in every dragOver() is too expensive and also for
+                // some reason has a weird side-effect: e.acceptDrag() is
+                // ignored, and no drops are possible. So the workaround is
+                // to cache all the data in dragEnter() only
+                //
+                // swingDragSource.updateContents(e);
 
-                if (swingDragSource != null) {
-                    swingDragSource.updateContents(e);
-                }
-
+                assert fxDropTarget != null;
                 final Point orig = e.getLocation();
                 final Point screen = new Point(orig);
                 SwingUtilities.convertPointToScreen(screen, comp);
-                applyDragResult(dropTarget.handleDragOver(orig.x, orig.y,
-                                                          screen.x, screen.y,
-                                                          dropActionToTransferMode(e.
-                        getDropAction())), e);
+                final TransferMode dr = fxDropTarget.handleDragOver(
+                        orig.x, orig.y, screen.x, screen.y,
+                        dropActionToTransferMode(e.getDropAction()));
+                applyDragResult(dr, e);
             }
 
             @Override
             public void drop(final DropTargetDropEvent e) {
-                if (!hasFxScene()) {
-                    // The drag has been already rejected in dragEnter(), but it doesn't
-                    // prevent dragExit(), dragOver() and drop() from being called
-                    return;
-                }
+                assert swingDragSource != null;
+                // Don't call updateContents() from drop(). In AWT, it is possible to
+                // get data from the Transferable object in drop() only after the drop
+                // has been accepted. Here we first let FX handle drop(), then accept
+                // or reject AWT drop based the result. So instead of querying the
+                // Transferable object, we use data from swingDragSource, which was
+                // cached in dragEnter(), but not in dragOver(), see comments in
+                // dragOver() above
+                //
+                // swingDragSource.updateContents(e);
 
                 final Point orig = e.getLocation();
                 final Point screen = new Point(orig);
                 SwingUtilities.convertPointToScreen(screen, comp);
 
+                assert fxDropTarget != null;
                 try {
-                    final TransferMode dropResult =
-                            dropTarget.handleDragDrop(orig.x, orig.y, screen.x,
-                                                      screen.y,
-                                                      dropActionToTransferMode(e.
-                            getDropAction()));
+                    final TransferMode dropResult = fxDropTarget.handleDragDrop(
+                            orig.x, orig.y, screen.x, screen.y,
+                            dropActionToTransferMode(e.getDropAction()));
                     applyDropResult(dropResult, e);
-
                     e.dropComplete(dropResult != null);
                 } finally {
                     endDnD();
                 }
             }
-        });
+        };
+        comp.setDropTarget(new DropTarget(comp,
+                DnDConstants.ACTION_COPY | DnDConstants.ACTION_MOVE | DnDConstants.ACTION_LINK, dtl));
+
     }
 
     void addNotify() {
-        DragSource.getDefaultDragSource().addDragSourceListener(
-                dragSourceListener);
+        dragSource.addDragSourceListener(dragSourceListener);
     }
 
     void removeNotify() {
         // RT-22049: Multi-JFrame/JFXPanel app leaks JFXPanels
         // Don't forget to unregister drag source listener!
-        DragSource.getDefaultDragSource().removeDragSourceListener(
-                dragSourceListener);
+        dragSource.removeDragSourceListener(dragSourceListener);
     }
 
-    EmbeddedSceneDragStartListenerInterface getDragStartListener() {
-        return new EmbeddedSceneDragStartListenerInterface() {
-
+    HostDragStartListener getDragStartListener() {
+        return new HostDragStartListener() {
             @Override
-            public void dragStarted(
-                    final EmbeddedSceneDragSourceInterface dragSource,
-                    final TransferMode dragAction) {
+            public void dragStarted(final EmbeddedSceneDSInterface dragSource,
+                                    final TransferMode dragAction)
+            {
                 assert Toolkit.getToolkit().isFxUserThread();
                 assert dragSource != null;
                 
-                //
                 // The method is called from FX Scene just before entering
                 // nested event loop servicing DnD events.
                 // It should initialize DnD in AWT EDT.
-                //
-
                 SwingUtilities.invokeLater(new Runnable() {
-
                     @Override
                     public void run() {
                         assert fxDragSource == null;
                         assert swingDragSource == null;
-                        assert dropTarget == null;
+                        assert fxDropTarget == null;
                         
                         fxDragSource = dragSource;
-
                         startDrag(me, dndTransferable, dragSource.
                                 getSupportedActions(), dragAction);
                     }
@@ -267,93 +254,50 @@
         };
     }
 
-    private static void startDrag(final MouseEvent e, final Transferable t,
+    private void startDrag(final MouseEvent e, final Transferable t,
                                   final Set<TransferMode> sa,
-                                  final TransferMode dragAction) {
-
+                                  final TransferMode dragAction)
+    {
         assert sa.contains(dragAction);
-
-        //
         // This is a replacement for the default AWT drag gesture recognizer.
         // Not sure DragGestureRecognizer was ever supposed to be used this way.
-        //
-
         final class StubDragGestureRecognizer extends DragGestureRecognizer {
-
-            StubDragGestureRecognizer() {
-                super(DragSource.getDefaultDragSource(), e.getComponent());
-                super.setSourceActions(transferModesToDropActions(sa));
-                super.appendEvent(e);
+            StubDragGestureRecognizer(DragSource ds) {
+                super(ds, e.getComponent());
+                setSourceActions(transferModesToDropActions(sa));
+                appendEvent(e);
             }
-
             @Override
             protected void registerListeners() {
             }
-
             @Override
             protected void unregisterListeners() {
             }
         }
 
         final Point pt = new Point(e.getX(), e.getY());
-
         final int action = transferModeToDropAction(dragAction);
-
-        final DragGestureRecognizer dgs = new StubDragGestureRecognizer();
-
-        final List<InputEvent> events = Arrays.asList(new InputEvent[]{dgs.
-                    getTriggerEvent()});
-
-        final DragGestureEvent dse = new DragGestureEvent(dgs, action, pt,
-                                                          events);
-
+        final DragGestureRecognizer dgs = new StubDragGestureRecognizer(dragSource);
+        final List<InputEvent> events =
+                Arrays.asList(new InputEvent[] { dgs.getTriggerEvent() });
+        final DragGestureEvent dse = new DragGestureEvent(dgs, action, pt, events);
         dse.startDrag(null, t);
     }
 
-    private boolean hasFxScene() {
-        assert SwingUtilities.isEventDispatchThread();
-        return getFxScene() != null;
-    }
-
-    private EmbeddedSceneInterface getFxScene() {
-        return facade.getScene();
-    }
-
-    private EmbeddedSceneDragSourceInterface getDragSource() {
-        assert hasFxScene();
-
-        assert (swingDragSource == null) != (fxDragSource == null);
-
-        if (swingDragSource != null) {
-            return swingDragSource;
-        }
-        return fxDragSource;
-    }
-
-    private EmbeddedSceneDropTargetInterface getDropTarget() {
-        assert hasFxScene();
-
-        if (dropTarget == null) {
-            dropTarget = getFxScene().createDropTarget();
-        }
-        return dropTarget;
-    }
-    
     private void endDnD() {
-        assert dropTarget != null;
-        
-        dropTarget = null;
-        if (swingDragSource != null) {
-            swingDragSource = null;
-        }
+        assert swingDragSource != null;
+        assert fxDropTarget != null;
+        fxDropTarget = null;
+        swingDragSource = null;
     }
 
     private void storeMouseEvent(final MouseEvent me) {
         this.me = me;
     }
 
-    private static void applyDragResult(final TransferMode dragResult,
-                                        final DropTargetDragEvent e) {
+    private void applyDragResult(final TransferMode dragResult,
+                                 final DropTargetDragEvent e)
+    {
         if (dragResult == null) {
             e.rejectDrag();
         } else {
@@ -361,8 +305,9 @@
         }
     }
 
-    private static void applyDropResult(final TransferMode dropResult,
-                                        final DropTargetDropEvent e) {
+    private void applyDropResult(final TransferMode dropResult,
+                                 final DropTargetDropEvent e)
+    {
         if (dropResult == null) {
             e.rejectDrop();
         } else {
@@ -399,7 +344,8 @@
     }
 
     static Set<TransferMode> dropActionsToTransferModes(
-            final int dropActions) {
+            final int dropActions)
+    {
         final Set<TransferMode> tms = EnumSet.noneOf(TransferMode.class);
         if ((dropActions & DnDConstants.ACTION_COPY) != 0) {
             tms.add(TransferMode.COPY);
@@ -421,35 +367,28 @@
         return dropActions;
     }
 
-    //
-    // This is facade to export data from FX to outer world.
-    //
+    // Transferable wrapper over FX dragboard. All the calls are
+    // forwarded to FX and executed on the FX event thread.
     private final class DnDTransferable implements Transferable {
 
         @Override
-        public Object getTransferData(final DataFlavor flavor) throws
-                UnsupportedFlavorException, IOException {
-            checkSwingEventDispatchThread();
+        public Object getTransferData(final DataFlavor flavor)
+                throws UnsupportedEncodingException
+        {
+            assert fxDragSource != null;
+            assert SwingUtilities.isEventDispatchThread();
 
-            if (!hasFxScene()) {
-                return null;
-            }
-
-            final String mimeType = DataFlavorUtils.getFxMimeType(flavor);
-
-            return DataFlavorUtils.adjustFxData(flavor, getDragSource().getData(
-                    mimeType));
+            String mimeType = DataFlavorUtils.getFxMimeType(flavor);
+            return DataFlavorUtils.adjustFxData(
+                    flavor, fxDragSource.getData(mimeType));
         }
 
         @Override
         public DataFlavor[] getTransferDataFlavors() {
-            checkSwingEventDispatchThread();
+            assert fxDragSource != null;
+            assert SwingUtilities.isEventDispatchThread();
 
-            if (!hasFxScene()) {
-                return null;
-            }
-
-            final String mimeTypes[] = getDragSource().getMimeTypes();
+            final String mimeTypes[] = fxDragSource.getMimeTypes();
 
             final ArrayList<DataFlavor> flavors =
                     new ArrayList<DataFlavor>(mimeTypes.length);
@@ -468,20 +407,11 @@
 
         @Override
         public boolean isDataFlavorSupported(final DataFlavor flavor) {
-            checkSwingEventDispatchThread();
+            assert fxDragSource != null;
+            assert SwingUtilities.isEventDispatchThread();
 
-            if (!hasFxScene()) {
-                return false;
-            }
-
-            return getDragSource().isMimeTypeAvailable(DataFlavorUtils.
-                    getFxMimeType(flavor));
-        }
-    };
-
-    private static void checkSwingEventDispatchThread() {
-        if (!SwingUtilities.isEventDispatchThread()) {
-            throw new IllegalStateException();
+            return fxDragSource.isMimeTypeAvailable(
+                    DataFlavorUtils.getFxMimeType(flavor));
         }
     }
 }
--- a/modules/swing/src/main/java/javafx/embed/swing/SwingDragSource.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/swing/src/main/java/javafx/embed/swing/SwingDragSource.java	Mon Nov 18 22:06:51 2013 -0800
@@ -25,12 +25,12 @@
 
 package javafx.embed.swing;
 
-import com.sun.javafx.embed.EmbeddedSceneDragSourceInterface;
+import com.sun.javafx.embed.EmbeddedSceneDSInterface;
 import com.sun.javafx.tk.Toolkit;
 import java.awt.datatransfer.DataFlavor;
 import java.awt.datatransfer.Transferable;
-import java.awt.dnd.DnDConstants;
 import java.awt.dnd.DropTargetDragEvent;
+import java.awt.dnd.DropTargetDropEvent;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Map;
@@ -40,45 +40,29 @@
 /**
  * Drag source to deliver data from Swing environment to embedded FX scene.
  */
-final class SwingDragSource implements EmbeddedSceneDragSourceInterface {
+final class SwingDragSource implements EmbeddedSceneDSInterface {
 
+    private int sourceActions;
     private Map<String, Object> mimeType2Data = Collections.EMPTY_MAP;
-    private int sourceActions;
-    private Set<TransferMode> cachedTransferModes;
-    
-    SwingDragSource(final DropTargetDragEvent e) {
-        setContents(e);
+
+    SwingDragSource() {
     }
     
     void updateContents(final DropTargetDragEvent e) {
-        updateSourceActions(e.getSourceActions());
+        sourceActions = e.getSourceActions();
         updateData(e.getTransferable());
     }
 
-    private void setContents(final DropTargetDragEvent e) {
-        this.sourceActions = DnDConstants.ACTION_NONE;
-        this.cachedTransferModes = null;
-        this.mimeType2Data = Collections.EMPTY_MAP;
-        updateContents(e);
+    void updateContents(final DropTargetDropEvent e) {
+        sourceActions = e.getSourceActions();
+        updateData(e.getTransferable());
     }
 
-    private void updateSourceActions(final int newSourceActions) {
-        if (newSourceActions != this.sourceActions) {
-            this.sourceActions = newSourceActions;
-            this.cachedTransferModes = null;
-        }
-    }
-
-    private void updateData(final Transferable t) {
+    private void updateData(Transferable t) {
         final Map<String, DataFlavor> mimeType2DataFlavor =
                 DataFlavorUtils.adjustSwingDataFlavors(
                 t.getTransferDataFlavors());
-        if (mimeType2DataFlavor.keySet().equals(mimeType2Data.keySet())) {
-            // Mime types have't changed. Assume data has not been
-            // changed as well, so don't need to reread it
-            return;
-        }
-        //
+
         // Read data from the given Transferable in advance. Need to do this
         // because we don't want Transferable#getTransferData() to be called
         // from DropTargetListener#drop().
@@ -99,7 +83,7 @@
         // SwingDragSource#getData() is called from FX user code and from
         // QuantumClipboard#getContent() (sik!). These calls usually take
         // place in the context of 
-        // EmbeddedSceneDropTargetInterface#handleDragDrop() method as the 
+        // EmbeddedSceneDTInterface#handleDragDrop() method as the
         // normal handling of DnD.
         // Instead of keeping reference to source Transferable we just read
         // all its data while in the context safe for calling
@@ -118,11 +102,7 @@
     @Override
     public Set<TransferMode> getSupportedActions() {
         assert Toolkit.getToolkit().isFxUserThread();
-        if (cachedTransferModes == null) {
-            cachedTransferModes =
-                    SwingDnD.dropActionsToTransferModes(sourceActions);
-        }
-        return cachedTransferModes;
+        return SwingDnD.dropActionsToTransferModes(sourceActions);
     }
 
     @Override
--- a/modules/swing/src/main/java/javafx/embed/swing/SwingNode.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/swing/src/main/java/javafx/embed/swing/SwingNode.java	Mon Nov 18 22:06:51 2013 -0800
@@ -145,6 +145,9 @@
                  activateLwFrame(newValue);
             }
         });
+
+        //Workaround for RT-34170
+        javafx.scene.text.Font.getFamilies();
     }
 
     /**
--- a/modules/swt/src/main/java/javafx/embed/swt/FXCanvas.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/swt/src/main/java/javafx/embed/swt/FXCanvas.java	Mon Nov 18 22:06:51 2013 -0800
@@ -39,15 +39,15 @@
 import com.sun.javafx.cursor.CursorFrame;
 import com.sun.javafx.cursor.CursorType;
 
+import com.sun.javafx.embed.EmbeddedSceneDSInterface;
+import com.sun.javafx.embed.HostDragStartListener;
 import javafx.application.Platform;
 import javafx.scene.Scene;
 import javafx.scene.input.TransferMode;
 
 import com.sun.javafx.application.PlatformImpl;
 import com.sun.javafx.embed.AbstractEvents;
-import com.sun.javafx.embed.EmbeddedSceneDragSourceInterface;
-import com.sun.javafx.embed.EmbeddedSceneDragStartListenerInterface;
-import com.sun.javafx.embed.EmbeddedSceneDropTargetInterface;
+import com.sun.javafx.embed.EmbeddedSceneDTInterface;
 import com.sun.javafx.embed.EmbeddedSceneInterface;
 import com.sun.javafx.embed.EmbeddedStageInterface;
 import com.sun.javafx.embed.HostInterface;
@@ -730,7 +730,7 @@
         }
 
         // Consider using dragAction
-        private DragSource createDragSource(final EmbeddedSceneDragSourceInterface fxDragSource, TransferMode dragAction) {
+        private DragSource createDragSource(final EmbeddedSceneDSInterface fxDragSource, TransferMode dragAction) {
             Transfer [] transfers = getTransferTypes(fxDragSource.getMimeTypes());
             if (transfers.length == 0) return null;
             int dragOperation = getDragActions(fxDragSource.getSupportedActions());
@@ -836,7 +836,7 @@
 
         DropTarget createDropTarget(EmbeddedSceneInterface embeddedScene) {
             final DropTarget dropTarget = new DropTarget(FXCanvas.this, DND.DROP_COPY | DND.DROP_LINK | DND.DROP_MOVE);
-            final EmbeddedSceneDropTargetInterface fxDropTarget = embeddedScene.createDropTarget();
+            final EmbeddedSceneDTInterface fxDropTarget = embeddedScene.createDropTarget();
             dropTarget.setTransfer(getAllTransfers());
             dropTarget.addDropListener(new DropTargetListener() {
                 Object data;
@@ -849,7 +849,7 @@
                 TransferData currentTransferData;
                 boolean ignoreLeave;
                 int detail = DND.DROP_NONE, operations = DND.DROP_NONE;
-                EmbeddedSceneDragSourceInterface fxDragSource = new EmbeddedSceneDragSourceInterface() {
+                EmbeddedSceneDSInterface fxDragSource = new EmbeddedSceneDSInterface() {
                     public Set<TransferMode> getSupportedActions() {
                         return getTransferModes(operations);
                     }
@@ -944,9 +944,9 @@
             if (pWidth > 0 && pHeight > 0) {
                 scenePeer.setSize(pWidth, pHeight);
             }
-            scenePeer.setDragStartListener(new EmbeddedSceneDragStartListenerInterface() {
+            scenePeer.setDragStartListener(new HostDragStartListener() {
                 @Override
-                public void dragStarted(final EmbeddedSceneDragSourceInterface fxDragSource, final TransferMode dragAction) {
+                public void dragStarted(final EmbeddedSceneDSInterface fxDragSource, final TransferMode dragAction) {
                     Platform.runLater(new Runnable ()  {
                         public void run () {
                             DragSource dragSource = createDragSource(fxDragSource, dragAction);
--- a/modules/swt/src/main/java/javafx/embed/swt/SWTEvents.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/swt/src/main/java/javafx/embed/swt/SWTEvents.java	Mon Nov 18 22:06:51 2013 -0800
@@ -64,19 +64,13 @@
         return 0;
     }
 */
-    // NOTE: not tested (are masked needed?)
     static int mouseButtonToEmbedMouseButton(int button, int extModifiers) {
-        int embedMouseButton = AbstractEvents.MOUSEEVENT_NONE_BUTTON;
-        if ((button == 1) || (extModifiers & SWT.BUTTON1) != 0) {
-            embedMouseButton |= AbstractEvents.MOUSEEVENT_PRIMARY_BUTTON;
+        switch (button) {
+            case 1: return AbstractEvents.MOUSEEVENT_PRIMARY_BUTTON;
+            case 2: return AbstractEvents.MOUSEEVENT_MIDDLE_BUTTON;
+            case 3: return AbstractEvents.MOUSEEVENT_SECONDARY_BUTTON;
         }
-        if ((button == 2) || (extModifiers & SWT.BUTTON2) != 0) {
-            embedMouseButton |= AbstractEvents.MOUSEEVENT_MIDDLE_BUTTON;
-        }
-        if ((button == 3) || (extModifiers & SWT.BUTTON3) != 0) {
-            embedMouseButton |= AbstractEvents.MOUSEEVENT_SECONDARY_BUTTON;
-        }
-        return embedMouseButton;
+        return AbstractEvents.MOUSEEVENT_NONE_BUTTON;
     }
 
     static int getWheelRotation(MouseEvent e, int embedMouseType) {
--- a/modules/web/src/main/java/com/sun/javafx/scene/web/skin/HTMLEditorSkin.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/web/src/main/java/com/sun/javafx/scene/web/skin/HTMLEditorSkin.java	Mon Nov 18 22:06:51 2013 -0800
@@ -697,7 +697,7 @@
                         if (item != null) {
                             setText(item);
                             // Remove trailing non-digits to get the size (don't assume there's a space).
-                            String size = item.replaceFirst("[^0-9.]*$", "");
+                            String size = item.replaceFirst("[^0-9.].*$", "");
                             setFont(new Font((String)fontFamilyComboBox.getValue(), Double.valueOf(size)));
                         }
                     }
--- a/modules/web/src/main/java/com/sun/javafx/webkit/InputMethodClientImpl.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/web/src/main/java/com/sun/javafx/webkit/InputMethodClientImpl.java	Mon Nov 18 22:06:51 2013 -0800
@@ -96,7 +96,9 @@
     // InputMethodRequests implementation
     public Point2D getTextLocation(int offset) {
         int[] loc = webPage.getClientTextLocation(offset);
-        WCPoint point = webPage.getPageClient().windowToScreen(new WCPoint(loc[0], loc[1]));
+        WCPoint point = webPage.getPageClient().windowToScreen(
+                // We need lower left corner of the char bounds rectangle here
+                new WCPoint(loc[0], loc[1] + loc[3]));
         return new Point2D(point.getIntX(), point.getIntY());
     }
 
--- a/modules/web/src/main/native/Source/WebCore/platform/java/WebPage.cpp	Thu Nov 14 10:49:15 2013 -0800
+++ b/modules/web/src/main/native/Source/WebCore/platform/java/WebPage.cpp	Mon Nov 18 22:06:51 2013 -0800
@@ -1704,11 +1704,21 @@
     Frame* frame = page->mainFrame();
 
     jint position = 0;
-    if (frame->editor().canEdit()) {
+    Editor &editor = frame->editor();
+    if (editor.canEdit()) {
         VisibleSelection selection = frame->selection()->selection();
         if (selection.isCaret()) {
             VisiblePosition caret = selection.visibleStart();
             position = caret.deepEquivalent().offsetInContainerNode();
+            if (editor.hasComposition()) {
+                int start = editor.compositionStart();
+                int end = editor.compositionEnd();
+                if (start < position && position <= end) {
+                    position = start;
+                } else if (position > end) {
+                    position -= end - start;
+                }
+            }
         }
     }
     return position;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/system/src/test/java/javafx/embed/swing/RT32570Test.java	Mon Nov 18 22:06:51 2013 -0800
@@ -0,0 +1,110 @@
+/*
+ * 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 javafx.embed.swing;
+
+import java.awt.Dimension;
+import javafx.scene.Group;
+import javafx.scene.Scene;
+import javafx.scene.paint.Color;
+import javafx.stage.Stage;
+import javax.swing.JLabel;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+import javax.swing.SwingUtilities;
+import org.junit.Test;
+import testharness.VisualTestBase;
+
+/**
+ * Tests that a JPopupMenu shown from inside of SwingNode second and
+ * all subsequent times is repainted.
+ *
+ * https://javafx-jira.kenai.com/browse/RT-32570
+ */
+public class RT32570Test extends VisualTestBase {
+
+    private static final double TOLERANCE = 0.07;
+    private static final int WIDTH = 100;
+    private static final int HEIGHT = 50;
+
+    private volatile SwingNode swingNode;
+    private Scene testScene;
+    private JPopupMenu popup;
+    private JLabel label;
+
+    private volatile boolean popped;
+
+    @Test(timeout=5000)
+    public void test() throws Exception {
+        runAndWait(() -> {
+            swingNode = new SwingNode();
+            Group group = new Group();
+            group.getChildren().add(swingNode);
+
+            testScene = new Scene(group, WIDTH, HEIGHT);
+            Stage stage = getStage();
+            stage.setScene(testScene);
+            stage.show();
+        });
+
+        SwingUtilities.invokeAndWait(() -> {
+            label = new JLabel();
+            label.setMinimumSize(new Dimension(WIDTH, HEIGHT));
+            label.setBackground(java.awt.Color.GREEN);
+            label.setOpaque(true);
+
+            popup = new JPopupMenu();
+            JMenuItem item = new JMenuItem();
+            item.setPreferredSize(new Dimension(WIDTH, HEIGHT));
+            item.setBackground(java.awt.Color.RED);
+            popup.add(item);
+
+            swingNode.setContent(label);
+        });
+
+        waitFirstFrame();
+
+        SwingUtilities.invokeAndWait(() -> popup.show(label, 0, 0));
+        SwingUtilities.invokeAndWait(() -> popup.setVisible(false));
+        SwingUtilities.invokeAndWait(() -> popup.show(label, 0, 0));
+
+        // Wait for the popup to be shown (second time):
+        while (!popped) {
+            runAndWait(() -> {
+                // If it's not shown, the background remains green
+                Color color = getColor(testScene, WIDTH / 2, HEIGHT / 2);
+                popped = !testColorEquals(Color.GREEN, color, TOLERANCE);
+            });
+            try { Thread.sleep(100); } catch(Exception e) {}
+        }
+
+        // Verify the popup content is painted:
+        runAndWait(() -> {
+            Color color = getColor(testScene, WIDTH / 2, HEIGHT / 2);
+            assertColorEquals(Color.RED, color, TOLERANCE);
+        });
+    }
+}
+
--- a/tests/system/src/test/java/testharness/VisualTestBase.java	Thu Nov 14 10:49:15 2013 -0800
+++ b/tests/system/src/test/java/testharness/VisualTestBase.java	Mon Nov 18 22:06:51 2013 -0800
@@ -175,14 +175,18 @@
     }
 
     protected void assertColorEquals(Color expected, Color actual, double delta) {
+        if (!testColorEquals(expected, actual, delta)) {
+            throw new AssertionFailedError("expected:" + colorToString(expected)
+                    + " but was:" + colorToString(actual));
+        }
+    }
+    
+    protected boolean testColorEquals(Color expected, Color actual, double delta) {
         double deltaRed = Math.abs(expected.getRed() - actual.getRed());
         double deltaGreen = Math.abs(expected.getGreen() - actual.getGreen());
         double deltaBlue = Math.abs(expected.getBlue() - actual.getBlue());
         double deltaOpacity = Math.abs(expected.getOpacity() - actual.getOpacity());
-        if (deltaRed > delta || deltaGreen > delta || deltaBlue > delta || deltaOpacity > delta) {
-            throw new AssertionFailedError("expected:" + colorToString(expected)
-                    + " but was:" + colorToString(actual));
-        }
+        return (deltaRed <= delta && deltaGreen <= delta && deltaBlue <= delta && deltaOpacity <= delta);
     }
 
     protected void assertColorDoesNotEqual(Color notExpected, Color actual, double delta) {