changeset 724:085fcfbba269

Automated merge with ssh://jfxsrc.us.oracle.com//javafx/2.2/MASTER/jfx/rt
author kcr
date Wed, 28 Mar 2012 11:51:15 -0700
parents dc9b910d1e55 ba369f618738
children edba48bc0a1c
files javafx-ui-common/src/com/sun/javafx/tk/TextHelper.java javafx-ui-common/src/javafx/scene/Parent.java
diffstat 20 files changed, 441 insertions(+), 499 deletions(-) [+]
line wrap: on
line diff
--- a/javafx-ui-common/src/com/sun/javafx/stage/PopupWindowPeerListener.java	Wed Mar 28 06:36:03 2012 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/stage/PopupWindowPeerListener.java	Wed Mar 28 11:51:15 2012 -0700
@@ -39,15 +39,6 @@
         this.popupWindow = popupWindow;
     }
 
-    public void changedSize(float w, float h) {
-        if (w != popupWindow.getWidth()) {
-            popupWindow.setWidth(w);
-        }
-        if (h != popupWindow.getHeight()) {
-            popupWindow.setHeight(h);
-        }
-    }
-
     public void changedFocused(boolean cf, FocusCause cause) {
         // TODO: at the native level popup windows are unfocusable, so we
         // don't get any focus notifications from the platform. Temporary
--- a/javafx-ui-common/src/com/sun/javafx/tk/DummyToolkit.java	Wed Mar 28 06:36:03 2012 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/tk/DummyToolkit.java	Wed Mar 28 11:51:15 2012 -0700
@@ -415,11 +415,6 @@
     }
 
     @Override
-    public TextHelper createTextHelper(Text text) {
-        throw new UnsupportedOperationException("Not supported yet.");
-    }
-
-    @Override
     public boolean imageContains(Object image, float x, float y) {
         throw new UnsupportedOperationException("Not supported yet.");
     }
--- a/javafx-ui-common/src/com/sun/javafx/tk/TextHelper.java	Wed Mar 28 06:36:03 2012 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2011, 2012, 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;
-
-import com.sun.javafx.geom.BaseBounds;
-import com.sun.javafx.geom.transform.BaseTransform;
-
-/**
- * Utility class used by Text nodes for measuring their bounds. instances of
- * this class are produced by Toolkit implementations. Generally a different
- * TextBoundsHelper class is created for each Text node, so as to allow the
- * toolkit implementation to cache information on the TextBoundsHelper.
- */
-public abstract class TextHelper {
-    public abstract BaseBounds computeBounds(BaseBounds bounds, BaseTransform tx);
-    public abstract BaseBounds computeLayoutBounds(BaseBounds bounds);
-    public abstract Object getCaretShape(int charIndex, boolean isLeading);
-    public abstract Object getSelectionShape();
-    public abstract Object getRangeShape(int start, int end);
-    public abstract Object getUnderlineShape(int start, int end);
-    public abstract Object getShape();
-    public abstract Object getHitInfo(float localX, float localY);
-    public abstract boolean contains(float localX, float localY);
-}
--- a/javafx-ui-common/src/com/sun/javafx/tk/Toolkit.java	Wed Mar 28 06:36:03 2012 -0700
+++ b/javafx-ui-common/src/com/sun/javafx/tk/Toolkit.java	Wed Mar 28 11:51:15 2012 -0700
@@ -636,8 +636,6 @@
     public abstract Object createSVGPathObject(SVGPath svgpath);
     public abstract Path2D createSVGPath2D(SVGPath svgpath);
 
-    public abstract TextHelper createTextHelper(Text text);
-
     /**
      * Tests whether the pixel on the given coordinates in the given image
      * is non-empty (not fully transparent). Return value is not defined
--- a/javafx-ui-common/src/javafx/scene/Node.java	Wed Mar 28 06:36:03 2012 -0700
+++ b/javafx-ui-common/src/javafx/scene/Node.java	Wed Mar 28 11:51:15 2012 -0700
@@ -4025,7 +4025,7 @@
      * @deprecated This is an internal API that is not intended for use and will be removed in the next version
      */
     @Deprecated
-    protected boolean impl_hasTransforms() {
+    public boolean impl_hasTransforms() {
         return (nodeTransformation != null)
                 && nodeTransformation.hasTransforms();
     }
@@ -6253,10 +6253,6 @@
 
     /**
      * Event dispatcher for invoking preprocessing of mouse events
-     *
-     * TODO: The dispatcher is inserted into the event dispatch chain, this
-     * needs to be solved differently, this way it's impossible for user
-     * to override this behavior.
      */
     private EventDispatcher preprocessMouseEventDispatcher;
 
--- a/javafx-ui-common/src/javafx/scene/Parent.java	Wed Mar 28 06:36:03 2012 -0700
+++ b/javafx-ui-common/src/javafx/scene/Parent.java	Wed Mar 28 11:51:15 2012 -0700
@@ -676,9 +676,6 @@
      */
     @Deprecated
     @Override protected Node impl_pickNodeLocal(PickRay pickRay) {
-//      TODO: FIX RT-5258: Optimize 3D picking
-       // if (intersects(pickRay)) {
-
             for (int i = children.size()-1; i >= 0; i--) {
                 Node picked = children.get(i).impl_pickNode(pickRay);
 
@@ -686,9 +683,6 @@
                     return picked;
                 }
             }
-
-      //}
-
         return null;
     }
 
@@ -1361,8 +1355,6 @@
         return extended;
     }
 
-
-    // TODO!!!
     // This is called when either the child is actually removed, OR IF IT IS
     // TOGGLED TO BE INVISIBLE. This is because in both cases it needs to be
     // cleared from the state which manages bounds.
@@ -1414,9 +1406,6 @@
             if (dirtyChildren != null) dirtyChildren.clear();
             cachedBoundsInvalid = false;
             cachedBounds.makeEmpty();
-            //TODO: isn't the above already done by childRemoved? If not in some
-            //      cases, shouldn't we do the following?
-            // top = left = bottom = right = near = far = null;
             return;
         }
 
@@ -1429,12 +1418,8 @@
 
             if (node.isVisible()) {
                 cachedBounds = node.getTransformedBounds(cachedBounds, BaseTransform.IDENTITY_TRANSFORM);
-                //TODO: shouldn't we do this?
-                //top = left = bottom = right = near = far = node;
             } else {
                 cachedBounds.makeEmpty();
-                //TODO: shouldn't we do this?
-                //top = left = bottom = right = near = far = null;
             }
             node.boundsChanged = false;
             return;
--- a/javafx-ui-common/src/javafx/scene/Scene.java	Wed Mar 28 06:36:03 2012 -0700
+++ b/javafx-ui-common/src/javafx/scene/Scene.java	Wed Mar 28 11:51:15 2012 -0700
@@ -633,8 +633,6 @@
             // content may have been added after scene was constructed, so
             // try again to set size based on content if the scene or window
             // weren't explicitly sized;
-            // (TODO): ideally we'd do this just once, at the latest point
-            // we could, before the window was assigned a size and made visible
             preferredSize();
         }
         impl_peer.setFillPaint(getFill() == null ? null : tk.getPaint(getFill()));
@@ -1141,10 +1139,6 @@
         protected void onChanged(Change<String> c) {
             StyleManager.getInstance().updateStylesheets(Scene.this);
             getRoot().impl_reapplyCSS();
-            // we'll immediately reapply the style for this scene. It might be
-            // better to defer eventually
-            // TODO needs to be wired up
-            // StyleManager.getInstance().getStyleHelper(this);
         }
     };
 
