8156217: Selected text is shifted on HiDPI display
authoralexsch
Thu, 20 Oct 2016 12:18:15 +0300
changeset 41807 f9eb6cb54fed
parent 41806 91176d55df60
child 41808 1b2343088086
child 41892 2766292cc7de
8156217: Selected text is shifted on HiDPI display Reviewed-by: prr, serb
jdk/src/java.desktop/share/classes/javax/swing/plaf/TextUI.java
jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java
jdk/src/java.desktop/share/classes/javax/swing/plaf/multi/MultiTextUI.java
jdk/src/java.desktop/share/classes/javax/swing/text/GlyphPainter1.java
jdk/src/java.desktop/share/classes/javax/swing/text/GlyphPainter2.java
jdk/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java
jdk/src/java.desktop/share/classes/javax/swing/text/ParagraphView.java
jdk/src/java.desktop/share/classes/javax/swing/text/PasswordView.java
jdk/src/java.desktop/share/classes/javax/swing/text/PlainView.java
jdk/src/java.desktop/share/classes/javax/swing/text/Utilities.java
jdk/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java
jdk/src/java.desktop/share/classes/sun/swing/SwingUtilities2.java
jdk/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java
jdk/test/javax/swing/text/Caret/8163124/CaretFloatingPointAPITest.java
jdk/test/javax/swing/text/JTextComponent/8156217/TextSelectionTest.java
jdk/test/javax/swing/text/View/8156217/FPMethodCalledTest.java
--- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/TextUI.java	Wed Oct 19 08:06:10 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/TextUI.java	Thu Oct 20 12:18:15 2016 +0300
@@ -46,7 +46,11 @@
      * @return the coordinates as a {@code Rectangle}
      * @exception BadLocationException  if the given position does not
      *   represent a valid location in the associated document
