--- 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 >= 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 >= 0
* @return the X location of the end of the range >= 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 >= 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 >= 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;
+ }
}