@@ -1194,14 +1188,9 @@
         if (PerformanceTracker.isLoggingEnabled()) {
             PerformanceTracker.logEvent("Scene.init for [" + this + "]");
         }
-        // TODO JASPER sure there is more init needed here
-
         mouseHandler = new MouseHandler();
         clickGenerator = new ClickGenerator();
 
-        // TODO need to reimplement
-        //StyleManager.getInstance().getStyleHelper(this);
-
         initialized = true;
 
         if (PerformanceTracker.isLoggingEnabled()) {
@@ -1491,7 +1480,6 @@
      * Set to true if something has happened to the focused node that makes
      * it no longer eligible to have the focus.
      *
-     * TODO: need to schedule a pulse if this turns true?
      */
     private boolean focusDirty = true;
 
@@ -1665,7 +1653,6 @@
     /**
      * Gets the scene's current focus owner node.
      *
-     * TODO: probably should be removed in favor of impl_focusOwner below.
      *
      * @treatAsPrivate implementation detail
      * @deprecated This is an internal API that is not intended for use and will be removed in the next version
@@ -1679,10 +1666,6 @@
      * variable might be false if this scene has no window, or if the
      * window is inactive (window.focused == false).
      *
-     * TODO this was added because of RT-3930. This needs to be reconciled
-     * with impl_getFocusOwner(). We don't need both. Exposing a variable
-     * is more powerful because it allows code to bind to it.
-     *
      * @treatAsPrivate implementation detail
      * @deprecated This is an internal API that is not intended for use and will be removed in the next version
      */
@@ -1751,15 +1734,6 @@
      * Returns true if this scene is quiescent, i.e. it has no activity
      * pending on it such as CSS processing or layout requests.
      *
-     * TODO this is for testing purposes only. It's not clear that
-     * the set of things this checks is exactly right. It doesn't check
-     * for events pending in the event queue for instance. However, it
-     * seems to work reasonably well at present for UI testing.
-     *
-     * TODO this should be replaced with a better interface, say a
-     * package-private interface that can be called from test support
-     * code that has been loaded into javafx.scene.
-     *
      * @return boolean indicating whether the scene is quiescent
      * @treatAsPrivate implementation detail
      * @deprecated This is an internal API that is not intended for use and will be removed in the next version
@@ -1775,9 +1749,6 @@
      * A listener for pulses, used for testing. If non-null, this is called at
      * the very end of ScenePulseListener.pulse().
      *
-     * TODO this is public so it can be written to from test code. Ugly,
-     * but effective. This should be replaced with a cleaner interface.
-     *
      * @treatAsPrivate implementation detail
      * @deprecated This is an internal API that is not intended for use and will be removed in the next version
      */
@@ -2230,7 +2201,6 @@
             }
             int order = touchMap.getOrder(id);
 
-            //TODO: this is workaround for RT-20139, remove when fixed
             if (!nextTouchEvent.impl_isDirect()) {
                 order = touchPointIndex - 1;
             }
@@ -2496,8 +2466,6 @@
          * the Node.onDragSourceRecognized function.
          */
         private boolean processRecognized(Node n, DragEvent de) {
-            //TODO: Should get Mouse Event, for now we have to make up one
-            //      this code is not used right now anyway
             MouseEvent me = MouseEvent.impl_mouseEvent(de.getX(), de.getY(),
                     de.getSceneX(), de.getScreenY(), MouseButton.PRIMARY, 1,
                     false, false, false, false, false, true, false, false, false,
@@ -3108,8 +3076,6 @@
                 if (getCamera() instanceof PerspectiveCamera) {
                     final PickRay pickRay = new PickRay();
                     Scene.this.impl_peer.computePickRay((float)e.getX(), (float)e.getY(), pickRay);
-    //                System.out.println("** 3D: origin = " + pickRay.getOriginNoClone()
-    //                        + ", direction = " + pickRay.getDirectionNoClone());
                     pickedTarget = pickNode(pickRay);
                 }
                 else {
@@ -3123,14 +3089,6 @@
 
             EventTarget target;
             if (pdrInProgress) {
-                // TODO I believe this is bogus. We should still deliver mouse
-                // enter / exit / move events to nodes that are not part of the
-                // press-drag-release event, but only pdr nodes get the mouse
-                // dragged events, and other nodes DO NOT (?) get pressed events...
-                // The use case here is that I press a button and a popup is visible
-                // and while the button is still depressed I "drag" over the item
-                // in the popup I want and release. So in this case I need to get
-                // some events on the items in the popup, just not the drag events.
                 target = pdrEventTarget;
             } else {
                 target = pickedTarget;
@@ -3357,7 +3315,7 @@
      *                                                                             *
      ******************************************************************************/
 
-    class KeyHandler implements InvalidationListener {
+    class KeyHandler {
         private Node focusOwner = null;
         private Node getFocusOwner() { return focusOwner; }
 
@@ -3454,12 +3412,6 @@
                 });
             }
         }
-
-        // TODO: What is the point of extending a listener, if handle() is not overridden?
-        @Override
-        public void invalidated(Observable valueModel) {
-            //nothing to do, implemented because of extending ChangeListener
-        }
     }
     /***************************************************************************
      *                                                                         *
--- a/javafx-ui-common/src/javafx/scene/input/DragEvent.java	Wed Mar 28 06:36:03 2012 -0700
+++ b/javafx-ui-common/src/javafx/scene/input/DragEvent.java	Wed Mar 28 11:51:15 2012 -0700
@@ -730,10 +730,6 @@
             double _screenX, double _screenY, TransferMode _transferMode,
             Dragboard _dragboard, TKDropEvent _tkDropEvent) {
         
-        //TODO: this is not nice. Toolkit always creates DragEvent of type ANY
-        //      and scenegraph then copies it and fixes the type.
-        //      Serious scenegraph/toolkit contract rework is needed
-        //      to get rid of this.
         DragEvent de = new DragEvent(DragEvent.ANY);
 
         de.x = _x;
--- a/javafx-ui-common/src/javafx/scene/input/Dragboard.java	Wed Mar 28 06:36:03 2012 -0700
+++ b/javafx-ui-common/src/javafx/scene/input/Dragboard.java	Wed Mar 28 11:51:15 2012 -0700
@@ -63,18 +63,5 @@
     public static Dragboard impl_create(TKClipboard peer) {
         return new Dragboard(peer);
     }
-
-    // TODO: DragView support
-//    /**
-//     * Visual representation of data being transfered in a drag and drop gesture.
-//     * This will be shown to the side of the mouse cursor as it is moved around
-//     * the screen.
-//     */
-//    public Node dragView;
-//
-//    /**
-//     * Specifies the opacity of the dragView node as the drag occurs. If this
-//     * is not specified, a default opacity of 0.65 will be applied.
-//     */
-//    public float dragViewOpacity = 0.65f;
+    
 }