+     *
+     * @deprecated replaced by
+     *     {@link #modelToView2D(JTextComponent, int, Position.Bias)}
      */
+    @Deprecated(since = "9")
     public abstract Rectangle modelToView(JTextComponent t, int pos) throws BadLocationException;
 
     /**
@@ -59,7 +63,11 @@
      * @return the coordinates as a {@code Rectangle}
      * @exception BadLocationException  if the given position does not
      *   represent a valid location in the associated document
+     *
+     * @deprecated replaced by
+     *     {@link #modelToView2D(JTextComponent, int, Position.Bias)}
      */
+    @Deprecated(since = "9")
     public abstract Rectangle modelToView(JTextComponent t, int pos, Position.Bias bias) throws BadLocationException;
 
     /**
@@ -92,7 +100,11 @@
      *   should be in the same coordinate system as the mouse
      *   events.
      * @return the offset from the start of the document >= 0
+     *
+     * @deprecated replaced by
+     *     {@link #viewToModel2D(JTextComponent, Point2D, Position.Bias[])}
      */
+    @Deprecated(since = "9")
     public abstract int viewToModel(JTextComponent t, Point pt);
 
     /**
@@ -110,7 +122,11 @@
      *
      * @return the location within the model that best represents the
      *         given point in the view >= 0
+     *
+     * @deprecated replaced by
+     *     {@link #viewToModel2D(JTextComponent, Point2D, Position.Bias[])}
      */
+    @Deprecated(since = "9")
     public abstract int viewToModel(JTextComponent t, Point pt,
                                     Position.Bias[] biasReturn);
 
@@ -222,7 +238,11 @@
      * @return a {@code String} containing the tooltip
      * @see javax.swing.text.JTextComponent#getToolTipText
      * @since 1.4
+     *
+     * @deprecated replaced by
+     *     {@link #getToolTipText2D(JTextComponent, Point2D)}
      */
+    @Deprecated(since = "9")
     public String getToolTipText(JTextComponent t, Point pt) {
         return null;
     }
--- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java	Wed Oct 19 08:06:10 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java	Thu Oct 20 12:18:15 2016 +0300
@@ -28,6 +28,8 @@
 import java.awt.*;
 import java.awt.event.*;
 import java.awt.datatransfer.*;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
 import java.awt.im.InputContext;
 import java.beans.*;
 import java.io.*;
@@ -1047,7 +1049,12 @@
      * @exception BadLocationException  if the given position does not
      *   represent a valid location in the associated document
      * @see TextUI#modelToView
+     *
+     * @deprecated replaced by
+     *     {@link #modelToView2D(JTextComponent, int, Position.Bias)}
      */
+    @Deprecated(since = "9")
+    @Override
     public Rectangle modelToView(JTextComponent tc, int pos) throws BadLocationException {
         return modelToView(tc, pos, Position.Bias.Forward);
     }
@@ -1064,8 +1071,30 @@
      * @exception BadLocationException  if the given position does not
      *   represent a valid location in the associated document
      * @see TextUI#modelToView
+     *
+     * @deprecated replaced by
+     *     {@link #modelToView2D(JTextComponent, int, Position.Bias)}
      */
-    public Rectangle modelToView(JTextComponent tc, int pos, Position.Bias bias) throws BadLocationException {
+    @Deprecated(since = "9")
+    @Override
+    public Rectangle modelToView(JTextComponent tc, int pos, Position.Bias bias)
+            throws BadLocationException
+    {
+        return (Rectangle) modelToView(tc, pos, bias, false);
+    }
+
+    @Override
+    public Rectangle2D modelToView2D(JTextComponent tc, int pos,
+                                     Position.Bias bias)
+            throws BadLocationException
+    {
+        return modelToView(tc, pos, bias, true);
+    }
+
+    private Rectangle2D modelToView(JTextComponent tc, int pos,
+                                    Position.Bias bias, boolean useFPAPI)
+            throws BadLocationException
+    {
         Document doc = editor.getDocument();
         if (doc instanceof AbstractDocument) {
             ((AbstractDocument)doc).readLock();
@@ -1076,7 +1105,7 @@
                 rootView.setSize(alloc.width, alloc.height);
                 Shape s = rootView.modelToView(pos, alloc, bias);
                 if (s != null) {
-                  return s.getBounds();
+                    return useFPAPI ? s.getBounds2D() : s.getBounds();
                 }
             }
         } finally {
@@ -1099,7 +1128,12 @@
      * @return the offset from the start of the document >= 0,
      *   -1 if not painted
      * @see TextUI#viewToModel
+     *
+     * @deprecated replaced by
+     *     {@link #viewToModel2D(JTextComponent, Point2D, Position.Bias[])}
      */
+    @Deprecated(since = "9")
+    @Override
     public int viewToModel(JTextComponent tc, Point pt) {
         return viewToModel(tc, pt, discardBias);
     }
@@ -1116,9 +1150,25 @@
      * @return the offset from the start of the document >= 0,
      *   -1 if the component doesn't yet have a positive size.
      * @see TextUI#viewToModel
+     *
+     * @deprecated replaced by
+     *     {@link #viewToModel2D(JTextComponent, Point2D, Position.Bias[])}
      */
+    @Deprecated(since = "9")
+    @Override
     public int viewToModel(JTextComponent tc, Point pt,
                            Position.Bias[] biasReturn) {
+        return viewToModel(tc, pt.x, pt.y, biasReturn);
+    }
+
+    @Override
+    public int viewToModel2D(JTextComponent tc, Point2D pt,
+                             Position.Bias[] biasReturn) {
+        return viewToModel(tc, (float) pt.getX(), (float) pt.getY(), biasReturn);
+    }
+
+    private int viewToModel(JTextComponent tc, float x, float y,
+                            Position.Bias[] biasReturn) {
         int offs = -1;
         Document doc = editor.getDocument();
         if (doc instanceof AbstractDocument) {
@@ -1128,7 +1178,7 @@
             Rectangle alloc = getVisibleEditorRect();
             if (alloc != null) {
                 rootView.setSize(alloc.width, alloc.height);
-                offs = rootView.viewToModel(pt.x, pt.y, alloc, biasReturn);
+                offs = rootView.viewToModel(x, y, alloc, biasReturn);
             }
         } finally {
             if (doc instanceof AbstractDocument) {
--- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/multi/MultiTextUI.java	Wed Oct 19 08:06:10 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/multi/MultiTextUI.java	Thu Oct 20 12:18:15 2016 +0300
@@ -38,6 +38,8 @@
 import javax.swing.JComponent;
 import java.awt.Graphics;
 import java.awt.Dimension;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
 import javax.accessibility.Accessible;
 
 /**
@@ -97,7 +99,11 @@
      *
      * @return the value obtained from the first UI, which is
      * the UI obtained from the default <code>LookAndFeel</code>
+     *
+     * @deprecated replaced by
+     *     {@link #modelToView2D(JTextComponent, int, Position.Bias)}
      */
+    @Deprecated(since = "9")
     public Rectangle modelToView(JTextComponent a, int b)
             throws BadLocationException {
         Rectangle returnValue =
@@ -113,7 +119,12 @@
      *
      * @return the value obtained from the first UI, which is
      * the UI obtained from the default <code>LookAndFeel</code>
+     *
+     * @deprecated replaced by
+     *     {@link #modelToView2D(JTextComponent, int, Position.Bias)}
      */
+    @Deprecated(since = "9")
+    @Override
     public Rectangle modelToView(JTextComponent a, int b, Position.Bias c)
             throws BadLocationException {
         Rectangle returnValue =
@@ -124,12 +135,24 @@
         return returnValue;
     }
 
+    @Override
+    public Rectangle2D modelToView2D(JTextComponent a, int b, Position.Bias c) throws BadLocationException {
+        Rectangle2D returnValue =
+            ((TextUI) (uis.elementAt(0))).modelToView2D(a,b,c);
+        for (int i = 1; i < uis.size(); i++) {
+            ((TextUI) (uis.elementAt(i))).modelToView2D(a,b,c);
+        }
+        return returnValue;
+    }
+
     /**
      * Invokes the <code>viewToModel</code> method on each UI handled by this object.
      *
      * @return the value obtained from the first UI, which is
      * the UI obtained from the default <code>LookAndFeel</code>
      */
+    @Deprecated(since = "9")
+    @Override
     public int viewToModel(JTextComponent a, Point b) {
         int returnValue =
             ((TextUI) (uis.elementAt(0))).viewToModel(a,b);
@@ -145,6 +168,8 @@
      * @return the value obtained from the first UI, which is
      * the UI obtained from the default <code>LookAndFeel</code>
      */
+    @Deprecated(since = "9")
+    @Override
     public int viewToModel(JTextComponent a, Point b, Position.Bias[] c) {
         int returnValue =
             ((TextUI) (uis.elementAt(0))).viewToModel(a,b,c);
@@ -154,6 +179,16 @@
         return returnValue;
     }
 
+    @Override
+    public int viewToModel2D(JTextComponent a, Point2D b, Position.Bias[] c) {
+        int returnValue =
+            ((TextUI) (uis.elementAt(0))).viewToModel2D(a,b,c);
+        for (int i = 1; i < uis.size(); i++) {
+            ((TextUI) (uis.elementAt(i))).viewToModel2D(a,b,c);
+        }
+        return returnValue;
+    }
+
     /**
      * Invokes the <code>getNextVisualPositionFrom</code> method on each UI handled by this object.
      *
--- a/jdk/src/java.desktop/share/classes/javax/swing/text/GlyphPainter1.java	Wed Oct 19 08:06:10 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/text/GlyphPainter1.java	Thu Oct 20 12:18:15 2016 +0300
@@ -98,26 +98,27 @@
         Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a : a.getBounds();
 
         // determine the x coordinate to render the glyphs
-        int x = alloc.x;
+        float x = alloc.x;
         int p = v.getStartOffset();
         int[] justificationData = getJustificationData(v);
         if (p != p0) {
             text = v.getText(p, p0);
-            int width = Utilities.getTabbedTextWidth(v, text, metrics, x, expander, p,
-                                                     justificationData);
+            float width = Utilities.getTabbedTextWidth(v, text, metrics, x,
+                                                       expander, p,
+                                                       justificationData);
             x += width;
             SegmentCache.releaseSharedSegment(text);
         }
 
         // determine the y coordinate to render the glyphs
-        int y = alloc.y + metrics.getHeight() - metrics.getDescent();
+        float y = alloc.y + metrics.getHeight() - metrics.getDescent();
 
         // render the glyphs
         text = v.getText(p0, p1);
         g.setFont(metrics.getFont());
 
         Utilities.drawTabbedText(v, text, x, y, g, expander,p0,
-                                 justificationData);
+                                 justificationData, true);
         SegmentCache.releaseSharedSegment(text);
     }
 
@@ -210,9 +211,9 @@
         TabExpander expander = v.getTabExpander();
         Segment s = v.getText(p0, v.getEndOffset());
         int[] justificationData = getJustificationData(v);
-        int index = Utilities.getTabbedTextOffset(v, s, metrics, (int)x, (int)(x+len),
+        int index = Utilities.getTabbedTextOffset(v, s, metrics, x, (x+len),
                                                   expander, p0, false,
-                                                  justificationData);
+                                                  justificationData, true);
         SegmentCache.releaseSharedSegment(s);
         int p1 = p0 + index;
         return p1;
--- a/jdk/src/java.desktop/share/classes/javax/swing/text/GlyphPainter2.java	Wed Oct 19 08:06:10 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/text/GlyphPainter2.java	Thu Oct 20 12:18:15 2016 +0300
@@ -145,8 +145,9 @@
 
         // vertical at the baseline, should use slope and check if glyphs
         // are being rendered vertically.
-        alloc.setRect(alloc.getX() + locs[0], alloc.getY(), 1, alloc.getHeight());
-        return alloc;
+        Rectangle2D rect = new Rectangle2D.Float();
+        rect.setRect(alloc.getX() + locs[0], alloc.getY(), 1, alloc.getHeight());
+        return rect;
     }
 
     /**
--- a/jdk/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java	Wed Oct 19 08:06:10 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java	Thu Oct 20 12:18:15 2016 +0300
@@ -49,6 +49,8 @@
 import java.awt.im.InputMethodRequests;
 import java.awt.font.TextHitInfo;
 import java.awt.font.TextAttribute;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
 
 import java.awt.print.Printable;
 import java.awt.print.PrinterException;
@@ -1370,12 +1372,38 @@
      * @exception BadLocationException if the given position does not
      *   represent a valid location in the associated document
      * @see TextUI#modelToView
+     *
+     * @deprecated replaced by
+     *     {@link #modelToView2D(int)}
      */
+    @Deprecated(since = "9")
     public Rectangle modelToView(int pos) throws BadLocationException {
         return getUI().modelToView(this, pos);
     }
 
     /**
+     * Converts the given location in the model to a place in
+     * the view coordinate system.
+     * The component must have a positive size for
+     * this translation to be computed (i.e. layout cannot
+     * be computed until the component has been sized).  The
+     * component does not have to be visible or painted.
+     *
+     * @param pos the position {@code >= 0}
+     * @return the coordinates as a rectangle, with (r.x, r.y) as the location
+     *   in the coordinate system, or null if the component does
+     *   not yet have a positive size.
+     * @exception BadLocationException if the given position does not
+     *   represent a valid location in the associated document
+     * @see TextUI#modelToView2D
+     *
+     * @since 9
+     */
+    public Rectangle2D modelToView2D(int pos) throws BadLocationException {
+        return getUI().modelToView2D(this, pos, Position.Bias.Forward);
+    }
+
+    /**
      * Converts the given place in the view coordinate system
      * to the nearest representative location in the model.
      * The component must have a positive size for
@@ -1388,12 +1416,36 @@
      *   or -1 if the component does not yet have a positive
      *   size.
      * @see TextUI#viewToModel
+     *
+     * @deprecated replaced by
+     *     {@link #viewToModel2D(Point2D)}
      */
+    @Deprecated(since = "9")
     public int viewToModel(Point pt) {
         return getUI().viewToModel(this, pt);
     }
 
     /**
+     * Converts the given place in the view coordinate system
+     * to the nearest representative location in the model.
+     * The component must have a positive size for
+     * this translation to be computed (i.e. layout cannot
+     * be computed until the component has been sized).  The
+     * component does not have to be visible or painted.
+     *
+     * @param pt the location in the view to translate
+     * @return the offset {@code >= 0} from the start of the document,
+     *   or {@code -1} if the component does not yet have a positive
+     *   size.
+     * @see TextUI#viewToModel2D
+     *
+     * @since 9
+     */
+    public int viewToModel2D(Point2D pt) {
+        return getUI().viewToModel2D(this, pt, new Position.Bias[1]);
+    }
+
+    /**
      * Transfers the currently selected range in the associated
      * text model to the system clipboard, removing the contents
      * from the model.  The current selection is reset.  Does nothing
--- a/jdk/src/java.desktop/share/classes/javax/swing/text/ParagraphView.java	Wed Oct 19 08:06:10 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/text/ParagraphView.java	Thu Oct 20 12:18:15 2016 +0300
@@ -27,6 +27,7 @@
 import java.util.Arrays;
 import java.awt.*;
 import java.awt.font.TextAttribute;
+import java.awt.geom.Rectangle2D;
 import javax.swing.event.*;
 import javax.swing.SizeRequirements;
 
@@ -888,10 +889,9 @@
             int height = r.height;
             int y = r.y;
             Shape loc = super.modelToView(pos, a, b);
-            r = loc.getBounds();
-            r.height = height;
-            r.y = y;
-            return r;
+            Rectangle2D bounds = loc.getBounds2D();
+            bounds.setRect(bounds.getX(), y, bounds.getWidth(), height);
+            return bounds;
         }
 
         /**
--- a/jdk/src/java.desktop/share/classes/javax/swing/text/PasswordView.java	Wed Oct 19 08:06:10 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/text/PasswordView.java	Thu Oct 20 12:18:15 2016 +0300
@@ -26,7 +26,11 @@
 
 import sun.swing.SwingUtilities2;
 import java.awt.*;
+import java.awt.font.FontRenderContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import javax.swing.JPasswordField;
+import static javax.swing.text.PlainView.isFPMethodOverriden;
 
 /**
  * Implements a View suitable for use in JPasswordField
@@ -61,15 +65,40 @@
      * @param p1 the ending offset in the model &gt;= p0
      * @return the X location of the end of the range &gt;= 0
      * @exception BadLocationException if p0 or p1 are out of range
+     *
+     * @deprecated replaced by
+     *     {@link #drawUnselectedText(Graphics2D, float, float, int, int)}
      */
+    @Deprecated(since = "9")
+    @Override
     protected int drawUnselectedText(Graphics g, int x, int y,
                                      int p0, int p1) throws BadLocationException {
+        return (int) drawUnselectedTextImpl(g, x, y, p0, p1, false);
+    }
 
+    @Override
+    protected float drawUnselectedText(Graphics2D g, float x, float y,
+                                       int p0, int p1)
+            throws BadLocationException
+    {
+        return drawUnselectedTextImpl(g, x, y, p0, p1, true);
+    }
+
+    private float drawUnselectedTextImpl(Graphics g, float x, float y,
+                                         int p0, int p1,
+                                         boolean useFPAPI)
+            throws BadLocationException
+    {
         Container c = getContainer();
         if (c instanceof JPasswordField) {
             JPasswordField f = (JPasswordField) c;
-            if (! f.echoCharIsSet()) {
-                return super.drawUnselectedText(g, x, y, p0, p1);
+            if (!f.echoCharIsSet()) {
+                boolean useDrawUnselectedFPAPI = useFPAPI
+                        && drawUnselectedTextOverridden
+                        && g instanceof Graphics2D;
+                return (useDrawUnselectedFPAPI )
+                        ? super.drawUnselectedText((Graphics2D) g, x, y, p0, p1)
+                        : super.drawUnselectedText(g, (int) x, (int) y, p0, p1);
             }
             if (f.isEnabled()) {
                 g.setColor(f.getForeground());
@@ -79,8 +108,13 @@
             }
             char echoChar = f.getEchoChar();
             int n = p1 - p0;
+            boolean useEchoCharFPAPI = useFPAPI
+                    && drawEchoCharacterOverridden
+                    && g instanceof Graphics2D;
             for (int i = 0; i < n; i++) {
-                x = drawEchoCharacter(g, x, y, echoChar);
+                x = (useEchoCharFPAPI)
+                        ? drawEchoCharacter((Graphics2D) g, x, y, echoChar)
+                        : drawEchoCharacter(g, (int) x, (int) y, echoChar);
             }
         }
         return x;
@@ -100,20 +134,50 @@
      * @param p1 the ending offset in the model &gt;= p0
      * @return the X location of the end of the range &gt;= 0
      * @exception BadLocationException if p0 or p1 are out of range
+     *
+     * @deprecated replaced by
+     *     {@link #drawSelectedText(Graphics2D, float, float, int, int)}
      */
+    @Deprecated(since = "9")
+    @Override
     protected int drawSelectedText(Graphics g, int x,
                                    int y, int p0, int p1) throws BadLocationException {
+        return (int) drawSelectedTextImpl(g, x, y, p0, p1, false);
+    }
+
+    @Override
+    protected float drawSelectedText(Graphics2D g, float x, float y,
+                                     int p0, int p1) throws BadLocationException
+    {
+        return drawSelectedTextImpl(g, x, y, p0, p1, true);
+    }
+
+    private float drawSelectedTextImpl(Graphics g, float x, float y,
+                                       int p0, int p1,
+                                       boolean useFPAPI)
+            throws BadLocationException {
         g.setColor(selected);
         Container c = getContainer();
         if (c instanceof JPasswordField) {
             JPasswordField f = (JPasswordField) c;
-            if (! f.echoCharIsSet()) {
-                return super.drawSelectedText(g, x, y, p0, p1);
+            if (!f.echoCharIsSet()) {
+                boolean useDrawUnselectedFPAPI = useFPAPI
+                        && drawSelectedTextOverridden
+                        && g instanceof Graphics2D;
+                return (useFPAPI)
+                        ? super.drawSelectedText((Graphics2D) g, x, y, p0, p1)
+                        : super.drawSelectedText(g, (int) x, (int) y, p0, p1);
             }
             char echoChar = f.getEchoChar();
             int n = p1 - p0;
+            boolean useEchoCharFPAPI = useFPAPI
+                    && drawEchoCharacterOverridden
+                    && g instanceof Graphics2D;
             for (int i = 0; i < n; i++) {
-                x = drawEchoCharacter(g, x, y, echoChar);
+                x = (useEchoCharFPAPI)
+                        ? drawEchoCharacter((Graphics2D) g, x, y, echoChar)
+                        : drawEchoCharacter(g, (int) x, (int) y, echoChar);
+
             }
         }
         return x;
@@ -130,12 +194,13 @@
      * @param y the starting Y coordinate &gt;= 0
      * @param c the echo character
      * @return the updated X position &gt;= 0
+     *
+     * @deprecated replaced by
+     *     {@link #drawEchoCharacter(Graphics2D, float, float, char)}
      */
+    @Deprecated(since = "9")
     protected int drawEchoCharacter(Graphics g, int x, int y, char c) {
-        ONE[0] = c;
-        SwingUtilities2.drawChars(Utilities.getJComponent(this),
-                                  g, ONE, 0, 1, x, y);
-        return x + g.getFontMetrics().charWidth(c);
+        return (int) drawEchoCharacterImpl(g, x, y, c, false);
     }
 
     /**
@@ -144,18 +209,29 @@
      * object is set to the appropriate foreground color for selected
      * or unselected text.
      *
-     * @implSpec This implementation calls
-     * {@link #drawEchoCharacter(Graphics, int, int, char)
-     *      drawEchoCharacter((Graphics) g, (int) x, (int) y, c)}.
-     *
      * @param g the graphics context
      * @param x the starting X coordinate {@code >= 0}
      * @param y the starting Y coordinate {@code >= 0}
      * @param c the echo character
      * @return the updated X position {@code >= 0}
+     *
+     * @since 9
      */
     protected float drawEchoCharacter(Graphics2D g, float x, float y, char c) {
-        return drawEchoCharacter((Graphics) g, (int) x, (int) y, c);
+        return drawEchoCharacterImpl(g, x, y, c, true);
+    }
+
+    private float drawEchoCharacterImpl(Graphics g, float x, float y,
+                                        char c, boolean useFPAPI) {
+        ONE[0] = c;
+        SwingUtilities2.drawChars(Utilities.getJComponent(this),
+                                  g, ONE, 0, 1, x, y);
+        if (useFPAPI) {
+            return x + g.getFontMetrics().charWidth(c);
+        } else {
+            FontRenderContext frc = g.getFontMetrics().getFontRenderContext();
+            return x + (float) g.getFont().getStringBounds(ONE, 0, 1, frc).getWidth();
+        }
     }
 
     /**
@@ -253,4 +329,23 @@
     }
 
     static char[] ONE = new char[1];
+
+    private final boolean drawEchoCharacterOverridden;
+
+    {
+        final Class<?> CLS = getClass();
+        final Class<?> INT = Integer.TYPE;
+        final Class<?> FP = Float.TYPE;
+        final Class<?> CHAR = Character.TYPE;
+
+        drawEchoCharacterOverridden = AccessController
+                .doPrivileged(new PrivilegedAction<Boolean>() {
+            @Override
+            public Boolean run() {
+                Class<?>[] intTypes = {Graphics.class, INT, INT, CHAR};
+                Class<?>[] fpTypes = {Graphics2D.class, FP, FP, CHAR};
+                return isFPMethodOverriden("drawEchoCharacter", CLS, intTypes, fpTypes);
+            }
+        });
+    }
 }
--- a/jdk/src/java.desktop/share/classes/javax/swing/text/PlainView.java	Wed Oct 19 08:06:10 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/text/PlainView.java	Thu Oct 20 12:18:15 2016 +0300
@@ -24,11 +24,14 @@
  */
 package javax.swing.text;
 
-import java.util.Vector;
-import java.util.Properties;
 import java.awt.*;
+import java.awt.font.FontRenderContext;
+import java.awt.geom.Rectangle2D;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.Objects;
 import javax.swing.event.*;
+import java.lang.reflect.Module;
 
 /**
  * Implements View interface for a simple multi-line text view
@@ -61,17 +64,6 @@
     }
 
     /**
-     * Returns the tab size set for the document, defaulting to 8.
-     *
-     * @implSpec This implementation calls {@link #getTabSize() getTabSize()}.
-     *
-     * @return the tab size
-     */
-    protected float getFractionalTabSize() {
-        return getTabSize();
-    }
-
-    /**
      * Renders a line of text, suppressing whitespace at the end
      * and expanding any tabs.  This is implemented to make calls
      * to the methods <code>drawUnselectedText</code> and
@@ -84,8 +76,16 @@
      * @param y the starting Y position &gt;= 0
      * @see #drawUnselectedText
      * @see #drawSelectedText
+     *
+     * @deprecated replaced by
+     *     {@link #drawLine(int, Graphics2D, float, float)}
      */
+    @Deprecated(since = "9")
     protected void drawLine(int lineIndex, Graphics g, int x, int y) {
+        drawLineImpl(lineIndex, g, x, y);
+    }
+
+    private void drawLineImpl(int lineIndex, Graphics g, float x, float y) {
         Element line = getElement().getElement(lineIndex);
         Element elem;
 
@@ -112,22 +112,23 @@
      * {@code drawSelectedText} so that the way selected and
      * unselected text are rendered can be customized.
      *
-     * @implSpec This implementation calls
-     * {@link #drawLine(int, Graphics, int, int)
-     * drawLine(lineIndex, (Graphics)g, (int) x, (int) y)}.
-     *
      * @param lineIndex the line to draw {@code >= 0}
      * @param g the {@code Graphics} context
      * @param x the starting X position {@code >= 0}
      * @param y the starting Y position {@code >= 0}
      * @see #drawUnselectedText
      * @see #drawSelectedText
+     *
+     * @since 9
      */
     protected void drawLine(int lineIndex, Graphics2D g, float x, float y) {
-        drawLine(lineIndex, (Graphics)g, (int) x, (int) y);
+        drawLineImpl(lineIndex, g, x, y);
     }
 
-    private int drawElement(int lineIndex, Element elem, Graphics g, int x, int y) throws BadLocationException {
+    private float drawElement(int lineIndex, Element elem, Graphics g,
+                              float x, float y)
+                              throws BadLocationException
+    {
         int p0 = elem.getStartOffset();
         int p1 = elem.getEndOffset();
         p1 = Math.min(getDocument().getLength(), p1);
@@ -144,23 +145,23 @@
         } else {
             if (sel0 == sel1 || selected == unselected) {
                 // no selection, or it is invisible
-                x = drawUnselectedText(g, x, y, p0, p1);
+                x = callDrawUnselectedText(g, x, y, p0, p1);
             } else if ((p0 >= sel0 && p0 <= sel1) && (p1 >= sel0 && p1 <= sel1)) {
-                x = drawSelectedText(g, x, y, p0, p1);
+                x = callDrawSelectedText(g, x, y, p0, p1);
             } else if (sel0 >= p0 && sel0 <= p1) {
                 if (sel1 >= p0 && sel1 <= p1) {
-                    x = drawUnselectedText(g, x, y, p0, sel0);
-                    x = drawSelectedText(g, x, y, sel0, sel1);
-                    x = drawUnselectedText(g, x, y, sel1, p1);
+                    x = callDrawUnselectedText(g, x, y, p0, sel0);
+                    x = callDrawSelectedText(g, x, y, sel0, sel1);
+                    x = callDrawUnselectedText(g, x, y, sel1, p1);
                 } else {
-                    x = drawUnselectedText(g, x, y, p0, sel0);
-                    x = drawSelectedText(g, x, y, sel0, p1);
+                    x = callDrawUnselectedText(g, x, y, p0, sel0);
+                    x = callDrawSelectedText(g, x, y, sel0, p1);
                 }
             } else if (sel1 >= p0 && sel1 <= p1) {
-                x = drawSelectedText(g, x, y, p0, sel1);
-                x = drawUnselectedText(g, x, y, sel1, p1);
+                x = callDrawSelectedText(g, x, y, p0, sel1);
+                x = callDrawUnselectedText(g, x, y, sel1, p1);
             } else {
-                x = drawUnselectedText(g, x, y, p0, p1);
+                x = callDrawUnselectedText(g, x, y, p0, p1);
             }
         }
 
@@ -178,14 +179,36 @@
      * @param p1 the ending position in the model &gt;= 0
      * @return the X location of the end of the range &gt;= 0
      * @exception BadLocationException if the range is invalid
+     *
+     * @deprecated replaced by
+     *     {@link #drawUnselectedText(Graphics2D, float, float, int, int)}
      */
+    @Deprecated(since = "9")
     protected int drawUnselectedText(Graphics g, int x, int y,
                                      int p0, int p1) throws BadLocationException {
+        return (int) drawUnselectedTextImpl(g, x, y, p0, p1, false);
+    }
+
+    private float callDrawUnselectedText(Graphics g, float x, float y,
+                                         int p0, int p1)
+                                         throws BadLocationException
+    {
+        return drawUnselectedTextOverridden && (g instanceof Graphics2D)
+                ? drawUnselectedText((Graphics2D) g, x, y, p0, p1)
+                : drawUnselectedText(g, (int) x, (int) y, p0, p1);
+    }
+
+    private float drawUnselectedTextImpl(Graphics g, float x, float y,
+                                         int p0, int p1,
+                                         boolean useFPAPI)
+            throws BadLocationException
+    {
         g.setColor(unselected);
         Document doc = getDocument();
         Segment s = SegmentCache.getSharedSegment();
         doc.getText(p0, p1 - p0, s);
-        int ret = Utilities.drawTabbedText(this, s, x, y, g, this, p0);
+        float ret = Utilities.drawTabbedText(this, s, x, y, g, this, p0, null,
+                                             useFPAPI);
         SegmentCache.releaseSharedSegment(s);
         return ret;
     }
@@ -194,10 +217,6 @@
      * Renders the given range in the model as normal unselected
      * text.  Uses the foreground or disabled color to render the text.
      *
-     * @implSpec This implementation calls
-     * {@link #drawUnselectedText(Graphics, int, int, int, int)
-     * drawUnselectedText((Graphics)g, (int) x, (int) y, p0, p1)}.
-     *
      * @param g the graphics context
      * @param x the starting X coordinate {@code >= 0}
      * @param y the starting Y coordinate {@code >= 0}
@@ -205,10 +224,12 @@
      * @param p1 the ending position in the model {@code >= 0}
      * @return the X location of the end of the range {@code >= 0}
      * @exception BadLocationException if the range is invalid
+     *
+     * @since 9
      */
     protected float drawUnselectedText(Graphics2D g, float x, float y,
                                        int p0, int p1) throws BadLocationException {
-        return drawUnselectedText((Graphics)g, (int) x, (int) y, p0, p1);
+        return drawUnselectedTextImpl(g, x, y, p0, p1, true);
     }
 
     /**
@@ -224,14 +245,38 @@
      * @param p1 the ending position in the model &gt;= 0
      * @return the location of the end of the range
      * @exception BadLocationException if the range is invalid
+     *
+     * @deprecated replaced by
+     *     {@link #drawSelectedText(Graphics2D, float, float, int, int)}
      */
+    @Deprecated(since = "9")
     protected int drawSelectedText(Graphics g, int x,
-                                   int y, int p0, int p1) throws BadLocationException {
+                                   int y, int p0, int p1)
+                                   throws BadLocationException
+    {
+        return (int) drawSelectedTextImpl(g, x, y, p0, p1, false);
+    }
+
+    float callDrawSelectedText(Graphics g, float x, float y,
+                               int p0, int p1)
+                               throws BadLocationException
+    {
+        return drawSelectedTextOverridden && g instanceof Graphics2D
+                ? drawSelectedText((Graphics2D) g, x, y, p0, p1)
+                : drawSelectedText(g, (int) x, (int) y, p0, p1);
+    }
+
+    private float drawSelectedTextImpl(Graphics g, float x, float y,
+                                       int p0, int p1,
+                                       boolean useFPAPI)
+            throws BadLocationException
+    {
         g.setColor(selected);
         Document doc = getDocument();
         Segment s = SegmentCache.getSharedSegment();
         doc.getText(p0, p1 - p0, s);
-        int ret = Utilities.drawTabbedText(this, s, x, y, g, this, p0);
+        float ret = Utilities.drawTabbedText(this, s, x, y, g, this, p0, null,
+                                             useFPAPI);
         SegmentCache.releaseSharedSegment(s);
         return ret;
     }
@@ -242,10 +287,6 @@
      * the hosting component.  It assumes the highlighter will render
      * the selected background.
      *
-     * @implSpec This implementation calls
-     * {@link #drawSelectedText(Graphics, int, int, int, int)
-     * drawSelectedText((Graphics)g, (int) x, (int) y, p0, p1)}.
-     *
      * @param g the graphics context
      * @param x the starting X coordinate {@code >= 0}
      * @param y the starting Y coordinate {@code >= 0}
@@ -253,11 +294,12 @@
      * @param p1 the ending position in the model {@code >= 0}
      * @return the location of the end of the range
      * @exception BadLocationException if the range is invalid
+     *
+     * @since 9
      */
-
     protected float drawSelectedText(Graphics2D g, float x,
                                      float y, int p0, int p1) throws BadLocationException {
-        return drawSelectedText((Graphics)g, (int) x, (int) y, p0, p1);
+        return drawSelectedTextImpl(g, x, y, p0, p1, true);
     }
 
     /**
@@ -287,7 +329,13 @@
             // The font changed, we need to recalculate the
             // longest line.
             calculateLongestLine();
-            tabSize = getTabSize() * metrics.charWidth('m');
+            if (useFloatingPointAPI) {
+                FontRenderContext frc = metrics.getFontRenderContext();
+                float tabWidth = (float) font.getStringBounds("m", frc).getWidth();
+                tabSize = getTabSize() * tabWidth;
+            } else {
+                tabSize = getTabSize() * metrics.charWidth('m');
+            }
         }
     }
 
@@ -388,7 +436,11 @@
                                               originalA, host, this);
                 }
             }
-            drawLine(line, g, x, y);
+            if (drawLineOverridden && (g instanceof Graphics2D)) {
+                drawLine(line, (Graphics2D) g, (float) x, (float) y);
+            } else {
+                drawLine(line, g, x, y);
+            }
             y += fontHeight;
             if (line == 0) {
                 // This should never really happen, in so far as if
@@ -435,6 +487,13 @@
         int p0 = line.getStartOffset();
         Segment s = SegmentCache.getSharedSegment();
         doc.getText(p0, pos - p0, s);
+
+        if (useFloatingPointAPI) {
+            float xOffs = Utilities.getTabbedTextWidth(s, metrics, (float) tabBase, this, p0);
+            SegmentCache.releaseSharedSegment(s);
+            return new Rectangle2D.Float(lineArea.x + xOffs, lineArea.y, 1, metrics.getHeight());
+        }
+
         int xOffs = Utilities.getTabbedTextWidth(s, metrics, tabBase, this,p0);
         SegmentCache.releaseSharedSegment(s);
 
@@ -456,14 +515,13 @@
      *  given point in the view &gt;= 0
      * @see View#viewToModel
      */
-    public int viewToModel(float fx, float fy, Shape a, Position.Bias[] bias) {
+    public int viewToModel(float x, float y, Shape a, Position.Bias[] bias) {
         // PENDING(prinz) properly calculate bias
         bias[0] = Position.Bias.Forward;
 
         Rectangle alloc = a.getBounds();
         Document doc = getDocument();
-        int x = (int) fx;
-        int y = (int) fy;
+
         if (y < alloc.y) {
             // above the area covered by this icon, so the position
             // is assumed to be the start of the coverage for this view.
@@ -481,7 +539,7 @@
             Element map = doc.getDefaultRootElement();
             int fontHeight = metrics.getHeight();
             int lineIndex = (fontHeight > 0 ?
-                                Math.abs((y - alloc.y) / fontHeight) :
+                                (int)Math.abs((y - alloc.y) / fontHeight) :
                                 map.getElementCount() - 1);
             if (lineIndex >= map.getElementCount()) {
                 return getEndOffset() - 1;
@@ -507,7 +565,7 @@
                     doc.getText(p0, p1 - p0, s);
                     tabBase = alloc.x;
                     int offs = p0 + Utilities.getTabbedTextOffset(s, metrics,
-                                                                  tabBase, x, this, p0);
+                                                                  tabBase, x, this, p0, true);
                     SegmentCache.releaseSharedSegment(s);
                     return offs;
                 } catch (BadLocationException e) {
@@ -586,7 +644,7 @@
         if (tabSize == 0) {
             return x;
         }
-        int ntabs = (((int) x) - tabBase) / tabSize;
+        float ntabs = (x - tabBase) / tabSize;
         return tabBase + ((ntabs + 1) * tabSize);
     }
 
@@ -758,6 +816,28 @@
         return w;
     }
 
+    static boolean isFPMethodOverriden(String method,
+                                Class<?> cls,
+                                Class<?>[] intTypes,
+                                Class<?>[] fpTypes)
+    {
+        Module thisModule = PlainView.class.getModule();
+        while (!thisModule.equals(cls.getModule())) {
+            try {
+                cls.getDeclaredMethod(method, fpTypes);
+                return true;
+            } catch (Exception e1) {
+                try {
+                    cls.getDeclaredMethod(method, intTypes);
+                    return false;
+                } catch (Exception e2) {
+                    cls = cls.getSuperclass();
+                }
+            }
+        }
+        return true;
+    }
+
     // --- member variables -----------------------------------------------
 
     /**
@@ -780,7 +860,7 @@
     Font font;
 
     Segment lineBuffer;
-    int tabSize;
+    float tabSize;
     int tabBase;
 
     int sel0;
@@ -796,4 +876,46 @@
      */
     int firstLineOffset;
 
+    final boolean drawLineOverridden;
+    final boolean drawSelectedTextOverridden;
+    final boolean drawUnselectedTextOverridden;
+    final boolean useFloatingPointAPI;
+
+    {
+        final Class<?> CLS = getClass();
+        final Class<?> INT = Integer.TYPE;
+        final Class<?> FP = Float.TYPE;
+
+        drawLineOverridden = AccessController
+                .doPrivileged(new PrivilegedAction<Boolean>() {
+            @Override
+            public Boolean run() {
+                Class<?>[] intTypes = {INT, Graphics.class, INT, INT};
+                Class<?>[] fpTypes = {INT, Graphics2D.class, FP, FP};
+                return isFPMethodOverriden("drawLine", CLS, intTypes, fpTypes);
+            }
+        });
+
+        drawUnselectedTextOverridden = AccessController
+                .doPrivileged(new PrivilegedAction<Boolean>() {
+            @Override
+            public Boolean run() {
+                Class<?>[] intTypes = {Graphics.class, INT, INT, INT, INT};
+                Class<?>[] fpTypes = {Graphics2D.class, FP, FP, INT, INT};
+                return isFPMethodOverriden("drawUnselectedText", CLS, intTypes, fpTypes);
+            }
+        });
+
+        drawSelectedTextOverridden = AccessController
+                .doPrivileged(new PrivilegedAction<Boolean>() {
+            @Override
+            public Boolean run() {
+                Class<?>[] intTypes = {Graphics.class, INT, INT, INT, INT};
+                Class<?>[] fpTypes = {Graphics2D.class, FP, FP, INT, INT};
+                return isFPMethodOverriden("drawSelectedText", CLS, intTypes, fpTypes);
+            }
+        });
+
+        useFloatingPointAPI = drawUnselectedTextOverridden || drawSelectedTextOverridden;
+    }
 }
--- a/jdk/src/java.desktop/share/classes/javax/swing/text/Utilities.java	Wed Oct 19 08:06:10 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/text/Utilities.java	Thu Oct 20 12:18:15 2016 +0300
@@ -24,24 +24,23 @@
  */
 package javax.swing.text;
 
-import java.lang.reflect.Method;
-
 import java.awt.Component;
 import java.awt.Rectangle;
 import java.awt.Graphics;
 import java.awt.FontMetrics;
 import java.awt.Shape;
-import java.awt.Toolkit;
 import java.awt.Graphics2D;
-import java.awt.font.FontRenderContext;
-import java.awt.font.TextLayout;
 import java.awt.font.TextAttribute;
+import java.awt.geom.Rectangle2D;
 
 import java.text.*;
 import javax.swing.JComponent;
 import javax.swing.SwingConstants;
 import javax.swing.text.ParagraphView.Row;
 import sun.swing.SwingUtilities2;
+import static sun.swing.SwingUtilities2.drawChars;
+import static sun.swing.SwingUtilities2.getFontCharWidth;
+import static sun.swing.SwingUtilities2.getFontCharsWidth;
 
 /**
  * A collection of methods to deal with various text
@@ -78,7 +77,11 @@
      *   tabs will be expanded as a space character.
      * @param startOffset starting offset of the text in the document &gt;= 0
      * @return  the X location at the end of the rendered text
+     *
+     * @deprecated replaced by
+     * {@link #drawTabbedText(Segment, float, float, Graphics2D, TabExpander, int)}
      */
+    @Deprecated(since = "9")
     public static final int drawTabbedText(Segment s, int x, int y, Graphics g,
                                            TabExpander e, int startOffset) {
         return drawTabbedText(null, s, x, y, g, e, startOffset);
@@ -96,6 +99,8 @@
      *           tabs will be expanded as a space character.
      * @param startOffset starting offset of the text in the document {@code >= 0}
      * @return  the X location at the end of the rendered text
+     *
+     * @since 9
      */
     public static final float drawTabbedText(Segment s, float x, float y,
                                              Graphics2D g,
@@ -138,9 +143,19 @@
                                 Segment s, int x, int y, Graphics g,
                                 TabExpander e, int startOffset,
                                 int [] justificationData) {
+        return (int) drawTabbedText(view, s, x, y, g, e, startOffset,
+                                    justificationData, false);
+    }
+
+    static final float drawTabbedText(View view,
+                                Segment s, float x, float y, Graphics g,
+                                TabExpander e, int startOffset,
+                                int [] justificationData,
+                                boolean useFPAPI)
+    {
         JComponent component = getJComponent(view);
         FontMetrics metrics = SwingUtilities2.getFontMetrics(component, g);
-        int nextX = x;
+        float nextX = x;
         char[] txt = s.array;
         int txtOffset = s.offset;
         int flushLen = 0;
@@ -174,19 +189,19 @@
                     && i <= endJustifiableContent
                     )) {
                 if (flushLen > 0) {
-                    nextX = SwingUtilities2.drawChars(component, g, txt,
-                                                flushIndex, flushLen, x, y);
+                    nextX = drawChars(component, g, txt, flushIndex, flushLen, x, y);
                     flushLen = 0;
                 }
                 flushIndex = i + 1;
                 if (txt[i] == '\t') {
                     if (e != null) {
-                        nextX = (int) e.nextTabStop((float) nextX, startOffset + i - txtOffset);
+                        nextX = e.nextTabStop(nextX, startOffset + i - txtOffset);
                     } else {
-                        nextX += metrics.charWidth(' ');
+                        nextX += getFontCharWidth(' ', metrics, useFPAPI);
                     }
                 } else if (txt[i] == ' ') {
-                    nextX += metrics.charWidth(' ') + spaceAddon;
+                    float spaceWidth = getFontCharWidth(' ', metrics, useFPAPI);
+                    nextX += spaceWidth + spaceAddon;
                     if (i <= spaceAddonLeftoverEnd) {
                         nextX++;
                     }
@@ -194,8 +209,8 @@
                 x = nextX;
             } else if ((txt[i] == '\n') || (txt[i] == '\r')) {
                 if (flushLen > 0) {
-                    nextX = SwingUtilities2.drawChars(component, g, txt,
-                                                flushIndex, flushLen, x, y);
+                    nextX = drawChars(component, g, txt, flushIndex, flushLen,
+                                      x, y, useFPAPI);
                     flushLen = 0;
                 }
                 flushIndex = i + 1;
@@ -205,8 +220,7 @@
             }
         }
         if (flushLen > 0) {
-            nextX = SwingUtilities2.drawChars(component, g,txt, flushIndex,
-                                              flushLen, x, y);
+            nextX = drawChars(component, g,txt, flushIndex, flushLen, x, y, useFPAPI);
         }
         return nextX;
     }
@@ -223,7 +237,11 @@
      *   tabs will be expanded as a space character.
      * @param startOffset starting offset of the text in the document &gt;= 0
      * @return  the width of the text
+     *
+     * @deprecated replaced by
+     *     {@link #getTabbedTextWidth(Segment, FontMetrics, float, TabExpander, int)}
      */
+    @Deprecated(since = "9")
     public static final int getTabbedTextWidth(Segment s, FontMetrics metrics, int x,
                                                TabExpander e, int startOffset) {
         return getTabbedTextWidth(null, s, metrics, x, e, startOffset, null);
@@ -240,11 +258,13 @@
      *   tabs will be expanded as a space character.
      * @param startOffset starting offset of the text in the document {@code >= 0}
      * @return  the width of the text
+     *
+     * @since 9
      */
     public static final float getTabbedTextWidth(Segment s, FontMetrics metrics,
                                                  float x, TabExpander e,
                                                  int startOffset) {
-        return getTabbedTextWidth(s, metrics, (int) x, e, startOffset);
+        return getTabbedTextWidth(null, s, metrics, x, e, startOffset, null);
     }
 
     // In addition to the previous method it can extend spaces for
@@ -254,10 +274,32 @@
     // one:
     // @param justificationData justificationData for the row.
     // if null not justification is needed
-    static final int getTabbedTextWidth(View view, Segment s, FontMetrics metrics, int x,
+    static final int getTabbedTextWidth(View view, Segment s,
+                                        FontMetrics metrics, int x,
+                                        TabExpander e, int startOffset,
+                                        int[] justificationData)
+    {
+        return (int) getTabbedTextWidth(view, s, metrics, x, e, startOffset,
+                                        justificationData, false);
+
+    }
+
+    static final float getTabbedTextWidth(View view, Segment s,
+                                        FontMetrics metrics, float x,
                                         TabExpander e, int startOffset,
-                                        int[] justificationData) {
-        int nextX = x;
+                                        int[] justificationData)
+    {
+        return  getTabbedTextWidth(view, s, metrics, x, e, startOffset,
+                                   justificationData, true);
+
+    }
+
+    static final float getTabbedTextWidth(View view, Segment s,
+                                        FontMetrics metrics, float x,
+                                        TabExpander e, int startOffset,
+                                        int[] justificationData,
+                                        boolean useFPAPI) {
+        float nextX = x;
         char[] txt = s.array;
         int txtOffset = s.offset;
         int n = s.offset + s.count;
@@ -294,13 +336,13 @@
                 charCount = 0;
                 if (txt[i] == '\t') {
                     if (e != null) {
-                        nextX = (int) e.nextTabStop((float) nextX,
-                                                    startOffset + i - txtOffset);
+                        nextX = e.nextTabStop(nextX, startOffset + i - txtOffset);
                     } else {
-                        nextX += metrics.charWidth(' ');
+                        nextX += getFontCharWidth(' ', metrics, useFPAPI);
                     }
                 } else if (txt[i] == ' ') {
-                    nextX += metrics.charWidth(' ') + spaceAddon;
+                    float spaceWidth = getFontCharWidth(' ', metrics, useFPAPI);
+                    nextX += spaceWidth + spaceAddon;
                     if (i <= spaceAddonLeftoverEnd) {
                         nextX++;
                     }
@@ -308,13 +350,15 @@
             } else if(txt[i] == '\n') {
             // Ignore newlines, they take up space and we shouldn't be
             // counting them.
-                nextX += metrics.charsWidth(txt, i - charCount, charCount);
+                nextX += getFontCharsWidth(txt, i - charCount, charCount,
+                                           metrics, useFPAPI);
                 charCount = 0;
             } else {
                 charCount++;
         }
         }
-        nextX += metrics.charsWidth(txt, n - charCount, charCount);
+        nextX += getFontCharsWidth(txt, n - charCount, charCount,
+                                   metrics, useFPAPI);
         return nextX - x;
     }
 
@@ -334,7 +378,12 @@
      *   tabs will be expanded as a space character.
      * @param startOffset starting offset of the text in the document &gt;= 0
      * @return  the offset into the text &gt;= 0
+     *
+     * @deprecated replaced by
+     *     {@link #getTabbedTextOffset(Segment, FontMetrics, float, float,
+     *                                 TabExpander, int, boolean)}
      */
+    @Deprecated(since = "9")
     public static final int getTabbedTextOffset(Segment s, FontMetrics metrics,
                                              int x0, int x, TabExpander e,
                                              int startOffset) {
@@ -346,7 +395,7 @@
                                          int startOffset,
                                          int[] justificationData) {
         return getTabbedTextOffset(view, s, metrics, x0, x, e, startOffset, true,
-                                   justificationData);
+                                   justificationData, false);
     }
 
     /**
@@ -365,13 +414,19 @@
      * @param startOffset starting offset of the text in the document &gt;= 0
      * @param round whether or not to round
      * @return  the offset into the text &gt;= 0
+     *
+     * @deprecated replaced by
+     *     {@link #getTabbedTextOffset(Segment, FontMetrics, float, float,
+     *                                 TabExpander, int, boolean)}
      */
+    @Deprecated(since = "9")
     public static final int getTabbedTextOffset(Segment s,
                                                 FontMetrics metrics,
                                                 int x0, int x, TabExpander e,
                                                 int startOffset,
                                                 boolean round) {
-        return getTabbedTextOffset(null, s, metrics, x0, x, e, startOffset, round, null);
+        return getTabbedTextOffset(null, s, metrics, x0, x, e, startOffset,
+                                   round, null, false);
     }
 
     /**
@@ -390,6 +445,8 @@
      * @param startOffset starting offset of the text in the document {@code >= 0}
      * @param round whether or not to round
      * @return  the offset into the text {@code >= 0}
+     *
+     * @since 9
      */
     public static final int getTabbedTextOffset(Segment s,
                                                 FontMetrics metrics,
@@ -398,8 +455,8 @@
                                                 int startOffset,
                                                 boolean round)
     {
-        return getTabbedTextOffset(null, s, metrics, (int) x0, (int) x, e,
-                                   startOffset, round, null);
+        return getTabbedTextOffset(null, s, metrics, x0, x, e,
+                                   startOffset, round, null, true);
     }
 
     // In addition to the previous method it can extend spaces for
@@ -412,15 +469,16 @@
     static final int getTabbedTextOffset(View view,
                                          Segment s,
                                          FontMetrics metrics,
-                                         int x0, int x, TabExpander e,
+                                         float x0, float x, TabExpander e,
                                          int startOffset,
                                          boolean round,
-                                         int[] justificationData) {
+                                         int[] justificationData,
+                                         boolean useFPAPI) {
         if (x0 >= x) {
             // x before x0, return.
             return 0;
         }
-        int nextX = x0;
+        float nextX = x0;
         // s may be a shared segment, so it is copied prior to calling
         // the tab expander
         char[] txt = s.array;
@@ -456,19 +514,19 @@
                     )){
                 if (txt[i] == '\t') {
                     if (e != null) {
-                        nextX = (int) e.nextTabStop((float) nextX,
-                                                    startOffset + i - txtOffset);
+                        nextX = e.nextTabStop(nextX, startOffset + i - txtOffset);
                     } else {
-                        nextX += metrics.charWidth(' ');
+                        nextX += getFontCharWidth(' ', metrics, useFPAPI);
                     }
                 } else if (txt[i] == ' ') {
-                    nextX += metrics.charWidth(' ') + spaceAddon;
+                    nextX += getFontCharWidth(' ', metrics, useFPAPI);
+                    nextX += spaceAddon;
                     if (i <= spaceAddonLeftoverEnd) {
                         nextX++;
                     }
                 }
             } else {
-                nextX += metrics.charWidth(txt[i]);
+                nextX += getFontCharWidth(txt[i], metrics, useFPAPI);
             }
             if (x < nextX) {
                 // found the hit position... return the appropriate side
@@ -480,12 +538,15 @@
                 if (round) {
                     offset = i + 1 - txtOffset;
 
-                    int width = metrics.charsWidth(txt, txtOffset, offset);
-                    int span = x - x0;
+                    float width = getFontCharsWidth(txt, txtOffset, offset,
+                                                    metrics, useFPAPI);
+                    float span = x - x0;
 
                     if (span < width) {
                         while (offset > 0) {
-                            int nextWidth = offset > 1 ? metrics.charsWidth(txt, txtOffset, offset - 1) : 0;
+                            float charsWidth = getFontCharsWidth(txt, txtOffset,
+                                    offset - 1, metrics, useFPAPI);
+                            float nextWidth = offset > 1 ? charsWidth : 0;
 
                             if (span >= nextWidth) {
                                 if (span - nextWidth < width - span) {
@@ -502,7 +563,9 @@
                 } else {
                     offset = i - txtOffset;
 
-                    while (offset > 0 && metrics.charsWidth(txt, txtOffset, offset) > (x - x0)) {
+                    while (offset > 0 && getFontCharsWidth(txt, txtOffset, offset,
+                                                           metrics, useFPAPI)
+                            > (x - x0)) {
                         offset--;
                     }
                 }
@@ -528,15 +591,26 @@
      *   tabs will be expanded as a space character.
      * @param startOffset starting offset in the document of the text
      * @return  the offset into the given text
+     *
+     * @deprecated replaced by
+     *     {@link #getBreakLocation(Segment, FontMetrics, float, float,
+     *                              TabExpander, int)}
      */
+    @Deprecated(since = "9")
     public static final int getBreakLocation(Segment s, FontMetrics metrics,
                                              int x0, int x, TabExpander e,
                                              int startOffset) {
+        return getBreakLocation(s, metrics, x0, x, e, startOffset, false);
+    }
+
+    static final int getBreakLocation(Segment s, FontMetrics metrics,
+                                      float x0, float x, TabExpander e,
+                                      int startOffset, boolean useFPIAPI) {
         char[] txt = s.array;
         int txtOffset = s.offset;
         int txtCount = s.count;
-        int index = Utilities.getTabbedTextOffset(s, metrics, x0, x,
-                                                  e, startOffset, false);
+        int index = getTabbedTextOffset(null, s, metrics, x0, x, e, startOffset,
+                                        false, null, useFPIAPI);
 
         if (index >= txtCount - 1) {
             return txtCount;
@@ -577,11 +651,13 @@
      *        tabs will be expanded as a space character.
      * @param startOffset starting offset in the document of the text
      * @return  the offset into the given text
+     *
+     * @since 9
      */
     public static final int getBreakLocation(Segment s, FontMetrics metrics,
                                              float x0, float x, TabExpander e,
                                              int startOffset) {
-        return getBreakLocation(s, metrics, (int) x0, (int) x, e, startOffset);
+        return getBreakLocation(s, metrics, x0, x, e, startOffset, false);
     }
 
     /**
@@ -627,16 +703,16 @@
      * @exception BadLocationException if the offset is out of range
      */
     public static final int getRowEnd(JTextComponent c, int offs) throws BadLocationException {
-        Rectangle r = c.modelToView(offs);
+        Rectangle2D r = c.modelToView2D(offs);
         if (r == null) {
             return -1;
         }
         int n = c.getDocument().getLength();
         int lastOffs = offs;
-        int y = r.y;
-        while ((r != null) && (y == r.y)) {
+        double y = r.getY();
+        while ((r != null) && (y == r.getY())) {
             // Skip invisible elements
-            if (r.height !=0) {
+            if (r.getHeight() !=0) {
                 offs = lastOffs;
             }
             lastOffs += 1;
@@ -657,27 +733,44 @@
      * @return the position &gt;= 0 if the request can be computed, otherwise
      *  a value of -1 will be returned.
      * @exception BadLocationException if the offset is out of range
+     *
+     * @deprecated replaced by
+     *     {@link #getPositionAbove(JTextComponent, int, float)}
      */
-    public static final int getPositionAbove(JTextComponent c, int offs, int x) throws BadLocationException {
+    @Deprecated(since = "9")
+    public static final int getPositionAbove(JTextComponent c, int offs, int x)
+            throws BadLocationException
+    {
+        return getPositionAbove(c, offs, x, false);
+    }
+
+    static final int getPositionAbove(JTextComponent c, int offs, float x,
+                                      boolean useFPAPI) throws BadLocationException
+    {
         int lastOffs = getRowStart(c, offs) - 1;
         if (lastOffs < 0) {
             return -1;
         }
-        int bestSpan = Integer.MAX_VALUE;
-        int y = 0;
-        Rectangle r = null;
+        double bestSpan = Integer.MAX_VALUE;
+        double y = 0;
+        Rectangle2D r = null;
         if (lastOffs >= 0) {
-            r = c.modelToView(lastOffs);
-            y = r.y;
+            r = useFPAPI ? c.modelToView2D(lastOffs) : c.modelToView(lastOffs);
+            y = r.getY();
         }
-        while ((r != null) && (y == r.y)) {
-            int span = Math.abs(r.x - x);
+        while ((r != null) && (y == r.getY())) {
+            double span = Math.abs(r.getX() - x);
             if (span < bestSpan) {
                 offs = lastOffs;
                 bestSpan = span;
             }
             lastOffs -= 1;
-            r = (lastOffs >= 0) ? c.modelToView(lastOffs) : null;
+
+            if ((lastOffs >= 0)) {
+                r = useFPAPI ? c.modelToView2D(lastOffs) : c.modelToView(lastOffs);
+            } else {
+                r = null;
+            }
         }
         return offs;
     }
@@ -694,10 +787,12 @@
      * @return the position {@code >= 0} if the request can be computed, otherwise
      *  a value of -1 will be returned.
      * @exception BadLocationException if the offset is out of range
+     *
+     * @since 9
      */
     public static final int getPositionAbove(JTextComponent c, int offs, float x)
             throws BadLocationException {
-        return getPositionAbove(c, offs, (int) x);
+        return getPositionAbove(c, offs, x, true);
     }
 
     /**
@@ -712,28 +807,45 @@
      * @return the position &gt;= 0 if the request can be computed, otherwise
      *  a value of -1 will be returned.
      * @exception BadLocationException if the offset is out of range
+     *
+     * @deprecated replaced by
+     *     {@link #getPositionBelow(JTextComponent, int, float)}
      */
-    public static final int getPositionBelow(JTextComponent c, int offs, int x) throws BadLocationException {
+    @Deprecated(since = "9")
+    public static final int getPositionBelow(JTextComponent c, int offs, int x)
+            throws BadLocationException
+    {
+        return getPositionBelow(c, offs, x, false);
+    }
+
+    static final int getPositionBelow(JTextComponent c, int offs, float x,
+                                      boolean useFPAPI) throws BadLocationException
+    {
         int lastOffs = getRowEnd(c, offs) + 1;
         if (lastOffs <= 0) {
             return -1;
         }
-        int bestSpan = Integer.MAX_VALUE;
+        double bestSpan = Integer.MAX_VALUE;
         int n = c.getDocument().getLength();
-        int y = 0;
-        Rectangle r = null;
+        double y = 0;
+        Rectangle2D r = null;
         if (lastOffs <= n) {
-            r = c.modelToView(lastOffs);
-            y = r.y;
+            r = useFPAPI ? c.modelToView2D(lastOffs) : c.modelToView(lastOffs);
+            y = r.getY();
         }
-        while ((r != null) && (y == r.y)) {
-            int span = Math.abs(x - r.x);
+        while ((r != null) && (y == r.getY())) {
+            double span = Math.abs(x - r.getX());
             if (span < bestSpan) {
                 offs = lastOffs;
                 bestSpan = span;
             }
             lastOffs += 1;
-            r = (lastOffs <= n) ? c.modelToView(lastOffs) : null;
+
+            if (lastOffs <= n) {
+                r = useFPAPI ? c.modelToView2D(lastOffs) : c.modelToView(lastOffs);
+            } else {
+                r = null;
+            }
         }
         return offs;
     }
@@ -750,10 +862,12 @@
      * @return the position {@code >= 0} if the request can be computed, otherwise
      *  a value of -1 will be returned.
      * @exception BadLocationException if the offset is out of range
+     *
+     * @since 9
      */
     public static final int getPositionBelow(JTextComponent c, int offs, float x)
             throws BadLocationException {
-        return getPositionBelow(c, offs, (int) x);
+        return getPositionBelow(c, offs, x, true);
     }
 
     /**
@@ -1029,7 +1143,23 @@
      */
     static int drawComposedText(View view, AttributeSet attr, Graphics g,
                                 int x, int y, int p0, int p1)
-                                     throws BadLocationException {
+            throws BadLocationException
+    {
+        return (int) drawComposedText(view, attr, g, x, y, p0, p1, false);
+    }
+
+    static float drawComposedText(View view, AttributeSet attr, Graphics g,
+                                  float x, float y, int p0, int p1)
+            throws BadLocationException
+    {
+        return drawComposedText(view, attr, g, x, y, p0, p1, true);
+    }
+
+    static float drawComposedText(View view, AttributeSet attr, Graphics g,
+                                  float x, float y, int p0, int p1,
+                                  boolean useFPAPI)
+            throws BadLocationException
+    {
         Graphics2D g2d = (Graphics2D)g;
         AttributedString as = (AttributedString)attr.getAttribute(
             StyleConstants.ComposedTextAttribute);
@@ -1039,8 +1169,7 @@
             return x;
 
         AttributedCharacterIterator aci = as.getIterator(null, p0, p1);
-        return x + (int)SwingUtilities2.drawString(
-                             getJComponent(view), g2d,aci,x,y);
+        return x + SwingUtilities2.drawString(getJComponent(view), g2d, aci, x, y);
     }
 
     /**
--- a/jdk/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java	Wed Oct 19 08:06:10 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java	Thu Oct 20 12:18:15 2016 +0300
@@ -25,8 +25,12 @@
 package javax.swing.text;
 
 import java.awt.*;
+import java.awt.font.FontRenderContext;
 import java.lang.ref.SoftReference;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import javax.swing.event.*;
+import static javax.swing.text.PlainView.isFPMethodOverriden;
 
 /**
  * View of plain text (text with only one font and color)
@@ -87,17 +91,6 @@
     }
 
     /**
-     * Returns the tab size set for the document, defaulting to 8.
-     *
-     * @implSpec This implementation calls {@link #getTabSize() getTabSize()}.
-     *
-     * @return the tab size
-     */
-    protected float getFractionalTabSize() {
-        return getTabSize();
-    }
-
-    /**
      * Renders a line of text, suppressing whitespace at the end
      * and expanding any tabs.  This is implemented to make calls
      * to the methods <code>drawUnselectedText</code> and
@@ -111,8 +104,17 @@
      * @param y the starting Y position &gt;= 0
      * @see #drawUnselectedText
      * @see #drawSelectedText
+     *
+     * @deprecated replaced by
+     *     {@link #drawLine(int, int, Graphics2D, float, float)}
      */
+    @Deprecated(since = "9")
     protected void drawLine(int p0, int p1, Graphics g, int x, int y) {
+        drawLineImpl(p0, p1, g, x, y, false);
+    }
+
+    private void drawLineImpl(int p0, int p1, Graphics g, float x, float y,
+                              boolean useFPAPI) {
         Element lineMap = getElement();
         Element line = lineMap.getElement(lineMap.getElementIndex(p0));
         Element elem;
@@ -143,10 +145,6 @@
      * <code>drawSelectedText</code> so that the way selected and
      * unselected text are rendered can be customized.
      *
-     * @implSpec This implementation calls
-     * {@link #drawLine(int, int, Graphics, int, int)
-     * drawLine(p0, p1, (Graphics) g, (int) x, (int) y)}.
-     *
      * @param p0 the starting document location to use &gt;= 0
      * @param p1 the ending document location to use &gt;= p1
      * @param g the graphics context
@@ -154,12 +152,17 @@
      * @param y the starting Y position &gt;= 0
      * @see #drawUnselectedText
      * @see #drawSelectedText
+     *
+     * @since 9
      */
     protected void drawLine(int p0, int p1, Graphics2D g, float x, float y) {
-        drawLine(p0, p1, (Graphics) g, (int) x, (int) y);
+        drawLineImpl(p0, p1, g, x, y, true);
     }
 
-    private int drawText(Element elem, int p0, int p1, Graphics g, int x, int y) throws BadLocationException {
+    private float drawText(Element elem, int p0, int p1, Graphics g,
+                           float x, float y)
+            throws BadLocationException
+    {
         p1 = Math.min(getDocument().getLength(), p1);
         AttributeSet attr = elem.getAttributes();
 
@@ -171,23 +174,23 @@
         } else {
             if (sel0 == sel1 || selected == unselected) {
                 // no selection, or it is invisible
-                x = drawUnselectedText(g, x, y, p0, p1);
+                x = callDrawUnselectedText(g, x, y, p0, p1);
             } else if ((p0 >= sel0 && p0 <= sel1) && (p1 >= sel0 && p1 <= sel1)) {
-                x = drawSelectedText(g, x, y, p0, p1);
+                x = callDrawSelectedText(g, x, y, p0, p1);
             } else if (sel0 >= p0 && sel0 <= p1) {
                 if (sel1 >= p0 && sel1 <= p1) {
-                    x = drawUnselectedText(g, x, y, p0, sel0);
-                    x = drawSelectedText(g, x, y, sel0, sel1);
-                    x = drawUnselectedText(g, x, y, sel1, p1);
+                    x = callDrawUnselectedText(g, x, y, p0, sel0);
+                    x = callDrawSelectedText(g, x, y, sel0, sel1);
+                    x = callDrawUnselectedText(g, x, y, sel1, p1);
                 } else {
-                    x = drawUnselectedText(g, x, y, p0, sel0);
-                    x = drawSelectedText(g, x, y, sel0, p1);
+                    x = callDrawUnselectedText(g, x, y, p0, sel0);
+                    x = callDrawSelectedText(g, x, y, sel0, p1);
                 }
             } else if (sel1 >= p0 && sel1 <= p1) {
-                x = drawSelectedText(g, x, y, p0, sel1);
-                x = drawUnselectedText(g, x, y, sel1, p1);
+                x = callDrawSelectedText(g, x, y, p0, sel1);
+                x = callDrawUnselectedText(g, x, y, sel1, p1);
             } else {
-                x = drawUnselectedText(g, x, y, p0, p1);
+                x = callDrawUnselectedText(g, x, y, p0, p1);
             }
         }
 
@@ -205,14 +208,36 @@
      * @param p1 the ending position in the model &gt;= p0
      * @return the X location of the end of the range &gt;= 0
      * @exception BadLocationException if the range is invalid
+     *
+     * @deprecated replaced by
+     *     {@link #drawUnselectedText(Graphics2D, float, float, int, int)}
      */
+    @Deprecated(since = "9")
     protected int drawUnselectedText(Graphics g, int x, int y,
-                                     int p0, int p1) throws BadLocationException {
+                                     int p0, int p1) throws BadLocationException
+    {
+        return (int) drawUnselectedTextImpl(g, x, y, p0, p1, false);
+    }
+
+    private float callDrawUnselectedText(Graphics g, float x, float y,
+                                         int p0, int p1)
+                                         throws BadLocationException
+    {
+        return drawUnselectedTextOverridden && g instanceof Graphics2D
+                ? drawUnselectedText((Graphics2D) g, x, y, p0, p1)
+                : drawUnselectedText(g, (int) x, (int) y, p0, p1);
+    }
+
+    private float drawUnselectedTextImpl(Graphics g, float x, float y,
+                                         int p0, int p1, boolean useFPAPI)
+            throws BadLocationException
+    {
         g.setColor(unselected);
         Document doc = getDocument();
         Segment segment = SegmentCache.getSharedSegment();
         doc.getText(p0, p1 - p0, segment);
-        int ret = Utilities.drawTabbedText(this, segment, x, y, g, this, p0);
+        float ret = Utilities.drawTabbedText(this, segment, x, y, g, this, p0,
+                                             null, useFPAPI);
         SegmentCache.releaseSharedSegment(segment);
         return ret;
     }
@@ -221,10 +246,6 @@
      * Renders the given range in the model as normal unselected
      * text.
      *
-     * @implSpec This implementation calls
-     * {@link #drawUnselectedText(Graphics, int, int, int, int)
-     * drawUnselectedText((Graphics)g, (int) x, (int) y, p0, p1)}.
-     *
      * @param g the graphics context
      * @param x the starting X coordinate &gt;= 0
      * @param y the starting Y coordinate &gt;= 0
@@ -232,10 +253,12 @@
      * @param p1 the ending position in the model &gt;= p0
      * @return the X location of the end of the range &gt;= 0
      * @exception BadLocationException if the range is invalid
+     *
+     * @since 9
      */
     protected float drawUnselectedText(Graphics2D g, float x, float y,
                                      int p0, int p1) throws BadLocationException {
-        return drawUnselectedText((Graphics) g, (int) x, (int) y, p0, p1);
+        return drawUnselectedTextImpl(g, x, y, p0, p1, true);
     }
     /**
      * Renders the given range in the model as selected text.  This
@@ -250,14 +273,37 @@
      * @param p1 the ending position in the model &gt;= p0
      * @return the location of the end of the range.
      * @exception BadLocationException if the range is invalid
+     *
+     * @deprecated replaced by
+     *     {@link #drawSelectedText(Graphics2D, float, float, int, int)}
      */
-    protected int drawSelectedText(Graphics g, int x,
-                                   int y, int p0, int p1) throws BadLocationException {
+    @Deprecated(since = "9")
+    protected int drawSelectedText(Graphics g, int x, int y, int p0, int p1)
+            throws BadLocationException
+    {
+        return (int) drawSelectedTextImpl(g, x, y, p0, p1, false);
+    }
+
+    private float callDrawSelectedText(Graphics g, float x, float y,
+                                       int p0, int p1)
+                                       throws BadLocationException
+    {
+        return drawSelectedTextOverridden && g instanceof Graphics2D
+                ? drawSelectedText((Graphics2D) g, x, y, p0, p1)
+                : drawSelectedText(g, (int) x, (int) y, p0, p1);
+    }
+
+    private float drawSelectedTextImpl(Graphics g, float x, float y,
+                                       int p0, int p1,
+                                       boolean useFPAPI)
+            throws BadLocationException
+    {
         g.setColor(selected);
         Document doc = getDocument();
         Segment segment = SegmentCache.getSharedSegment();
         doc.getText(p0, p1 - p0, segment);
-        int ret = Utilities.drawTabbedText(this, segment, x, y, g, this, p0);
+        float ret = Utilities.drawTabbedText(this, segment, x, y, g, this, p0,
+                                             null, useFPAPI);
         SegmentCache.releaseSharedSegment(segment);
         return ret;
     }
@@ -268,10 +314,6 @@
      * the hosting component.  It assumes the highlighter will render
      * the selected background.
      *
-     * @implSpec This implementation calls
-     * {@link #drawSelectedText(Graphics, int, int, int, int)
-     * drawSelectedText((Graphics)g, (int) x, (int) y, p0, p1)}.
-     *
      * @param g the graphics context
      * @param x the starting X coordinate &gt;= 0
      * @param y the starting Y coordinate &gt;= 0
@@ -279,10 +321,12 @@
      * @param p1 the ending position in the model &gt;= p0
      * @return the location of the end of the range.
      * @exception BadLocationException if the range is invalid
+     *
+     * @since 9
      */
     protected float drawSelectedText(Graphics2D g, float x, float y,
                                      int p0, int p1) throws BadLocationException {
-        return drawSelectedText((Graphics) g, (int) x, (int) y, p0, p1);
+        return drawSelectedTextImpl(g, x, y, p0, p1, true);
     }
     /**
      * Gives access to a buffer that can be used to fetch
@@ -395,7 +439,13 @@
         Component host = getContainer();
         Font f = host.getFont();
         metrics = host.getFontMetrics(f);
-        tabSize = getTabSize() * metrics.charWidth('m');
+        if (useFloatingPointAPI) {
+            FontRenderContext frc = metrics.getFontRenderContext();
+            float tabWidth = (float) f.getStringBounds("m", frc).getWidth();
+            tabSize = getTabSize() * tabWidth;
+        } else {
+            tabSize = getTabSize() * metrics.charWidth('m');
+        }
     }
 
     // --- TabExpander methods ------------------------------------------
@@ -413,7 +463,7 @@
     public float nextTabStop(float x, int tabOffset) {
         if (tabSize == 0)
             return x;
-        int ntabs = ((int) x - tabBase) / tabSize;
+        float ntabs = (x - tabBase) / tabSize;
         return tabBase + ((ntabs + 1) * tabSize);
     }
 
@@ -591,7 +641,7 @@
     Segment lineBuffer;
     boolean widthChanging;
     int tabBase;
-    int tabSize;
+    float tabSize;
     boolean wordWrap;
 
     int sel0;
@@ -668,6 +718,7 @@
             int end = getEndOffset();
             int p0 = start;
             int[] lineEnds = getLineEnds();
+            boolean useDrawLineFP = drawLineOverridden && g instanceof Graphics2D;
             for (int i = 0; i < lineCount; i++) {
                 int p1 = (lineEnds == null) ? end :
                                              start + lineEnds[i];
@@ -677,8 +728,11 @@
                                   : p1;
                     dh.paintLayeredHighlights(g, p0, hOffset, a, host, this);
                 }
-                drawLine(p0, p1, g, x, y);
-
+                if (useDrawLineFP) {
+                    drawLine(p0, p1, (Graphics2D) g, (float) x, (float) y);
+                } else {
+                    drawLine(p0, p1, g, x, y);
+                }
                 p0 = p1;
                 y += metrics.getHeight();
             }
@@ -929,4 +983,47 @@
         int lineCount;
         SoftReference<int[]> lineCache = null;
     }
+
+    private final boolean drawLineOverridden;
+    private final boolean drawSelectedTextOverridden;
+    private final boolean drawUnselectedTextOverridden;
+    private final boolean useFloatingPointAPI;
+
+    {
+        final Class<?> CLS = getClass();
+        final Class<?> INT = Integer.TYPE;
+        final Class<?> FP = Float.TYPE;
+
+        drawLineOverridden = AccessController
+                .doPrivileged(new PrivilegedAction<Boolean>() {
+            @Override
+            public Boolean run() {
+                Class<?>[] intTypes = {INT, INT, Graphics.class, INT, INT};
+                Class<?>[] fpTypes = {INT, INT, Graphics2D.class, FP, FP};
+                return isFPMethodOverriden("drawLine", CLS, intTypes, fpTypes);
+            }
+        });
+
+        drawUnselectedTextOverridden = AccessController
+                .doPrivileged(new PrivilegedAction<Boolean>() {
+            @Override
+            public Boolean run() {
+                Class<?>[] intTypes = {Graphics.class, INT, INT, INT, INT};
+                Class<?>[] fpTypes = {Graphics2D.class, FP, FP, INT, INT};
+                return isFPMethodOverriden("drawUnselectedText", CLS, intTypes, fpTypes);
+            }
+        });
+
+        drawSelectedTextOverridden = AccessController
+                .doPrivileged(new PrivilegedAction<Boolean>() {
+            @Override
+            public Boolean run() {
+                Class<?>[] intTypes = {Graphics.class, INT, INT, INT, INT};
+                Class<?>[] fpTypes = {Graphics2D.class, FP, FP, INT, INT};
+                return isFPMethodOverriden("drawSelectedText", CLS, intTypes, fpTypes);
+            }
+        });
+
+        useFloatingPointAPI = drawUnselectedTextOverridden || drawSelectedTextOverridden;
+    }
 }
--- a/jdk/src/java.desktop/share/classes/sun/swing/SwingUtilities2.java	Wed Oct 19 08:06:10 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/swing/SwingUtilities2.java	Thu Oct 20 12:18:15 2016 +0300
@@ -30,6 +30,7 @@
 import static java.awt.RenderingHints.*;
 import java.awt.event.*;
 import java.awt.font.*;
+import java.awt.geom.Rectangle2D;
 import java.awt.geom.AffineTransform;
 import static java.awt.geom.AffineTransform.TYPE_FLIP;
 import static java.awt.geom.AffineTransform.TYPE_TRANSLATION;
@@ -723,10 +724,31 @@
                                  int length,
                                  int x,
                                  int y) {
+        return (int) drawChars(c, g, data, offset, length, x, y, false);
+    }
+
+    public static float drawChars(JComponent c, Graphics g,
+                                 char[] data,
+                                 int offset,
+                                 int length,
+                                 float x,
+                                 float y) {
+        return drawChars(c, g, data, offset, length, x, y, true);
+    }
+
+    public static float drawChars(JComponent c, Graphics g,
+                                 char[] data,
+                                 int offset,
+                                 int length,
+                                 float x,
+                                 float y,
+                                 boolean useFPAPI) {
         if ( length <= 0 ) { //no need to paint empty strings
             return x;
         }
-        int nextX = x + getFontMetrics(c, g).charsWidth(data, offset, length);
+        float nextX = x + getFontCharsWidth(data, offset, length,
+                                            getFontMetrics(c, g),
+                                            useFPAPI);
         if (isPrinting(g)) {
             Graphics2D g2d = getGraphics2D(g);
             if (g2d != null) {
@@ -766,8 +788,14 @@
         Object aaHint = (c == null)
                             ? null
                             : c.getClientProperty(KEY_TEXT_ANTIALIASING);
-        if (aaHint != null && (g instanceof Graphics2D)) {
-            Graphics2D g2 = (Graphics2D)g;
+
+        if (!(g instanceof Graphics2D)) {
+            g.drawChars(data, offset, length, (int) x, (int) y);
+            return nextX;
+        }
+
+        Graphics2D g2 = (Graphics2D) g;
+        if (aaHint != null) {
 
             Object oldContrast = null;
             Object oldAAValue = g2.getRenderingHint(KEY_TEXT_ANTIALIASING);
@@ -788,7 +816,7 @@
                 }
             }
 
-            g.drawChars(data, offset, length, x, y);
+            g2.drawString(new String(data, offset, length), x, y);
 
             if (oldAAValue != null) {
                 g2.setRenderingHint(KEY_TEXT_ANTIALIASING, oldAAValue);
@@ -798,19 +826,59 @@
             }
         }
         else {
-            g.drawChars(data, offset, length, x, y);
+            g2.drawString(new String(data, offset, length), x, y);
         }
         return nextX;
     }
 
+    public static float getFontCharWidth(char c, FontMetrics fm,
+                                         boolean useFPAPI)
+    {
+        return getFontCharsWidth(new char[]{c}, 0, 1, fm, useFPAPI);
+    }
+
+    public static float getFontCharsWidth(char[] data, int offset, int len,
+                                          FontMetrics fm,
+                                          boolean useFPAPI)
+    {
+        return len == 0 ? 0 : getFontStringWidth(new String(data, offset, len),
+                                                 fm, useFPAPI);
+    }
+
+    public static float getFontStringWidth(String data, FontMetrics fm,
+                                           boolean useFPAPI)
+    {
+        if (useFPAPI) {
+            Rectangle2D bounds = fm.getFont()
+                    .getStringBounds(data, fm.getFontRenderContext());
+            return (float) bounds.getWidth();
+        } else {
+            return fm.stringWidth(data);
+        }
+    }
+
     /*
      * see documentation for drawChars
      * returns the advance
      */
     public static float drawString(JComponent c, Graphics g,
                                    AttributedCharacterIterator iterator,
-                                   int x,
-                                   int y) {
+                                   int x, int y)
+    {
+        return drawStringImpl(c, g, iterator, x, y);
+    }
+
+    public static float drawString(JComponent c, Graphics g,
+                                   AttributedCharacterIterator iterator,
+                                   float x, float y)
+    {
+        return drawStringImpl(c, g, iterator, x, y);
+    }
+
+    private static float drawStringImpl(JComponent c, Graphics g,
+                                   AttributedCharacterIterator iterator,
+                                   float x, float y)
+    {
 
         float retVal;
         boolean isPrinting = isPrinting(g);
@@ -825,8 +893,8 @@
 
         Graphics2D g2d = getGraphics2D(g);
         if (g2d == null) {
-            g.drawString(iterator,x,y); //for the cases where advance
-                                        //matters it should not happen
+            g.drawString(iterator, (int)x, (int)y); //for the cases where advance
+                                                    //matters it should not happen
             retVal = x;
 
         } else {
--- a/jdk/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java	Wed Oct 19 08:06:10 2016 -0700
+++ b/jdk/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java	Thu Oct 20 12:18:15 2016 +0300
@@ -41,13 +41,13 @@
 
 import javax.accessibility.*;
 import com.sun.java.accessibility.util.*;
+import java.awt.geom.Rectangle2D;
 import sun.awt.AWTAccessor;
 import sun.awt.AppContext;
 import sun.awt.SunToolkit;
 
 import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CountDownLatch;
 
 /*
  * Note: This class has to be public.  It's loaded from the VM like this:
@@ -1754,7 +1754,7 @@
                     if (child instanceof JTextComponent) {
                         JTextComponent text = (JTextComponent) child;
                         try {
-                            r = text.modelToView(text.getCaretPosition());
+                            r = text.modelToView2D(text.getCaretPosition()).getBounds();
                             if (r != null) {
                                 Point p = text.getLocationOnScreen();
                                 r.translate(p.x, p.y);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/text/Caret/8163124/CaretFloatingPointAPITest.java	Thu Oct 20 12:18:15 2016 +0300
@@ -0,0 +1,447 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.geom.Line2D;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ChangeListener;
+import javax.swing.plaf.TextUI;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Caret;
+import javax.swing.text.DefaultHighlighter;
+import javax.swing.text.Document;
+import javax.swing.text.Highlighter;
+import javax.swing.text.JTextComponent;
+import javax.swing.text.Position;
+
+/*
+ * @test
+ * @bug 8163175
+ * @summary PlainView.modelToView() method should return Rectangle2D
+ * @run main/manual CaretFloatingPointAPITest
+ */
+public class CaretFloatingPointAPITest {
+
+    private static volatile boolean testResult = false;
+    private static volatile CountDownLatch countDownLatch;
+    private static final String INSTRUCTIONS = "INSTRUCTIONS:\n\n"
+            + "Verify that cursor position is not rounded on HiDPI display.\n\n"
+            + "If the display does not support HiDPI mode press PASS.\n\n"
+            + "1. Press the Right-Arrow key several times to move the red caret"
+            + " in the text field.\n"
+            + "2. Check that the caret has the same position between chars"
+            + " in diffrent locations.\n\n"
+            + "If so, press PASS, else press FAIL.\n";
+
+    public static void main(String args[]) throws Exception {
+        countDownLatch = new CountDownLatch(1);
+
+        SwingUtilities.invokeLater(CaretFloatingPointAPITest::createUI);
+        countDownLatch.await(15, TimeUnit.MINUTES);
+
+        if (!testResult) {
+            throw new RuntimeException("Test fails!");
+        }
+    }
+
+    private static void createUI() {
+
+        final JFrame mainFrame = new JFrame("Metal L&F icons test");
+        GridBagLayout layout = new GridBagLayout();
+        JPanel mainControlPanel = new JPanel(layout);
+        JPanel resultButtonPanel = new JPanel(layout);
+
+        GridBagConstraints gbc = new GridBagConstraints();
+
+        JTextField textField = new JTextField("aaaaaaaaaaaaaaaaaaaaaaa");
+        Dimension size = new Dimension(400, 100);
+        textField.setPreferredSize(size);
+        textField.setFont(textField.getFont().deriveFont(28.0f));
+        textField.setCaretColor(Color.RED);
+        textField.setCaret(new CustomCaret());
+        gbc.gridx = 0;
+        gbc.gridy = 0;
+        gbc.insets = new Insets(5, 15, 5, 15);
+        gbc.fill = GridBagConstraints.HORIZONTAL;
+        mainControlPanel.add(textField, gbc);
+
+        JTextArea instructionTextArea = new JTextArea();
+        instructionTextArea.setText(INSTRUCTIONS);
+        instructionTextArea.setEditable(false);
+        instructionTextArea.setBackground(Color.white);
+
+        gbc.gridx = 0;
+        gbc.gridy = 1;
+        gbc.fill = GridBagConstraints.HORIZONTAL;
+        mainControlPanel.add(instructionTextArea, gbc);
+
+        JButton passButton = new JButton("Pass");
+        passButton.setActionCommand("Pass");
+        passButton.addActionListener((ActionEvent e) -> {
+            testResult = true;
+            mainFrame.dispose();
+            countDownLatch.countDown();
+
+        });
+
+        JButton failButton = new JButton("Fail");
+        failButton.setActionCommand("Fail");
+        failButton.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                mainFrame.dispose();
+                countDownLatch.countDown();
+            }
+        });
+
+        gbc.gridx = 0;
+        gbc.gridy = 0;
+
+        resultButtonPanel.add(passButton, gbc);
+
+        gbc.gridx = 1;
+        gbc.gridy = 0;
+        resultButtonPanel.add(failButton, gbc);
+
+        gbc.gridx = 0;
+        gbc.gridy = 2;
+        mainControlPanel.add(resultButtonPanel, gbc);
+
+        mainFrame.add(mainControlPanel);
+        mainFrame.pack();
+
+        mainFrame.addWindowListener(new WindowAdapter() {
+
+            @Override
+            public void windowClosing(WindowEvent e) {
+                mainFrame.dispose();
+                countDownLatch.countDown();
+            }
+        });
+        mainFrame.setVisible(true);
+    }
+
+    static class CustomCaret implements Caret {
+
+        private JTextComponent component;
+        private boolean visible;
+        private boolean selectionVisible = true;
+        int blinkRate;
+        int dot;
+        int mark;
+        Position.Bias dotBias;
+        Position.Bias markBias;
+        Object selectionTag;
+        Point2D magicCaretPosition;
+
+        private MouseListener mouseListener = new CaretMouseListener();
+
+        @Override
+        public void install(JTextComponent c) {
+            this.component = c;
+            c.addMouseListener(mouseListener);
+        }
+
+        @Override
+        public void deinstall(JTextComponent c) {
+            c.removeMouseListener(mouseListener);
+            this.component = null;
+        }
+
+        @Override
+        public void paint(Graphics g) {
+
+            if (component == null) {
+                return;
+            }
+
+            int dot = getDot();
+            Rectangle2D r = null;
+            try {
+                r = component.modelToView2D(dot);
+            } catch (BadLocationException e) {
+                return;
+            }
+
+            if (r == null) {
+                return;
+            }
+
+            Rectangle2D cr = getCaretRectangle(r);
+            repaint(cr.getBounds());
+
+            g.setColor(component.getCaretColor());
+            float cx = (float) cr.getX();
+            float cy = (float) cr.getY();
+            float cw = (float) cr.getWidth();
+            float ch = (float) cr.getHeight();
+            float c = cx + cw / 2;
+
+            Graphics2D g2d = (Graphics2D) g;
+            g2d.draw(new Line2D.Float(c, cy, c, cy + ch));
+            g2d.draw(new Line2D.Float(cx, cy, cx + cw, cy));
+            g2d.draw(new Line2D.Float(cx, cy + ch, cx + cw, cy + ch));
+        }
+
+        void repaint(Rectangle r) {
+            component.repaint(r);
+        }
+
+        Rectangle2D getCaretRectangle(Rectangle2D r) {
+            int d = 3;
+            double cx = r.getX() - d;
+            double cy = r.getY();
+            double cw = 2 * d;
+            double ch = r.getHeight();
+            return new Rectangle2D.Double(cx, cy, cw, ch);
+        }
+
+        @Override
+        public void addChangeListener(ChangeListener l) {
+        }
+
+        @Override
+        public void removeChangeListener(ChangeListener l) {
+        }
+
+        @Override
+        public boolean isVisible() {
+            return visible;
+        }
+
+        @Override
+        public void setVisible(boolean v) {
+            this.visible = true;
+        }
+
+        @Override
+        public boolean isSelectionVisible() {
+            return selectionVisible;
+        }
+
+        @Override
+        public void setSelectionVisible(boolean v) {
+            this.selectionVisible = v;
+            updateSelection();
+        }
+
+        @Override
+        public void setMagicCaretPosition(Point p) {
+            magicCaretPosition = p;
+        }
+
+        @Override
+        public Point getMagicCaretPosition() {
+            if (magicCaretPosition != null) {
+                return new Point((int) magicCaretPosition.getX(),
+                                 (int) magicCaretPosition.getY());
+            }
+            return null;
+        }
+
+        @Override
+        public void setBlinkRate(int rate) {
+            this.blinkRate = rate;
+        }
+
+        @Override
+        public int getBlinkRate() {
+            return blinkRate;
+        }
+
+        @Override
+        public int getDot() {
+            return dot;
+        }
+
+        @Override
+        public int getMark() {
+            return mark;
+        }
+
+        @Override
+        public void setDot(int dot) {
+            setDot(dot, Position.Bias.Forward);
+        }
+
+        private void setDot(int dot, Position.Bias bias) {
+            handleSetDot(dot, bias);
+            updateSelection();
+        }
+
+        @Override
+        public void moveDot(int dot) {
+            moveDot(dot, Position.Bias.Forward);
+        }
+
+        private void moveDot(int dot, Position.Bias bias) {
+            changeCaretPosition(dot, bias);
+            updateSelection();
+        }
+
+        void handleSetDot(int dot, Position.Bias dotBias) {
+
+            if (component == null) {
+                return;
+            }
+
+            Document doc = component.getDocument();
+            if (doc != null) {
+                dot = Math.min(dot, doc.getLength());
+            }
+
+            dot = Math.max(dot, 0);
+
+            if (dot == 0) {
+                dotBias = Position.Bias.Forward;
+            }
+
+            mark = dot;
+
+            if (this.dot != dot || this.dotBias != dotBias) {
+                changeCaretPosition(dot, dotBias);
+                updateSelection();
+            }
+
+            this.markBias = this.dotBias;
+        }
+
+        void changeCaretPosition(int dot, Position.Bias dotBias) {
+            this.dot = dot;
+            this.dotBias = dotBias;
+            setMagicCaretPosition(null);
+            SwingUtilities.invokeLater(this::repaintNewCaret);
+        }
+
+        private void updateSelection() {
+            Highlighter h = component.getHighlighter();
+            if (h != null) {
+                int p0 = Math.min(dot, mark);
+                int p1 = Math.max(dot, mark);
+
+                if (p0 == p1 || !selectionVisible) {
+                    if (selectionTag != null) {
+                        h.removeHighlight(selectionTag);
+                        selectionTag = null;
+                    }
+                } else {
+                    try {
+                        if (selectionTag != null) {
+                            h.changeHighlight(selectionTag, p0, p1);
+                        } else {
+                            Highlighter.HighlightPainter p = getSelectionPainter();
+                            selectionTag = h.addHighlight(p0, p1, p);
+                        }
+                    } catch (BadLocationException e) {
+                        throw new RuntimeException(e);
+                    }
+                }
+            }
+        }
+
+        void repaintNewCaret() {
+            if (component != null) {
+                TextUI mapper = component.getUI();
+                Document doc = component.getDocument();
+                if ((mapper != null) && (doc != null)) {
+                    Rectangle2D newLoc;
+                    try {
+                        newLoc = mapper.modelToView2D(component, this.dot, this.dotBias);
+                    } catch (BadLocationException e) {
+                        newLoc = null;
+                    }
+                    if (newLoc != null) {
+                        adjustVisibility(newLoc.getBounds());
+                        if (getMagicCaretPosition() == null) {
+                            setMagicCaretPosition(new Point((int) newLoc.getX(),
+                                                            (int) newLoc.getY()));
+                        }
+                    }
+                    damage(newLoc.getBounds());
+                }
+            }
+        }
+
+        protected Highlighter.HighlightPainter getSelectionPainter() {
+            return DefaultHighlighter.DefaultPainter;
+        }
+
+        protected void adjustVisibility(Rectangle nloc) {
+            if (component == null) {
+                return;
+            }
+            if (SwingUtilities.isEventDispatchThread()) {
+                component.scrollRectToVisible(nloc);
+            } else {
+                SwingUtilities.invokeLater(() -> {
+                    component.scrollRectToVisible(nloc);
+                });
+            }
+        }
+
+        protected synchronized void damage(Rectangle r) {
+            if (r != null && component != null) {
+                component.repaint(r);
+            }
+        }
+
+        private class CaretMouseListener extends MouseAdapter {
+
+            @Override
+            public void mousePressed(MouseEvent e) {
+                Point pt = new Point(e.getX(), e.getY());
+                Position.Bias[] biasRet = new Position.Bias[1];
+                int pos = component.getUI().viewToModel(component, pt, biasRet);
+                if (biasRet[0] == null) {
+                    biasRet[0] = Position.Bias.Forward;
+                }
+                if (pos >= 0) {
+                    setDot(pos);
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/text/JTextComponent/8156217/TextSelectionTest.java	Thu Oct 20 12:18:15 2016 +0300
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JTextArea;
+import javax.swing.SwingUtilities;
+import javax.swing.text.JTextComponent;
+
+/**
+ * @test
+ * @bug 8156217
+ * @summary Selected text is shifted on HiDPI display
+ * @run main/manual/othervm -Dsun.java2d.uiScale=2 TextSelectionTest
+ */
+public class TextSelectionTest {
+
+    private static final String INSTRUCTIONS = "This is a manual test.\n"
+            + "\n"
+            + "Select the current text from the end to the beginning.\n"
+            + "\n"
+            + "If the text is slightly shiftted from one side to another\n"
+            + "and back during selection press Fail.\n"
+            + "Otherwise, press Pass.";
+
+    private static final CountDownLatch latch = new CountDownLatch(1);
+    private static volatile boolean passed = false;
+
+    public static void main(String[] args) throws Exception {
+        SwingUtilities.invokeAndWait(TextSelectionTest::createAndShowGUI);
+        latch.await(3, TimeUnit.MINUTES);
+        System.out.println("passed: " + passed);
+        if (!passed) {
+            throw new RuntimeException("Test fails!");
+        }
+    }
+
+    private static void createAndShowGUI() {
+
+        JFrame frame = new JFrame("Follow the instructions below:");
+        frame.setSize(700, 500);
+        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+        JPanel panel = new JPanel(new BorderLayout());
+        JTextComponent textComponent = new JTextArea(INSTRUCTIONS);
+        textComponent.setEditable(false);
+        Font font = textComponent.getFont();
+        font = font.deriveFont(24.0f);
+        textComponent.setFont(font);
+        panel.add(textComponent, BorderLayout.CENTER);
+
+        JPanel buttonsPanel = new JPanel(new FlowLayout());
+        JButton passButton = new JButton("Pass");
+        passButton.addActionListener((e) -> {
+            passed = true;
+            latch.countDown();
+            frame.dispose();
+        });
+        JButton failsButton = new JButton("Fail");
+        failsButton.addActionListener((e) -> {
+            passed = false;
+            latch.countDown();
+            frame.dispose();
+        });
+
+        buttonsPanel.add(passButton);
+        buttonsPanel.add(failsButton);
+        panel.add(buttonsPanel, BorderLayout.SOUTH);
+
+        frame.getContentPane().add(panel);
+
+        frame.addWindowListener(new WindowAdapter() {
+
+            @Override
+            public void windowClosing(WindowEvent e) {
+                latch.countDown();
+            }
+        });
+        frame.setVisible(true);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/text/View/8156217/FPMethodCalledTest.java	Thu Oct 20 12:18:15 2016 +0300
@@ -0,0 +1,499 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.awt.FlowLayout;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Robot;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JPasswordField;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.plaf.metal.MetalLookAndFeel;
+import javax.swing.plaf.metal.MetalTextFieldUI;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Element;
+import javax.swing.text.PasswordView;
+import javax.swing.text.PlainView;
+import javax.swing.text.View;
+import javax.swing.text.WrappedPlainView;
+
+/**
+ * @test
+ * @bug 8156217
+ * @key headful
+ * @summary Selected text is shifted on HiDPI display
+ * @run main FPMethodCalledTest
+ */
+public class FPMethodCalledTest {
+
+    private static JFrame frame;
+    private static JTextField textField;
+
+    public static void main(String[] args) throws Exception {
+
+        for (Test test : TESTS) {
+            test(test);
+        }
+    }
+
+    static void test(final Test test) throws Exception {
+        try {
+            Robot robot = new Robot();
+            robot.setAutoDelay(50);
+            SwingUtilities.invokeAndWait(() -> {
+                createAndShowGUI(test);
+            });
+
+            robot.waitForIdle();
+
+            SwingUtilities.invokeAndWait(() -> {
+                textField.select(1, 3);
+            });
+
+            robot.waitForIdle();
+
+            SwingUtilities.invokeAndWait(() -> {
+                Resultable resultable = test.resultable;
+                if (!resultable.getResult()) {
+                    throw new RuntimeException("Test fails for: " + resultable);
+                }
+            });
+        } finally {
+            SwingUtilities.invokeAndWait(() -> {
+                if (frame != null) {
+                    frame.dispose();
+                }
+            });
+        }
+    }
+
+    static void createAndShowGUI(Test test) {
+
+        try {
+            UIManager.setLookAndFeel(new MetalLookAndFeel());
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        frame = new JFrame();
+        frame.setSize(300, 300);
+        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+        JPanel panel = new JPanel(new FlowLayout());
+
+        String text = "AAAAAAA";
+        textField = test.isPasswordField()
+                ? new JPasswordField(text)
+                : new JTextField(text);
+
+        textField.setUI(new MetalTextFieldUI() {
+
+            @Override
+            public View create(Element elem) {
+                return test.createView(elem);
+            }
+        });
+
+        panel.add(textField);
+        frame.getContentPane().add(panel);
+        frame.setVisible(true);
+    }
+
+    private static final Test[] TESTS = {
+        new Test() {
+            @Override
+            View createView(Element elem) {
+                PlainViewINTAPI view = new PlainViewINTAPI(elem);
+                resultable = view;
+                return view;
+            }
+        },
+        new Test() {
+            @Override
+            View createView(Element elem) {
+                PlainViewFPAPI view = new PlainViewFPAPI(elem);
+                resultable = view;
+                return view;
+            }
+        },
+        new Test() {
+            @Override
+            View createView(Element elem) {
+                PlainViewMixedAPI view = new PlainViewMixedAPI(elem);
+                resultable = view;
+                return view;
+            }
+        },
+        new Test() {
+            @Override
+            View createView(Element elem) {
+                WrappedPlainViewINTAPI view = new WrappedPlainViewINTAPI(elem);
+                resultable = view;
+                return view;
+            }
+        },
+        new Test() {
+            @Override
+            View createView(Element elem) {
+                WrappedPlainViewFPAPI view = new WrappedPlainViewFPAPI(elem);
+                resultable = view;
+                return view;
+            }
+        },
+        new Test() {
+            @Override
+            View createView(Element elem) {
+                WrappedPlainViewMixedAPI view = new WrappedPlainViewMixedAPI(elem);
+                resultable = view;
+                return view;
+            }
+        },
+        new Test(true) {
+
+            @Override
+            View createView(Element elem) {
+                PasswordViewINTAPI view = new PasswordViewINTAPI(elem);
+                resultable = view;
+                return view;
+            }
+        },
+        new Test(true) {
+
+            @Override
+            View createView(Element elem) {
+                PasswordViewFPAPI view = new PasswordViewFPAPI(elem);
+                resultable = view;
+                return view;
+            }
+        },
+        new Test(true) {
+
+            @Override
+            View createView(Element elem) {
+                PasswordViewMixedAPI view = new PasswordViewMixedAPI(elem);
+                resultable = view;
+                return view;
+            }
+        }
+    };
+
+    static interface Resultable {
+
+        boolean getResult();
+    }
+
+    static abstract class Test {
+
+        Resultable resultable;
+        final boolean isPasswordField;
+
+        public Test() {
+            this(false);
+        }
+
+        public Test(boolean isPasswordField) {
+            this.isPasswordField = isPasswordField;
+        }
+
+        boolean isPasswordField() {
+            return isPasswordField;
+        }
+
+        abstract View createView(Element elem);
+    }
+
+    static class PlainViewINTAPI extends PlainView implements Resultable {
+
+        boolean drawLine = false;
+        boolean drawSelected = false;
+        boolean drawUnselected = false;
+
+        public PlainViewINTAPI(Element elem) {
+            super(elem);
+        }
+
+        @Override
+        protected void drawLine(int lineIndex, Graphics g, int x, int y) {
+            drawLine = true;
+            super.drawLine(lineIndex, g, x, y);
+        }
+
+        @Override
+        protected int drawSelectedText(Graphics g, int x, int y,
+                int p0, int p1) throws BadLocationException {
+            drawSelected = true;
+            return super.drawSelectedText(g, x, y, p0, p1);
+        }
+
+        @Override
+        protected int drawUnselectedText(Graphics g, int x, int y,
+                int p0, int p1) throws BadLocationException {
+            drawUnselected = true;
+            return super.drawUnselectedText(g, x, y, p0, p1);
+        }
+
+        @Override
+        public boolean getResult() {
+            return drawLine && drawSelected && drawUnselected;
+        }
+    }
+
+    static class PlainViewFPAPI extends PlainView implements Resultable {
+
+        boolean drawLine = false;
+        boolean drawSelected = false;
+        boolean drawUnselected = false;
+
+        public PlainViewFPAPI(Element elem) {
+            super(elem);
+        }
+
+        @Override
+        protected void drawLine(int lineIndex, Graphics2D g, float x, float y) {
+            drawLine = true;
+            super.drawLine(lineIndex, g, x, y);
+        }
+
+        @Override
+        protected float drawSelectedText(Graphics2D g, float x, float y,
+                int p0, int p1) throws BadLocationException {
+            drawSelected = true;
+            return super.drawSelectedText(g, x, y, p0, p1);
+        }
+
+        @Override
+        protected float drawUnselectedText(Graphics2D g, float x, float y,
+                int p0, int p1) throws BadLocationException {
+            drawUnselected = true;
+            return super.drawUnselectedText(g, x, y, p0, p1);
+        }
+
+        @Override
+        public boolean getResult() {
+            return drawSelected;
+        }
+    }
+
+    static class PlainViewMixedAPI extends PlainView implements Resultable {
+
+        boolean isIntMethodCalled = false;
+        boolean isFPMethodCalled = false;
+
+        public PlainViewMixedAPI(Element elem) {
+            super(elem);
+        }
+
+        @Override
+        protected int drawSelectedText(Graphics g, int x, int y,
+                int p0, int p1) throws BadLocationException {
+            isIntMethodCalled = true;
+            return super.drawSelectedText(g, x, y, p0, p1);
+        }
+
+        @Override
+        protected float drawSelectedText(Graphics2D g, float x, float y,
+                int p0, int p1) throws BadLocationException {
+            isFPMethodCalled = true;
+            return super.drawSelectedText(g, x, y, p0, p1);
+        }
+
+        @Override
+        public boolean getResult() {
+            return !isIntMethodCalled && isFPMethodCalled;
+        }
+    }
+
+    static class WrappedPlainViewINTAPI extends WrappedPlainView implements Resultable {
+
+        boolean drawLine = false;
+        boolean drawSelected = false;
+        boolean drawUnselected = false;
+
+        public WrappedPlainViewINTAPI(Element elem) {
+            super(elem);
+        }
+
+        @Override
+        protected void drawLine(int p0, int p1, Graphics g, int x, int y) {
+            drawLine = true;
+            super.drawLine(p0, p1, g, x, y);
+        }
+
+        @Override
+        protected int drawSelectedText(Graphics g, int x, int y,
+                int p0, int p1) throws BadLocationException {
+            drawSelected = true;
+            return super.drawSelectedText(g, x, y, p0, p1);
+        }
+
+        @Override
+        protected int drawUnselectedText(Graphics g, int x, int y,
+                int p0, int p1) throws BadLocationException {
+            drawUnselected = true;
+            return super.drawUnselectedText(g, x, y, p0, p1);
+        }
+
+        @Override
+        public boolean getResult() {
+            return drawLine && drawSelected && drawUnselected;
+        }
+    }
+
+    static class WrappedPlainViewFPAPI extends WrappedPlainView implements Resultable {
+
+        boolean drawLine = false;
+        boolean drawSelected = false;
+        boolean drawUnselected = false;
+
+        public WrappedPlainViewFPAPI(Element elem) {
+            super(elem);
+        }
+
+        @Override
+        protected void drawLine(int p0, int p1, Graphics2D g, float x, float y) {
+            drawLine = true;
+            super.drawLine(p0, p1, g, x, y);
+        }
+
+        @Override
+        protected float drawSelectedText(Graphics2D g, float x, float y,
+                int p0, int p1) throws BadLocationException {
+            drawSelected = true;
+            return super.drawSelectedText(g, x, y, p0, p1);
+        }
+
+        @Override
+        protected float drawUnselectedText(Graphics2D g, float x, float y,
+                int p0, int p1) throws BadLocationException {
+            drawUnselected = true;
+            return super.drawUnselectedText(g, x, y, p0, p1);
+        }
+
+        @Override
+        public boolean getResult() {
+            return drawLine && drawSelected && drawUnselected;
+        }
+    }
+
+    static class WrappedPlainViewMixedAPI extends WrappedPlainView implements Resultable {
+
+        boolean isIntMethodCalled = false;
+        boolean isFPMethodCalled = false;
+
+        public WrappedPlainViewMixedAPI(Element elem) {
+            super(elem);
+        }
+
+        @Override
+        protected int drawUnselectedText(Graphics g, int x, int y,
+                int p0, int p1) throws BadLocationException {
+            isIntMethodCalled = true;
+            return super.drawUnselectedText(g, x, y, p0, p1);
+        }
+
+        @Override
+        protected float drawUnselectedText(Graphics2D g, float x, float y,
+                int p0, int p1) throws BadLocationException {
+            isFPMethodCalled = true;
+            return super.drawUnselectedText(g, x, y, p0, p1);
+        }
+
+        @Override
+        public boolean getResult() {
+            return !isIntMethodCalled && isFPMethodCalled;
+        }
+    }
+
+    static class PasswordViewINTAPI extends PasswordView implements Resultable {
+
+        boolean isIntMethodCalled = false;
+
+        public PasswordViewINTAPI(Element elem) {
+            super(elem);
+
+        }
+
+        @Override
+        protected int drawEchoCharacter(Graphics g, int x, int y, char c) {
+            isIntMethodCalled = true;
+            return super.drawEchoCharacter(g, x, y, c);
+        }
+
+        @Override
+        public boolean getResult() {
+            return isIntMethodCalled;
+        }
+    }
+
+    static class PasswordViewFPAPI extends PasswordView implements Resultable {
+
+        boolean isFPMethodCalled = false;
+
+        public PasswordViewFPAPI(Element elem) {
+            super(elem);
+
+        }
+
+        @Override
+        protected float drawEchoCharacter(Graphics2D g, float x, float y, char c) {
+            isFPMethodCalled = true;
+            return super.drawEchoCharacter(g, x, y, c);
+        }
+
+        @Override
+        public boolean getResult() {
+            return isFPMethodCalled;
+        }
+    }
+
+    static class PasswordViewMixedAPI extends PasswordView implements Resultable {
+
+        boolean isIntMethodCalled = false;
+        boolean isFPMethodCalled = false;
+
+        public PasswordViewMixedAPI(Element elem) {
+            super(elem);
+
+        }
+
+        @Override
+        protected int drawEchoCharacter(Graphics g, int x, int y, char c) {
+            isIntMethodCalled = true;
+            return super.drawEchoCharacter(g, x, y, c);
+        }
+
+        @Override
+        protected float drawEchoCharacter(Graphics2D g, float x, float y, char c) {
+            isFPMethodCalled = true;
+            return super.drawEchoCharacter(g, x, y, c);
+        }
+
+        @Override
+        public boolean getResult() {
+            return !isIntMethodCalled && isFPMethodCalled;
+        }
+    }
+}