--- a/javafx-ui-common/src/javafx/scene/shape/Path.java	Wed Mar 28 06:36:03 2012 -0700
+++ b/javafx-ui-common/src/javafx/scene/shape/Path.java	Wed Mar 28 11:51:15 2012 -0700
@@ -189,10 +189,6 @@
     private final ObservableList<PathElement> elements = new TrackableObservableList<PathElement>() {
         @Override
         protected void onChanged(Change<PathElement> c) {
-            //
-            // TODO: Need to keep a list of Path objects in PathElement if we want
-            // to support sharability. See how transforms is handled in Node.
-            //
             List<PathElement> list = c.getList();
             boolean firstElementChanged = false;
             while (c.next()) {
--- a/javafx-ui-common/src/javafx/scene/shape/Rectangle.java	Wed Mar 28 06:36:03 2012 -0700
+++ b/javafx-ui-common/src/javafx/scene/shape/Rectangle.java	Wed Mar 28 11:51:15 2012 -0700
@@ -504,7 +504,6 @@
         }
         if ((getArcWidth() > 0) && (getArcHeight() > 0)
                 && ((tx.getType() & NON_RECTILINEAR_TYPE_MASK) != 0)) {
-            // TODO: Optimize rotated bounds...
             return computeShapeBounds(bounds, tx, impl_configShape());
         }
         double upad;
--- a/javafx-ui-common/src/javafx/scene/shape/Shape.java	Wed Mar 28 06:36:03 2012 -0700
+++ b/javafx-ui-common/src/javafx/scene/shape/Shape.java	Wed Mar 28 11:51:15 2012 -0700
@@ -945,10 +945,8 @@
                 x1 += dx;
                 y1 += dy;
             }
-            // TODO - only pad by upad or dpad, depending on transform
             _dpad += upad;
         } else {
-            // TODO - only pad by upad or dpad, depending on transform
             x0 -= upad;
             y0 -= upad;
             x1 += upad*2;
--- a/javafx-ui-common/src/javafx/scene/text/Text.java	Wed Mar 28 06:36:03 2012 -0700
+++ b/javafx-ui-common/src/javafx/scene/text/Text.java	Wed Mar 28 11:51:15 2012 -0700
@@ -45,11 +45,13 @@
 import javafx.geometry.Bounds;
 import javafx.geometry.Point2D;
 import javafx.geometry.VPos;
+import javafx.scene.Node;
 import javafx.scene.Scene;
 import javafx.scene.paint.Color;
 import javafx.scene.paint.Paint;
 import javafx.scene.shape.PathElement;
 import javafx.scene.shape.Shape;
+import javafx.scene.transform.Transform;
 
 import com.sun.javafx.css.StyleableBooleanProperty;
 import com.sun.javafx.css.StyleableObjectProperty;
@@ -59,6 +61,7 @@
 import com.sun.javafx.css.converters.FontConverter;
 import com.sun.javafx.geom.BaseBounds;
 import com.sun.javafx.geom.RectBounds;
+import com.sun.javafx.geom.transform.Affine3D;
 import com.sun.javafx.geom.transform.BaseTransform;
 import com.sun.javafx.scene.DirtyBits;
 import com.sun.javafx.scene.shape.PathUtils;
@@ -66,7 +69,8 @@
 import com.sun.javafx.sg.PGNode;
 import com.sun.javafx.sg.PGShape;
 import com.sun.javafx.sg.PGText;
-import com.sun.javafx.tk.TextHelper;
+import com.sun.javafx.sg.PGTextHelper;
+import com.sun.javafx.tk.FontLoader;
 import com.sun.javafx.tk.Toolkit;
 import javafx.beans.DefaultProperty;
 import javafx.beans.property.*;
@@ -116,17 +120,38 @@
         return Toolkit.getToolkit().createPGText();
     }
 
-    PGText getPGText() {
+    private PGText getPGText() {
         return (PGText) impl_getPGNode();
     }
 
+    private PGTextHelper textHelper;
+    /* 
+     * The Text node state is synced down to *its* helper on return.
+     * This doesn't mean its synced to the peer! That happens only
+     * during the pulse.
+     */
+    private PGTextHelper getTextHelper() {
+        if (textHelper == null) {
+            Scene.impl_setAllowPGAccess(true);
+            textHelper = getPGText().getTextHelper();
+            Scene.impl_setAllowPGAccess(false);
+        }
+        updatePGTextHelper(textHelper);
+        return textHelper;
+    }
+
+    private static FontLoader fontLoader = null;
     /**
      * Creates an empty instance of Text.
      */
     public Text() {
+        if (fontLoader == null) {
+            fontLoader = Toolkit.getToolkit().getFontLoader();
+        }
         setPickOnBounds(true);
         getDecorationShapes();
-        setBaselineOffset(Toolkit.getToolkit().getFontLoader().getFontMetrics(getFontInternal()).getAscent());
+        setBaselineOffset(
+             fontLoader.getFontMetrics(getFontInternal()).getAscent());
     }
 
     /**
@@ -322,7 +347,8 @@
                 public void invalidated() {
                     impl_markDirty(DirtyBits.TEXT_FONT);
                     impl_geomChanged();
-                    setBaselineOffset(Toolkit.getToolkit().getFontLoader().getFontMetrics(getFontInternal()).getAscent());
+                    setBaselineOffset(fontLoader.getFontMetrics(
+                                          getFontInternal()).getAscent());
                 }
 
                 @Override 
@@ -829,14 +855,14 @@
      * set to {@code -1} to unset selection.
      *
      * @treatAsPrivate implementation detail
-     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
-     */
-    @Deprecated
-    private IntegerProperty impl_selectionEnd;
+	     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
+	     */
+	    @Deprecated
+	    private IntegerProperty impl_selectionEnd;
 
-    /**
-     * @treatAsPrivate implementation detail
-     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
+	    /**
+	     * @treatAsPrivate implementation detail
+	     * @deprecated This is an internal API that is not intended for use and will be removed in the next version
      */
     @Deprecated
     public final void setImpl_selectionEnd(int value) {
@@ -1085,18 +1111,14 @@
         if (getImpl_caretPosition() >= 0) {
             //convert insertion postiion into character index
             int charIndex = getImpl_caretPosition() - ((isImpl_caretBias()) ? 0 : 1);
-            Scene.impl_setAllowPGAccess(true);
             Object nativeShape = getTextHelper().getCaretShape(charIndex, isImpl_caretBias());
-            Scene.impl_setAllowPGAccess(false);
             setImpl_caretShape(Toolkit.getToolkit().convertShapeToFXPath(nativeShape));
         } else {
             setImpl_caretShape(null);
         }
 
         if (getImpl_selectionStart() >= 0 && getImpl_selectionEnd() >= 0) {
-            Scene.impl_setAllowPGAccess(true);
             Object nativeShape = getTextHelper().getSelectionShape();
-            Scene.impl_setAllowPGAccess(false);
             setImpl_selectionShape(Toolkit.getToolkit().convertShapeToFXPath(nativeShape));
         } else {
             setImpl_selectionShape(null);
@@ -1113,14 +1135,6 @@
     public final void impl_displaySoftwareKeyboard(boolean display) {
     }
 
-    private TextHelper textHelper;
-    private TextHelper getTextHelper() {
-        if (textHelper == null) {
-            textHelper = Toolkit.getToolkit().createTextHelper(this);
-        }
-        return textHelper;
-    }
-
     /**
      * The cached layout bounds.
      * This is never null, but is frequently set to be
@@ -1195,7 +1209,7 @@
         {
             return bounds.makeEmpty();
         }
-        return getTextHelper().computeBounds(bounds, tx);
+        return getTextHelper().computeContentBounds(bounds, tx);
     }
 
     /**
@@ -1206,10 +1220,9 @@
     @Override
     protected final boolean impl_computeContains(double localX, double localY) {
         // Need to call the TextHelper to do glyph (geometry) based picking.
-
-        // Perform the expensive glyph (geometry) based picking
-        // See the computeContains function in SGText.java for detail.
-        return getTextHelper().contains((float)localX, (float)localY);
+        // Performs expensive glyph (geometry) based picking
+        // This is currently unimplemented in the peer (just returns true).
+        return getTextHelper().computeContains((float)localX, (float)localY);
     }
 
     /**
@@ -1242,7 +1255,7 @@
 
     /***************************************************************************
      *                                                                         *
-     *                         Stylesheet Handling                             *
+     *                            Stylesheet Handling                          *
      *                                                                         *
      **************************************************************************/
 
@@ -1298,7 +1311,7 @@
 
          };
          
-         private static final StyleableProperty<Text,TextAlignment> TEXT_ALIGNMENT = 
+         private static final StyleableProperty<Text,TextAlignment> TEXT_ALIGNMENT =
                  new StyleableProperty<Text,TextAlignment>("-fx-text-alignment",
                  new EnumConverter<TextAlignment>(TextAlignment.class),
                  TextAlignment.LEFT) {
@@ -1354,7 +1367,7 @@
          private static final List<StyleableProperty> STYLEABLES;
          static {
             final List<StyleableProperty> styleables =
-                    new ArrayList<StyleableProperty>(Shape.impl_CSS_STYLEABLES());
+                new ArrayList<StyleableProperty>(Shape.impl_CSS_STYLEABLES());
             Collections.addAll(styleables,
                 FONT,
                 UNDERLINE,
@@ -1391,45 +1404,175 @@
     }
 
     private void updatePGText() {
+        getTextHelper(); // implicitly syncs Text to Helper.
+        getPGText().updateText();
+    }
+
+    /*
+     * This skips the pivot x/y as that requires knowing the bounds
+     * but we need to sync the transform down to the helper when
+     * getting bounds. And we only need the portion of the transform
+     * that affects text size anyway.
+     */
+    private Affine3D getConcatenatedNodeTransform(Node node, Affine3D dst) {
+        if (node.getScaleX() != 1 || node.getScaleY() != 1 ||
+            node.getRotate() != 0 || node.impl_hasTransforms())
+        {
+            if (node.getRotate() != 0) {
+                dst.rotate(Math.toRadians(node.getRotate()),
+                           node.getRotationAxis().getX(),
+                           node.getRotationAxis().getY(),
+                           node.getRotationAxis().getZ());
+            }
+            if (node.getScaleX() != 1 || node.getScaleY() != 1) {
+                dst.scale(node.getScaleX(), node.getScaleY());
+            }
+            if (node.impl_hasTransforms()) {
+                for (Transform t : node.getTransforms()) {
+                    t.impl_apply(dst);
+                }
+            }
+        }
+        return dst;
+    }
+
+    private BaseTransform getCumulativeTransform() {
+        Affine3D dst = new Affine3D();
+        Node node = this;
+        do {
+            dst = getConcatenatedNodeTransform(node, dst);
+            node = node.getParent();
+        } while (node != null);
+        return dst;
+    }
+
+    private PGShape.Mode getMode() {
+        if (getFill() != null && getStroke() != null) {
+            return PGShape.Mode.STROKE_FILL;
+        } else if (getFill() != null) {
+            return PGShape.Mode.FILL;
+        } else if (getStroke() != null) {
+            return PGShape.Mode.STROKE;
+        } else {
+            return PGShape.Mode.EMPTY;
+        }
+    }
+
+    /* This method can be called outside of the pulse */
+    private void updatePGTextHelper(PGTextHelper helper) {
+
         if (impl_isDirty(DirtyBits.NODE_GEOMETRY)) {
-            getPGText().setLocation((float)getX(), (float)getY());
+            helper.setLocation((float)getX(), (float)getY());
+            impl_clearDirty(DirtyBits.NODE_GEOMETRY);
         }
         if (impl_isDirty(DirtyBits.TEXT_ATTRS)) {
-            PGText peer = getPGText();
-            peer.setTextBoundsType(getBoundsType().ordinal());
-            peer.setTextOrigin(getTextOrigin().ordinal());
-            peer.setWrappingWidth((float)getWrappingWidth());
-            peer.setUnderline(isUnderline());
-            peer.setStrikethrough(isStrikethrough());
-            peer.setTextAlignment(getTextAlignment().ordinal());
-            peer.setFontSmoothingType(getFontSmoothingType().ordinal());
+            helper.setTextBoundsType(getBoundsType().ordinal());
+            helper.setTextOrigin(getTextOrigin().ordinal());
+            helper.setWrappingWidth((float)getWrappingWidth());
+            helper.setUnderline(isUnderline());
+            helper.setStrikethrough(isStrikethrough());
+            helper.setTextAlignment(getTextAlignment().ordinal());
+            helper.setFontSmoothingType(getFontSmoothingType().ordinal());
+            impl_clearDirty(DirtyBits.TEXT_ATTRS);
         }
         if (impl_isDirty(DirtyBits.TEXT_FONT)) {
-            getPGText().setFont(getFontInternal().impl_getNativeFont());
+            helper.setFont(getFontInternal().impl_getNativeFont());
+            impl_clearDirty(DirtyBits.TEXT_FONT);
         }
         if (impl_isDirty(DirtyBits.NODE_CONTENTS)) {
-            getPGText().setText(getTextInternal());
+            helper.setText(getTextInternal());
+            impl_clearDirty(DirtyBits.NODE_CONTENTS);
         }
         if (impl_isDirty(DirtyBits.TEXT_SELECTION)) {
             if (getImpl_selectionStart() >= 0 && getImpl_selectionEnd() >= 0) {
-                getPGText().setLogicalSelection(getImpl_selectionStart(),
-                                                getImpl_selectionEnd());
+                helper.setLogicalSelection(getImpl_selectionStart(),
+                                           getImpl_selectionEnd());
                 // getStroke and getFill can be null
-                Paint strokePaint   = getStroke();
-                Paint fillPaint     = selectionFill == null ? null : selectionFill.get();
+                Paint strokePaint = getStroke();
+                Paint fillPaint =
+                    selectionFill == null ? null : selectionFill.get();
                 Object strokeObj = (strokePaint == null) ? null :
-                                    strokePaint.impl_getPlatformPaint();
+                    strokePaint.impl_getPlatformPaint();
                 Object fillObj = (fillPaint == null) ? null :
-                                    fillPaint.impl_getPlatformPaint();
+                    fillPaint.impl_getPlatformPaint();
 
-                getPGText().setSelectionPaint(strokeObj, fillObj);
+                helper.setSelectionPaint(strokeObj, fillObj);
             } else {
                 // Deselect any PGText, in order to update selected text color
-                getPGText().setLogicalSelection(0, 0);
+                helper.setLogicalSelection(0, 0);
+            }
+            impl_clearDirty(DirtyBits.TEXT_SELECTION);
+        }
+        /* Rendering state like transform, Mode, and stroke also matter
+         * for bounds calculations. Need to pass down this information too.
+         */
+        helper.setCumulativeTransform(getCumulativeTransform());
+        helper.setMode(getMode());
+        if (impl_isDirty(DirtyBits.SHAPE_STROKE) ||
+            impl_isDirty(DirtyBits.SHAPE_STROKEATTRS))
+        {
+            boolean hasStroke = getStroke() != null;
+            helper.setStroke(hasStroke);
+            /* We don't want to do this work unless there's currently
+             * a stroke set. And we also don't want to repeat it unless
+             * something changed. We know something has changed if we
+             * are here because of the dirty bits, so we then have to
+             * check if there's a stroke been set. The case this does
+             * extra work is if the stroke's Paint changes, but nothing else.
+             */
+            if (hasStroke) {
+                List<Double> daList = getStrokeDashArray();
+                int len = daList.size();
+                float[] strokeDashArray = new float[len];
+                for (int i=0; i<len; i++) {
+                    strokeDashArray[i] = daList.get(i).floatValue();
+                }
+                helper.setStrokeParameters(
+                       getPGStrokeType(),
+                       getPGStrokeDashArray(),
+                       (float)getStrokeDashOffset(),
+                       getPGStrokeLineCap(),
+                       getPGStrokeLineJoin(),
+                       Math.max((float)getStrokeMiterLimit(), 1f),
+                       Math.max((float)getStrokeWidth(), 0f));
             }
         }
     }
 
+    private com.sun.javafx.sg.PGShape.StrokeType getPGStrokeType() {
+        switch (getStrokeType()) {
+            case INSIDE: return PGShape.StrokeType.INSIDE;
+            case OUTSIDE: return PGShape.StrokeType.OUTSIDE;
+            default: return PGShape.StrokeType.CENTERED;
+        }
+    }
+
+    private com.sun.javafx.sg.PGShape.StrokeLineCap getPGStrokeLineCap() {
+        switch (getStrokeLineCap()) {
+            case SQUARE: return PGShape.StrokeLineCap.SQUARE;
+            case BUTT:   return PGShape.StrokeLineCap.BUTT;
+            default: return PGShape.StrokeLineCap.ROUND;
+        }
+    }
+
+    private com.sun.javafx.sg.PGShape.StrokeLineJoin getPGStrokeLineJoin() {
+         switch (getStrokeLineJoin()) {
+             case MITER: return PGShape.StrokeLineJoin.MITER;
+             case BEVEL: return PGShape.StrokeLineJoin.BEVEL;
+             default: return PGShape.StrokeLineJoin.ROUND;
+         }
+    }
+
+    private float[] getPGStrokeDashArray() {
+        List<Double> daList = getStrokeDashArray();
+        int len = daList.size();
+        float[] strokeDashArray = new float[len];
+        for (int i=0; i<len; i++) {
+            strokeDashArray[i] = daList.get(i).floatValue();
+        }
+        return strokeDashArray;
+    }
+
     /**
      * @treatAsPrivate implementation detail
      * @deprecated This is an internal API that is not intended for use and will be removed in the next version
--- a/javafx-ui-common/src/javafx/stage/PopupWindow.java	Wed Mar 28 06:36:03 2012 -0700
+++ b/javafx-ui-common/src/javafx/stage/PopupWindow.java	Wed Mar 28 11:51:15 2012 -0700
@@ -217,9 +217,6 @@
     /**
      * Specifies whether Popups should auto hide. If a popup loses focus and
      * autoHide is true, then the popup will be hidden automatically.
-     * TODO How does this function if you want to animate the popup becoming invisible??
-     * For example, if you wanted to scroll up the popup (such as if the popup
-     * is used for a drop down list).
      * @defaultValue false
      */
     private BooleanProperty autoHide =
--- a/javafx-ui-common/src/javafx/stage/Stage.java	Wed Mar 28 06:36:03 2012 -0700
+++ b/javafx-ui-common/src/javafx/stage/Stage.java	Wed Mar 28 11:51:15 2012 -0700
@@ -227,8 +227,6 @@
         super.show();
     }
     
-    // TODO do I also want to expose the model as being a writable model?
-    
     private boolean primary = false;
 
     /**
@@ -242,7 +240,6 @@
         this.primary = primary;
     }
 
-    // TODO: consider making this public
     /**
      * Returns whether this stage is the primary stage.
      * When run as an applet, the primary stage will appear in the broswer
@@ -911,7 +908,6 @@
         }
     }
 
-    // TODO: remove
     /**
      * Closes this {@code Stage}.
      * This call is equivalent to {@code hide()}.
--- a/javafx-ui-common/test/unit/com/sun/javafx/pgstub/StubToolkit.java	Wed Mar 28 06:36:03 2012 -0700
+++ b/javafx-ui-common/test/unit/com/sun/javafx/pgstub/StubToolkit.java	Wed Mar 28 11:51:15 2012 -0700
@@ -102,7 +102,6 @@
 import com.sun.javafx.tk.TKScreenConfigurationListener;
 import com.sun.javafx.tk.TKStage;
 import com.sun.javafx.tk.TKSystemMenu;
-import com.sun.javafx.tk.TextHelper;
 import com.sun.javafx.tk.Toolkit;
 import com.sun.prism.BasicStroke;
 import com.sun.scenario.DelayedRunnable;
@@ -419,11 +418,6 @@
         return new StubText();
     }
 
-    @Override
-    public TextHelper createTextHelper(Text text) {
-        return new StubTextHelper(text);
-    }
-
     /*
      * additional testing functions
      */
--- a/javafx-ui-common/test/unit/javafx/scene/text/TextTest.java	Wed Mar 28 06:36:03 2012 -0700
+++ b/javafx-ui-common/test/unit/javafx/scene/text/TextTest.java	Wed Mar 28 11:51:15 2012 -0700
@@ -82,137 +82,137 @@
     }
 */
 
-    @Test public void testPropertyPropagation_textOrigin() throws Exception {
-        final Text node = new Text();
-        NodeTest.testObjectPropertyPropagation(node, "textOrigin", "textOrigin",
-                VPos.BASELINE, VPos.TOP, new NodeTest.ObjectValueConvertor() {
-                    @Override
-                    public Object toSg(Object pgValue) {
-                        return VPos.values()[((Number)pgValue).intValue()];
-                    }
-                });
-    }
+//     @Test public void testPropertyPropagation_textOrigin() throws Exception {
+//         final Text node = new Text();
+//         NodeTest.testObjectPropertyPropagation(node, "textOrigin", "textOrigin",
+//                 VPos.BASELINE, VPos.TOP, new NodeTest.ObjectValueConvertor() {
+//                     @Override
+//                     public Object toSg(Object pgValue) {
+//                         return VPos.values()[((Number)pgValue).intValue()];
+//                     }
+//                 });
+//     }
     
-    @Test public void testPropertyPropagation_boundsType() throws Exception {
-        final Text node = new Text();
-        NodeTest.testObjectPropertyPropagation(node, "boundsType", "textBoundsType",
-                TextBoundsType.LOGICAL, TextBoundsType.VISUAL, new NodeTest.ObjectValueConvertor() {
-                    @Override
-                    public Object toSg(Object pgValue) {
-                        return TextBoundsType.values()[((Number)pgValue).intValue()];
-                    }
-                });
-    }
+//     @Test public void testPropertyPropagation_boundsType() throws Exception {
+//         final Text node = new Text();
+//         NodeTest.testObjectPropertyPropagation(node, "boundsType", "textBoundsType",
+//                 TextBoundsType.LOGICAL, TextBoundsType.VISUAL, new NodeTest.ObjectValueConvertor() {
+//                     @Override
+//                     public Object toSg(Object pgValue) {
+//                         return TextBoundsType.values()[((Number)pgValue).intValue()];
+//                     }
+//                 });
+//     }
     
-    @Test public void testPropertyPropagation_textAlignment() throws Exception {
-        final Text node = new Text();
-        NodeTest.testObjectPropertyPropagation(node, "textAlignment", "textAlignment", 
-                TextAlignment.LEFT, TextAlignment.CENTER, new NodeTest.ObjectValueConvertor() {
-                    @Override
-                    public Object toSg(Object pgValue) {
-                        return TextAlignment.values()[(((Number)pgValue).intValue())];
-                    }
-                });
-    }
+//     @Test public void testPropertyPropagation_textAlignment() throws Exception {
+//         final Text node = new Text();
+//         NodeTest.testObjectPropertyPropagation(node, "textAlignment", "textAlignment", 
+//                 TextAlignment.LEFT, TextAlignment.CENTER, new NodeTest.ObjectValueConvertor() {
+//                     @Override
+//                     public Object toSg(Object pgValue) {
+//                         return TextAlignment.values()[(((Number)pgValue).intValue())];
+//                     }
+//                 });
+//     }
     
-    @Test public void testPropertyPropagation_visible() throws Exception {
-        final Text node = new Text();
-        NodeTest.testBooleanPropertyPropagation(node, "visible", false, true);
-    }
+//     @Test public void testPropertyPropagation_visible() throws Exception {
+//         final Text node = new Text();
+//         NodeTest.testBooleanPropertyPropagation(node, "visible", false, true);
+//     }
 
-    @Test public void testPropertyPropagation_text() throws Exception {
-        final Text node = new Text();
-        NodeTest.testObjectPropertyPropagation(node, "text", "text", "Hello", "World");
-    }
+//     @Test public void testPropertyPropagation_text() throws Exception {
+//         final Text node = new Text();
+//         NodeTest.testObjectPropertyPropagation(node, "text", "text", "Hello", "World");
+//     }
 
-    @Test public void testPropertyPropagation_strikethrough() throws Exception {
-        final Text node = new Text();
-        NodeTest.testBooleanPropertyPropagation(node, "strikethrough", false, true);
-    }
+//     @Test public void testPropertyPropagation_strikethrough() throws Exception {
+//         final Text node = new Text();
+//         NodeTest.testBooleanPropertyPropagation(node, "strikethrough", false, true);
+//     }
 
-    @Test public void testPropertyPropagation_underline() throws Exception {
-        final Text node = new Text();
-        NodeTest.testBooleanPropertyPropagation(node, "underline", false, true);
-    }
+//     @Test public void testPropertyPropagation_underline() throws Exception {
+//         final Text node = new Text();
+//         NodeTest.testBooleanPropertyPropagation(node, "underline", false, true);
+//     }
 
-    @Test public void testPropertyPropagation_x() throws Exception {
-        final Text node = new Text();
-        NodeTest.testDoublePropertyPropagation(node, "x", 100, 200);
-    }
+//     @Test public void testPropertyPropagation_x() throws Exception {
+//         final Text node = new Text();
+//         NodeTest.testDoublePropertyPropagation(node, "x", 100, 200);
+//     }
 
-    @Test public void testPropertyPropagation_y() throws Exception {
-        final Text node = new Text();
-        NodeTest.testDoublePropertyPropagation(node, "y", 100, 200);
-    }
+//     @Test public void testPropertyPropagation_y() throws Exception {
+//         final Text node = new Text();
+//         NodeTest.testDoublePropertyPropagation(node, "y", 100, 200);
+//     }
 
-    @Test public void testPropertyPropagation_wrappingWidth() throws Exception {
-        final Text node = new Text();
-        NodeTest.testDoublePropertyPropagation(node, "wrappingWidth", 100, 200);
-    }
+//     @Test public void testPropertyPropagation_wrappingWidth() throws Exception {
+//         final Text node = new Text();
+//         NodeTest.testDoublePropertyPropagation(node, "wrappingWidth", 100, 200);
+//     }
 
-    @Test public void testBoundPropertySync_X() throws Exception {
-        NodeTest.assertDoublePropertySynced(
-                new Text(1.0, 2.0, "The Text"),
-                "x", "x", 10.0);
-    }
+//     @Test public void testBoundPropertySync_X() throws Exception {
+//         NodeTest.assertDoublePropertySynced(
+//                 new Text(1.0, 2.0, "The Text"),
+//                 "x", "x", 10.0);
+//     }
 
-    @Test public void testBoundPropertySync_Y() throws Exception {
-        NodeTest.assertDoublePropertySynced(
-                new Text(1.0, 2.0, "The Text"),
-                "y", "y", 20.0);
-    }
+//     @Test public void testBoundPropertySync_Y() throws Exception {
+//         NodeTest.assertDoublePropertySynced(
+//                 new Text(1.0, 2.0, "The Text"),
+//                 "y", "y", 20.0);
+//     }
 
-    @Test public void testBoundPropertySync_Text() throws Exception {
-        NodeTest.assertStringPropertySynced(
-                new Text(1.0, 2.0, "The Text"),
-                "text", "text", "The Changed Text");
-    }
+//     @Test public void testBoundPropertySync_Text() throws Exception {
+//         NodeTest.assertStringPropertySynced(
+//                 new Text(1.0, 2.0, "The Text"),
+//                 "text", "text", "The Changed Text");
+//     }
 
-    // The StubFontLoader is not adequate. SansSerif is the default font
-    // family. But StubFontLoader is hard coded with some knowledge of
-    // Amble so we end up with a null reference for its the PGFont
-    // and it sets null on the PGText node. StubFontLoader needs to be
-    // replaced with the real font loader.
-/*
-    @Test public void testBoundPropertySync_Font() throws Exception {
-        List<String> fontNames = Font.getFontNames();
-        String fontName = fontNames.get(fontNames.size() - 1);
-        NodeTest.assertObjectPropertySynced(
-                new Text(1.0, 2.0, "The Text"),
-                "font", "font", new Font(fontName, 22));
-    }
-*/
+//     // The StubFontLoader is not adequate. SansSerif is the default font
+//     // family. But StubFontLoader is hard coded with some knowledge of
+//     // Amble so we end up with a null reference for its the PGFont
+//     // and it sets null on the PGText node. StubFontLoader needs to be
+//     // replaced with the real font loader.
+// /*
+//     @Test public void testBoundPropertySync_Font() throws Exception {
+//         List<String> fontNames = Font.getFontNames();
+//         String fontName = fontNames.get(fontNames.size() - 1);
+//         NodeTest.assertObjectPropertySynced(
+//                 new Text(1.0, 2.0, "The Text"),
+//                 "font", "font", new Font(fontName, 22));
+//     }
+// */
 
-    @Test public void testBoundPropertySync_BoundsType() throws Exception {
-        NodeTest.assertObjectPropertySynced(
-                new Text(1.0, 2.0, "The Text"),
-                "boundsType", "textBoundsType", TextBoundsType.VISUAL);
-    }
+//     @Test public void testBoundPropertySync_BoundsType() throws Exception {
+//         NodeTest.assertObjectPropertySynced(
+//                 new Text(1.0, 2.0, "The Text"),
+//                 "boundsType", "textBoundsType", TextBoundsType.VISUAL);
+//     }
 
     
-    @Test public void testBoundPropertySync_WrappingWidth() throws Exception {
-        NodeTest.assertDoublePropertySynced(
-                new Text(1.0, 2.0, "The Text"),
-                "wrappingWidth", "wrappingWidth", 50);
-    }
+//     @Test public void testBoundPropertySync_WrappingWidth() throws Exception {
+//         NodeTest.assertDoublePropertySynced(
+//                 new Text(1.0, 2.0, "The Text"),
+//                 "wrappingWidth", "wrappingWidth", 50);
+//     }
     
 
-    @Test public void testBoundPropertySync_Underline() throws Exception {
-        NodeTest.assertBooleanPropertySynced(
-                new Text(1.0, 2.0, "The Text"),
-                "underline", "underline", true);
-    }
+//     @Test public void testBoundPropertySync_Underline() throws Exception {
+//         NodeTest.assertBooleanPropertySynced(
+//                 new Text(1.0, 2.0, "The Text"),
+//                 "underline", "underline", true);
+//     }
 
-    @Test public void testBoundPropertySync_Strikethrough() throws Exception {
-        NodeTest.assertBooleanPropertySynced(
-                new Text(1.0, 2.0, "The Text"),
-                "strikethrough", "strikethrough", true);
-    }
+//     @Test public void testBoundPropertySync_Strikethrough() throws Exception {
+//         NodeTest.assertBooleanPropertySynced(
+//                 new Text(1.0, 2.0, "The Text"),
+//                 "strikethrough", "strikethrough", true);
+//     }
 
-    @Test public void testBoundPropertySync_TextAlignment() throws Exception {
-        NodeTest.assertObjectPropertySynced(
-                new Text(1.0, 2.0, "The Text"),
-                "textAlignment", "textAlignment", TextAlignment.RIGHT);
-    }
+//     @Test public void testBoundPropertySync_TextAlignment() throws Exception {
+//         NodeTest.assertObjectPropertySynced(
+//                 new Text(1.0, 2.0, "The Text"),
+//                 "textAlignment", "textAlignment", TextAlignment.RIGHT);
+//     }
 
 }
--- a/test-stub-toolkit/src/com/sun/javafx/pgstub/StubText.java	Wed Mar 28 06:36:03 2012 -0700
+++ b/test-stub-toolkit/src/com/sun/javafx/pgstub/StubText.java	Wed Mar 28 11:51:15 2012 -0700
@@ -24,115 +24,19 @@
  */
 package com.sun.javafx.pgstub;
 
-import javafx.scene.text.Font;
-
-import com.sun.javafx.geom.RectBounds;
-import com.sun.javafx.scene.text.HitInfo;
 import com.sun.javafx.sg.PGText;
+import com.sun.javafx.sg.PGTextHelper;
 
 public class StubText extends StubShape implements PGText {
-    // for tests
-    private float x;
-    private float y;
-    private float wrappingWidth;
-    private String text;
-    private boolean strikethrough;
-    private boolean underline;
-    private Object font;
-    private int textBoundsType;
-    private int textOrigin;
-    private int textAlignment;
-    private int fontSmoothingType;
 
-    public RectBounds computeLayoutBounds(RectBounds bounds) {
-        // We assume that the font point size == pixel height,
-        // and completely square glyphs, mono-spaced.
-        if (text == null) return bounds.makeEmpty();
-
-        final double fontSize = (font == null ? 0 : ((Font)font).getSize());
-        final String[] lines = text.split("\n");
-        double width = 0.0;
-        double height = fontSize * lines.length;
-        for (String line : lines) {
-            width = Math.max(width, fontSize * line.length());
+    StubTextHelper helper = null;
+    public PGTextHelper getTextHelper() {
+        if (helper == null) {
+            helper = new StubTextHelper();
         }
-
-        return (RectBounds) bounds.deriveWithNewBounds(0, 0, 0, (float)width, (float)height, 0);
+        return helper;
     }
 
-    public void setText(String text) { this.text = text;}
-    public String getText() {return text;}
-
-    public void setLocation(float x, float y) { this.x = x; this.y = y;}
-    public float getX() {return x;}
-    public float getY() {return y;}
-
-    public void setFont(Object f) { font = f; }
-    public Object getFont() { return font; }
-    
-    public void setTextBoundsType(int textBoundsType) {
-        this.textBoundsType = textBoundsType;
+    public void updateText() {
     }
-    public int getTextBoundsType() { return textBoundsType; }
-    
-    public void setTextOrigin(int textOrigin) { this.textOrigin = textOrigin; }
-    public int getTextOrigin() { return textOrigin; }
-    
-    public void setWrappingWidth(float width) { this.wrappingWidth = width;}
-    public float getWrappingWidth() {return wrappingWidth;}
-
-    public void setUnderline(boolean underline) { this.underline = underline;}
-    public boolean isUnderline() { return underline;}
-    
-    public void setStrikethrough(boolean strikethrough) { this.strikethrough = strikethrough;}
-    public boolean isStrikethrough() {return strikethrough;}
-
-    public void setTextAlignment(int alignment) { textAlignment = alignment; }
-    public int getTextAlignment() { return textAlignment; }
-    
-    public int getFontSmoothingType() { return fontSmoothingType; }
-    public void setFontSmoothingType(int fontSmoothing) { 
-        fontSmoothingType = fontSmoothing;
-    }
-
-    public void setInputMethodText(int start, Object text) { }
-
-    // somewhat questionable -- do these remain in PGText??
-    public void setLogicalSelection(int start, int end) { }
-    public void setSelectionPaint(Object strokePaint, Object fillPaint) { }
-    // given the x, y point, give the insertion index into the string
-    public Object getHitInfo(float x, float y) {
-        // TODO this probably needs to be entirely rewritten...
-        if (text == null) {
-            final HitInfo hit = new HitInfo();
-            hit.setCharIndex(0);
-            hit.setLeading(true);
-            return hit;
-        }
-
-        final double fontSize = (font == null ? 0 : ((Font)font).getSize());
-        final String[] lines = text.split("\n");
-        int lineIndex = Math.min(lines.length - 1, (int) (y / fontSize));
-        if (lineIndex >= lines.length) {
-            throw new IllegalStateException("Asked for hit info out of y range: x=" + x + "y=" +
-                    + y + "text='" + text + "', lineIndex=" + lineIndex + ", numLines=" + lines.length +
-                    ", fontSize=" + fontSize);
-        }
-        int offset = 0;
-        for (int i=0; i<lineIndex; i++) {
-            offset += lines[i].length() + 1; // add in the \n
-        }
-
-        int charPos = (int) (x / lines[lineIndex].length());
-        if (charPos + offset > text.length()) {
-            throw new IllegalStateException("Asked for hit info out of x range");
-        }
-
-        final HitInfo hit = new HitInfo();
-        hit.setCharIndex(offset + charPos);
-        return hit;
-    }
-    public Object getCaretShape(int charIndex, boolean isLeading) { return null; }
-    public Object getSelectionShape() { return null; }
-    public Object getRangeShape(int start, int end) { return null; }
 }
--- a/test-stub-toolkit/src/com/sun/javafx/pgstub/StubTextHelper.java	Wed Mar 28 06:36:03 2012 -0700
+++ b/test-stub-toolkit/src/com/sun/javafx/pgstub/StubTextHelper.java	Wed Mar 28 11:51:15 2012 -0700
@@ -22,84 +22,151 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-/*
- * StubTextHelper.fx
- */
-
 package com.sun.javafx.pgstub;
 
-import javafx.scene.Scene;
-import javafx.scene.text.Text;
+import javafx.scene.text.Font;
 
 import com.sun.javafx.geom.BaseBounds;
-import com.sun.javafx.geom.RectBounds;
 import com.sun.javafx.geom.transform.BaseTransform;
-import com.sun.javafx.tk.TextHelper;
+import com.sun.javafx.scene.text.HitInfo;
+import com.sun.javafx.sg.PGTextHelper;
+import com.sun.javafx.sg.PGShape.Mode;
+import com.sun.javafx.sg.PGShape.StrokeLineCap;
+import com.sun.javafx.sg.PGShape.StrokeLineJoin;
+import com.sun.javafx.sg.PGShape.StrokeType;
 
-/**
- * @author Jan
- */
-public class StubTextHelper extends TextHelper {
+public class StubTextHelper implements PGTextHelper {
+    // for tests
+    private float x;
+    private float y;
+    private float wrappingWidth;
+    private String text;
+    private boolean strikethrough;
+    private boolean underline;
+    private Object font;
+    private int textBoundsType;
+    private int textOrigin;
+    private int textAlignment;
+    private int fontSmoothingType;
 
-    private Text text;
-    public StubTextHelper(Text text) {
-        this.text = text;
+    public void setText(String text) { this.text = text;}
+    public String getText() {return text;}
+
+    public void setLocation(float x, float y) { this.x = x; this.y = y;}
+    public float getX() {return x;}
+    public float getY() {return y;}
+
+    public void setFont(Object f) { font = f; }
+    public Object getFont() { return font; }
+    
+    public void setTextBoundsType(int textBoundsType) {
+        this.textBoundsType = textBoundsType;
+    }
+    public int getTextBoundsType() { return textBoundsType; }
+    
+    public void setTextOrigin(int textOrigin) { this.textOrigin = textOrigin; }
+    public int getTextOrigin() { return textOrigin; }
+    
+    public void setWrappingWidth(float width) { this.wrappingWidth = width;}
+    public float getWrappingWidth() {return wrappingWidth;}
+
+    public void setUnderline(boolean underline) { this.underline = underline;}
+    public boolean isUnderline() { return underline;}
+    
+    public void setStrikethrough(boolean strikethrough) {
+        this.strikethrough = strikethrough;}
+    public boolean isStrikethrough() {return strikethrough;}
+
+    public void setTextAlignment(int alignment) { textAlignment = alignment; }
+    public int getTextAlignment() { return textAlignment; }
+    
+    public int getFontSmoothingType() { return fontSmoothingType; }
+    public void setFontSmoothingType(int fontSmoothing) { 
+        fontSmoothingType = fontSmoothing;
     }
 
-    @Override
-    public BaseBounds computeBounds(BaseBounds bounds, BaseTransform tx) {
-        Scene.impl_setAllowPGAccess(true);
-        StubText ng = (StubText) text.impl_getPGNode();
-        text.impl_syncPGNodeDirect();
-        Scene.impl_setAllowPGAccess(false);
-        return tx.transform(computeLayoutBounds(bounds), new RectBounds());
+    public void setLogicalSelection(int start, int end) { }
+    public void setSelectionPaint(Object strokePaint, Object fillPaint) { }
+    // given the x, y point, give the insertion index into the string
+    public Object getHitInfo(float x, float y) {
+        // TODO this probably needs to be entirely rewritten...
+        if (text == null) {
+            final HitInfo hit = new HitInfo();
+            hit.setCharIndex(0);
+            hit.setLeading(true);
+            return hit;
+        }
+
+        final double fontSize = (font == null ? 0 : ((Font)font).getSize());
+        final String[] lines = text.split("\n");
+        int lineIndex = Math.min(lines.length - 1, (int) (y / fontSize));
+        if (lineIndex >= lines.length) {
+            throw new IllegalStateException("Asked for hit info out of y range: x=" + x + "y=" +
+                    + y + "text='" + text + "', lineIndex=" + lineIndex + ", numLines=" + lines.length +
+                    ", fontSize=" + fontSize);
+        }
+        int offset = 0;
+        for (int i=0; i<lineIndex; i++) {
+            offset += lines[i].length() + 1; // add in the \n
+        }
+
+        int charPos = (int) (x / lines[lineIndex].length());
+        if (charPos + offset > text.length()) {
+            throw new IllegalStateException("Asked for hit info out of x range");
+        }
+
+        final HitInfo hit = new HitInfo();
+        hit.setCharIndex(offset + charPos);
+        return hit;
     }
 
-    @Override
     public BaseBounds computeLayoutBounds(BaseBounds bounds) {
-        Scene.impl_setAllowPGAccess(true);
-        StubText ng = (StubText) text.impl_getPGNode();
-        text.impl_syncPGNodeDirect();
-        Scene.impl_setAllowPGAccess(false);
-        return ng.computeLayoutBounds((RectBounds)bounds);
+        // We assume that the font point size == pixel height,
+        // and completely square glyphs, mono-spaced.
+        if (text == null) return bounds.makeEmpty();
+
+        final double fontSize = (font == null ? 0 : ((Font)font).getSize());
+        final String[] lines = text.split("\n");
+        double width = 0.0;
+        double height = fontSize * lines.length;
+        for (String line : lines) {
+            width = Math.max(width, fontSize * line.length());
+        }
+
+        return bounds.deriveWithNewBounds(0, 0, 0,
+                                          (float)width, (float)height, 0);
     }
 
-    @Override
-    public Object getCaretShape(int charIndex, boolean isLeading) {
-        return null;
+    public BaseBounds computeContentBounds(BaseBounds bds, BaseTransform tx) {
+        return computeLayoutBounds(bds);     
     }
 
-    @Override
-    public Object getSelectionShape() {
-        return null;
+    public Object getCaretShape(int charIndex, boolean isLeading) {
+        return null; }
+    public Object getSelectionShape() { return null; }
+    public Object getRangeShape(int start, int end) { return null; }
+    public Object getUnderlineShape(int start, int end) { return null; }
+
+    public boolean computeContains(float localX, float localY) {
+        return true;
     }
 
-    @Override
-    public Object getRangeShape(int start, int end) {
-        return null;
+    public Object getShape() {
+        return new Object();
     }
 
-    @Override
-    public Object getUnderlineShape(int start, int end) {
-        return null;
-    }
-
-    @Override
-    public Object getShape() {
-        return null;
-    }
-
-    @Override
-    public Object getHitInfo(float localX, float localY) {
-        Scene.impl_setAllowPGAccess(true);
-        StubText ng = (StubText) text.impl_getPGNode();
-        text.impl_syncPGNodeDirect();
-        Scene.impl_setAllowPGAccess(false);
-        return ng.getHitInfo(localX, localY);
-    }
-
-    @Override
-    public boolean contains(float localX, float localY) {
-        return false;
+    // Rendering state stuff ..
+    
+    public void setCumulativeTransform(BaseTransform tx) { return; }
+    public void setMode(Mode mode) { return; }
+    public void setStroke(boolean doStroke) { return; }
+    public void setStrokeParameters(StrokeType strokeType,
+                                    float[] strokeDashArray,
+                                    float strokeDashOffset,
+                                    StrokeLineCap lineCap,
+                                    StrokeLineJoin lineJoin,
+                                    float strokeMiterLimit,
+                                    float strokeWidth) {
+        return;
     }
 }
--- a/test-stub-toolkit/src/com/sun/javafx/pgstub/StubToolkit.java	Wed Mar 28 06:36:03 2012 -0700
+++ b/test-stub-toolkit/src/com/sun/javafx/pgstub/StubToolkit.java	Wed Mar 28 11:51:15 2012 -0700
@@ -102,7 +102,6 @@
 import com.sun.javafx.tk.TKScreenConfigurationListener;
 import com.sun.javafx.tk.TKStage;
 import com.sun.javafx.tk.TKSystemMenu;
-import com.sun.javafx.tk.TextHelper;
 import com.sun.javafx.tk.Toolkit;
 import com.sun.prism.BasicStroke;
 import com.sun.scenario.DelayedRunnable;
@@ -421,11 +420,6 @@
         return new StubText();
     }
 
-    @Override
-    public TextHelper createTextHelper(Text text) {
-        return new StubTextHelper(text);
-    }
-
     /*
      * additional testing functions
      */