提交 2ef9119c 编写于 作者: A alexp

6797139: JButton title is truncating for some strings irrespective of preferred size.

Reviewed-by: peterz
上级 64e73098
...@@ -999,24 +999,20 @@ public class SwingUtilities implements SwingConstants ...@@ -999,24 +999,20 @@ public class SwingUtilities implements SwingConstants
textR.height = (int) v.getPreferredSpan(View.Y_AXIS); textR.height = (int) v.getPreferredSpan(View.Y_AXIS);
} else { } else {
textR.width = SwingUtilities2.stringWidth(c, fm, text); textR.width = SwingUtilities2.stringWidth(c, fm, text);
// Take into account the left and right side bearings.
// This gives more space than it is actually needed,
// but there are two reasons:
// 1. If we set the width to the actual bounds,
// all callers would have to account for the bearings
// themselves. NOTE: all pref size calculations don't do it.
// 2. You can do a drawString at the returned location
// and the text won't be clipped.
lsb = SwingUtilities2.getLeftSideBearing(c, fm, text); lsb = SwingUtilities2.getLeftSideBearing(c, fm, text);
if (lsb < 0) { if (lsb < 0) {
// If lsb is negative, add it to the width and later
// adjust the x location. This gives more space than is
// actually needed.
// This is done like this for two reasons:
// 1. If we set the width to the actual bounds all
// callers would have to account for negative lsb
// (pref size calculations ONLY look at width of
// textR)
// 2. You can do a drawString at the returned location
// and the text won't be clipped.
textR.width -= lsb; textR.width -= lsb;
} }
rsb = SwingUtilities2.getRightSideBearing(c, fm, text);
if (rsb > 0) {
textR.width += rsb;
}
if (textR.width > availTextWidth) { if (textR.width > availTextWidth) {
text = SwingUtilities2.clipString(c, fm, text, text = SwingUtilities2.clipString(c, fm, text,
availTextWidth); availTextWidth);
......
...@@ -195,7 +195,7 @@ class SynthMenuItemLayoutHelper extends MenuItemLayoutHelper { ...@@ -195,7 +195,7 @@ class SynthMenuItemLayoutHelper extends MenuItemLayoutHelper {
getHorizontalAlignment(), getVerticalAlignment(), getHorizontalAlignment(), getVerticalAlignment(),
getHorizontalTextPosition(), getVerticalTextPosition(), getHorizontalTextPosition(), getVerticalTextPosition(),
getViewRect(), iconRect, textRect, getGap()); getViewRect(), iconRect, textRect, getGap());
textRect.width += getLeftTextExtraWidth() + getRightTextExtraWidth(); textRect.width += getLeftTextExtraWidth();
Rectangle labelRect = iconRect.union(textRect); Rectangle labelRect = iconRect.union(textRect);
getLabelSize().setHeight(labelRect.height); getLabelSize().setHeight(labelRect.height);
getLabelSize().setWidth(labelRect.width); getLabelSize().setWidth(labelRect.width);
......
...@@ -84,7 +84,6 @@ public class MenuItemLayoutHelper { ...@@ -84,7 +84,6 @@ public class MenuItemLayoutHelper {
private int minTextOffset; private int minTextOffset;
private int leftTextExtraWidth; private int leftTextExtraWidth;
private int rightTextExtraWidth;
private Rectangle viewRect; private Rectangle viewRect;
...@@ -157,7 +156,6 @@ public class MenuItemLayoutHelper { ...@@ -157,7 +156,6 @@ public class MenuItemLayoutHelper {
private void calcExtraWidths() { private void calcExtraWidths() {
leftTextExtraWidth = getLeftExtraWidth(text); leftTextExtraWidth = getLeftExtraWidth(text);
rightTextExtraWidth = getRightExtraWidth(text);
} }
private int getLeftExtraWidth(String str) { private int getLeftExtraWidth(String str) {
...@@ -169,15 +167,6 @@ public class MenuItemLayoutHelper { ...@@ -169,15 +167,6 @@ public class MenuItemLayoutHelper {
} }
} }
private int getRightExtraWidth(String str) {
int rsb = SwingUtilities2.getRightSideBearing(mi, fm, str);
if (rsb > 0) {
return rsb;
} else {
return 0;
}
}
private void setOriginalWidths() { private void setOriginalWidths() {
iconSize.origWidth = iconSize.width; iconSize.origWidth = iconSize.width;
textSize.origWidth = textSize.width; textSize.origWidth = textSize.width;
...@@ -313,7 +302,7 @@ public class MenuItemLayoutHelper { ...@@ -313,7 +302,7 @@ public class MenuItemLayoutHelper {
verticalAlignment, horizontalAlignment, verticalAlignment, horizontalAlignment,
verticalTextPosition, horizontalTextPosition, verticalTextPosition, horizontalTextPosition,
viewRect, iconRect, textRect, gap); viewRect, iconRect, textRect, gap);
textRect.width += leftTextExtraWidth + rightTextExtraWidth; textRect.width += leftTextExtraWidth;
Rectangle labelRect = iconRect.union(textRect); Rectangle labelRect = iconRect.union(textRect);
labelSize.height = labelRect.height; labelSize.height = labelRect.height;
labelSize.width = labelRect.width; labelSize.width = labelRect.width;
...@@ -1121,10 +1110,6 @@ public class MenuItemLayoutHelper { ...@@ -1121,10 +1110,6 @@ public class MenuItemLayoutHelper {
return leftTextExtraWidth; return leftTextExtraWidth;
} }
public int getRightTextExtraWidth() {
return rightTextExtraWidth;
}
/** /**
* Returns false if the component is a JMenu and it is a top * Returns false if the component is a JMenu and it is a top
* level menu (on the menubar). * level menu (on the menubar).
......
...@@ -27,7 +27,6 @@ package sun.swing; ...@@ -27,7 +27,6 @@ package sun.swing;
import java.security.*; import java.security.*;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.lang.ref.SoftReference;
import java.awt.*; import java.awt.*;
import static java.awt.RenderingHints.*; import static java.awt.RenderingHints.*;
import java.awt.event.*; import java.awt.event.*;
...@@ -78,17 +77,23 @@ public class SwingUtilities2 { ...@@ -78,17 +77,23 @@ public class SwingUtilities2 {
public static final Object LAF_STATE_KEY = public static final Object LAF_STATE_KEY =
new StringBuffer("LookAndFeel State"); new StringBuffer("LookAndFeel State");
// Most of applications use 10 or less fonts simultaneously // Maintain a cache of CACHE_SIZE fonts and the left side bearing
private static final int STRONG_BEARING_CACHE_SIZE = 10; // of the characters falling into the range MIN_CHAR_INDEX to
// Strong cache for the left and right side bearings // MAX_CHAR_INDEX. The values in fontCache are created as needed.
// for STRONG_BEARING_CACHE_SIZE most recently used fonts. private static LSBCacheEntry[] fontCache;
private static BearingCacheEntry[] strongBearingCache = // Windows defines 6 font desktop properties, we will therefore only
new BearingCacheEntry[STRONG_BEARING_CACHE_SIZE]; // cache the metrics for 6 fonts.
// Next index to insert an entry into the strong bearing cache private static final int CACHE_SIZE = 6;
private static int strongBearingCacheNextIndex = 0; // nextIndex in fontCache to insert a font into.
// Soft cache for the left and right side bearings private static int nextIndex;
private static Set<SoftReference<BearingCacheEntry>> softBearingCache = // LSBCacheEntry used to search in fontCache to see if we already
new HashSet<SoftReference<BearingCacheEntry>>(); // have an entry for a particular font
private static LSBCacheEntry searchKey;
// getLeftSideBearing will consult all characters that fall in the
// range MIN_CHAR_INDEX to MAX_CHAR_INDEX.
private static final int MIN_CHAR_INDEX = (int)'W';
private static final int MAX_CHAR_INDEX = (int)'W' + 1;
public static final FontRenderContext DEFAULT_FRC = public static final FontRenderContext DEFAULT_FRC =
new FontRenderContext(null, false, false); new FontRenderContext(null, false, false);
...@@ -183,6 +188,10 @@ public class SwingUtilities2 { ...@@ -183,6 +188,10 @@ public class SwingUtilities2 {
private static final Object charsBufferLock = new Object(); private static final Object charsBufferLock = new Object();
private static char[] charsBuffer = new char[CHAR_BUFFER_SIZE]; private static char[] charsBuffer = new char[CHAR_BUFFER_SIZE];
static {
fontCache = new LSBCacheEntry[CACHE_SIZE];
}
/** /**
* checks whether TextLayout is required to handle characters. * checks whether TextLayout is required to handle characters.
* *
...@@ -226,7 +235,9 @@ public class SwingUtilities2 { ...@@ -226,7 +235,9 @@ public class SwingUtilities2 {
/** /**
* Returns the left side bearing of the first character of string. The * Returns the left side bearing of the first character of string. The
* left side bearing is calculated from the passed in FontMetrics. * left side bearing is calculated from the passed in
* FontMetrics. If the passed in String is less than one
* character, this will throw a StringIndexOutOfBoundsException exception.
* *
* @param c JComponent that will display the string * @param c JComponent that will display the string
* @param fm FontMetrics used to measure the String width * @param fm FontMetrics used to measure the String width
...@@ -234,14 +245,11 @@ public class SwingUtilities2 { ...@@ -234,14 +245,11 @@ public class SwingUtilities2 {
*/ */
public static int getLeftSideBearing(JComponent c, FontMetrics fm, public static int getLeftSideBearing(JComponent c, FontMetrics fm,
String string) { String string) {
if ((string == null) || (string.length() == 0)) {
return 0;
}
return getLeftSideBearing(c, fm, string.charAt(0)); return getLeftSideBearing(c, fm, string.charAt(0));
} }
/** /**
* Returns the left side bearing of the specified character. The * Returns the left side bearing of the first character of string. The
* left side bearing is calculated from the passed in FontMetrics. * left side bearing is calculated from the passed in FontMetrics.
* *
* @param c JComponent that will display the string * @param c JComponent that will display the string
...@@ -250,105 +258,37 @@ public class SwingUtilities2 { ...@@ -250,105 +258,37 @@ public class SwingUtilities2 {
*/ */
public static int getLeftSideBearing(JComponent c, FontMetrics fm, public static int getLeftSideBearing(JComponent c, FontMetrics fm,
char firstChar) { char firstChar) {
return getBearing(c, fm, firstChar, true); int charIndex = (int) firstChar;
} if (charIndex < MAX_CHAR_INDEX && charIndex >= MIN_CHAR_INDEX) {
byte[] lsbs = null;
/**
* Returns the right side bearing of the last character of string. The
* right side bearing is calculated from the passed in FontMetrics.
*
* @param c JComponent that will display the string
* @param fm FontMetrics used to measure the String width
* @param string String to get the right side bearing for.
*/
public static int getRightSideBearing(JComponent c, FontMetrics fm,
String string) {
if ((string == null) || (string.length() == 0)) {
return 0;
}
return getRightSideBearing(c, fm, string.charAt(string.length() - 1));
}
/**
* Returns the right side bearing of the specified character. The
* right side bearing is calculated from the passed in FontMetrics.
*
* @param c JComponent that will display the string
* @param fm FontMetrics used to measure the String width
* @param lastChar Character to get the right side bearing for.
*/
public static int getRightSideBearing(JComponent c, FontMetrics fm,
char lastChar) {
return getBearing(c, fm, lastChar, false);
}
/* Calculates the left and right side bearing for a character. FontRenderContext frc = getFontRenderContext(c, fm);
* Strongly caches bearings for STRONG_BEARING_CACHE_SIZE Font font = fm.getFont();
* most recently used Fonts and softly caches as many as GC allows. synchronized (SwingUtilities2.class) {
*/ LSBCacheEntry entry = null;
private static int getBearing(JComponent comp, FontMetrics fm, char c, if (searchKey == null) {
boolean isLeftBearing) { searchKey = new LSBCacheEntry(frc, font);
if (fm == null) { } else {
if (comp == null) { searchKey.reset(frc, font);
return 0;
} else {
fm = comp.getFontMetrics(comp.getFont());
}
}
synchronized (SwingUtilities2.class) {
BearingCacheEntry entry = null;
BearingCacheEntry searchKey = new BearingCacheEntry(fm);
// See if we already have an entry in the strong cache
for (BearingCacheEntry cacheEntry : strongBearingCache) {
if (searchKey.equals(cacheEntry)) {
entry = cacheEntry;
break;
} }
} // See if we already have an entry for this pair
// See if we already have an entry in the soft cache for (LSBCacheEntry cacheEntry : fontCache) {
if (entry == null) {
Iterator<SoftReference<BearingCacheEntry>> iter =
softBearingCache.iterator();
while (iter.hasNext()) {
BearingCacheEntry cacheEntry = iter.next().get();
if (cacheEntry == null) {
// Remove discarded soft reference from the cache
iter.remove();
continue;
}
if (searchKey.equals(cacheEntry)) { if (searchKey.equals(cacheEntry)) {
entry = cacheEntry; entry = cacheEntry;
putEntryInStrongCache(entry);
break; break;
} }
} }
if (entry == null) {
// No entry for this pair, add it.
entry = searchKey;
fontCache[nextIndex] = searchKey;
searchKey = null;
nextIndex = (nextIndex + 1) % CACHE_SIZE;
}
return entry.getLeftSideBearing(firstChar);
} }
if (entry == null) {
// No entry, add it
entry = searchKey;
cacheEntry(entry);
}
return (isLeftBearing)
? entry.getLeftSideBearing(c)
: entry.getRightSideBearing(c);
} }
} return 0;
private synchronized static void cacheEntry(BearingCacheEntry entry) {
// Move the oldest entry from the strong cache into the soft cache
BearingCacheEntry oldestEntry =
strongBearingCache[strongBearingCacheNextIndex];
if (oldestEntry != null) {
softBearingCache.add(new SoftReference<BearingCacheEntry>(oldestEntry));
}
// Put entry in the strong cache
putEntryInStrongCache(entry);
}
private synchronized static void putEntryInStrongCache(BearingCacheEntry entry) {
strongBearingCache[strongBearingCacheNextIndex] = entry;
strongBearingCacheNextIndex = (strongBearingCacheNextIndex + 1)
% STRONG_BEARING_CACHE_SIZE;
} }
/** /**
...@@ -1063,99 +1003,72 @@ public class SwingUtilities2 { ...@@ -1063,99 +1003,72 @@ public class SwingUtilities2 {
} }
/** /**
* BearingCacheEntry is used to cache left and right character bearings * LSBCacheEntry is used to cache the left side bearing (lsb) for
* for a particular <code>Font</code> and <code>FontRenderContext</code>. * a particular <code>Font</code> and <code>FontRenderContext</code>.
* This only caches characters that fall in the range
* <code>MIN_CHAR_INDEX</code> to <code>MAX_CHAR_INDEX</code>.
*/ */
private static class BearingCacheEntry { private static class LSBCacheEntry {
private FontMetrics fontMetrics; // Used to indicate a particular entry in lsb has not been set.
private static final byte UNSET = Byte.MAX_VALUE;
// Used in creating a GlyphVector to get the lsb
private static final char[] oneChar = new char[1];
private byte[] lsbCache;
private Font font; private Font font;
private FontRenderContext frc; private FontRenderContext frc;
private Map<Character, Short> cache;
// Used for the creation of a GlyphVector
private static final char[] oneChar = new char[1];
public BearingCacheEntry(FontMetrics fontMetrics) {
this.fontMetrics = fontMetrics;
this.font = fontMetrics.getFont();
this.frc = fontMetrics.getFontRenderContext();
this.cache = new HashMap<Character, Short>();
assert (font != null && frc != null);
}
public int getLeftSideBearing(char aChar) { public LSBCacheEntry(FontRenderContext frc, Font font) {
Short bearing = cache.get(aChar); lsbCache = new byte[MAX_CHAR_INDEX - MIN_CHAR_INDEX];
if (bearing == null) { reset(frc, font);
bearing = calcBearing(aChar);
cache.put(aChar, bearing);
}
return ((0xFF00 & bearing) >>> 8) - 127;
} }
public int getRightSideBearing(char aChar) { public void reset(FontRenderContext frc, Font font) {
Short bearing = cache.get(aChar); this.font = font;
if (bearing == null) { this.frc = frc;
bearing = calcBearing(aChar); for (int counter = lsbCache.length - 1; counter >= 0; counter--) {
cache.put(aChar, bearing); lsbCache[counter] = UNSET;
} }
return (0xFF & bearing) - 127;
} }
/* Calculates left and right side bearings for a character. public int getLeftSideBearing(char aChar) {
* Makes an assumption that bearing is a value between -127 and +127. int index = aChar - MIN_CHAR_INDEX;
* Stores LSB and RSB as single two-byte number (short): assert (index >= 0 && index < (MAX_CHAR_INDEX - MIN_CHAR_INDEX));
* LSB is the high byte, RSB is the low byte. byte lsb = lsbCache[index];
*/ if (lsb == UNSET) {
private short calcBearing(char aChar) { oneChar[0] = aChar;
oneChar[0] = aChar; GlyphVector gv = font.createGlyphVector(frc, oneChar);
GlyphVector gv = font.createGlyphVector(frc, oneChar); lsb = (byte) gv.getGlyphPixelBounds(0, frc, 0f, 0f).x;
Rectangle pixelBounds = gv.getGlyphPixelBounds(0, frc, 0f, 0f); if (lsb < 0) {
/* HRGB/HBGR LCD glyph images will always have a pixel
// Get bearings * on the left used in colour fringe reduction.
int lsb = pixelBounds.x; * Text rendering positions this correctly but here
int rsb = pixelBounds.width - fontMetrics.charWidth(aChar); * we are using the glyph image to adjust that position
* so must account for it.
/* HRGB/HBGR LCD glyph images will always have a pixel */
* on the left and a pixel on the right Object aaHint = frc.getAntiAliasingHint();
* used in colour fringe reduction. if (aaHint == VALUE_TEXT_ANTIALIAS_LCD_HRGB ||
* Text rendering positions this correctly but here aaHint == VALUE_TEXT_ANTIALIAS_LCD_HBGR) {
* we are using the glyph image to adjust that position lsb++;
* so must account for it. }
*/ }
if (lsb < 0) { lsbCache[index] = lsb;
Object aaHint = frc.getAntiAliasingHint();
if (aaHint == VALUE_TEXT_ANTIALIAS_LCD_HRGB ||
aaHint == VALUE_TEXT_ANTIALIAS_LCD_HBGR) {
lsb++;
}
}
if (rsb > 0) {
Object aaHint = frc.getAntiAliasingHint();
if (aaHint == VALUE_TEXT_ANTIALIAS_LCD_HRGB ||
aaHint == VALUE_TEXT_ANTIALIAS_LCD_HBGR) {
rsb--;
}
} }
return lsb;
// Make sure that LSB and RSB are valid (see 6472972)
if (lsb < -127 || lsb > 127) {
lsb = 0;
}
if (rsb < -127 || rsb > 127) {
rsb = 0;
}
int bearing = ((lsb + 127) << 8) + (rsb + 127);
return (short)bearing;
} }
public boolean equals(Object entry) { public boolean equals(Object entry) {
if (entry == this) { if (entry == this) {
return true; return true;
} }
if (!(entry instanceof BearingCacheEntry)) { if (!(entry instanceof LSBCacheEntry)) {
return false; return false;
} }
BearingCacheEntry oEntry = (BearingCacheEntry)entry; LSBCacheEntry oEntry = (LSBCacheEntry) entry;
return (font.equals(oEntry.font) && return (font.equals(oEntry.font) &&
frc.equals(oEntry.frc)); frc.equals(oEntry.frc));
} }
...@@ -1172,7 +1085,6 @@ public class SwingUtilities2 { ...@@ -1172,7 +1085,6 @@ public class SwingUtilities2 {
} }
} }
/* /*
* here goes the fix for 4856343 [Problem with applet interaction * here goes the fix for 4856343 [Problem with applet interaction
* with system selection clipboard] * with system selection clipboard]
...@@ -1181,36 +1093,34 @@ public class SwingUtilities2 { ...@@ -1181,36 +1093,34 @@ public class SwingUtilities2 {
* are to be performed * are to be performed
*/ */
/** /**
* checks the security permissions for accessing system clipboard * checks the security permissions for accessing system clipboard
* *
* for untrusted context (see isTrustedContext) checks the * for untrusted context (see isTrustedContext) checks the
* permissions for the current event being handled * permissions for the current event being handled
* *
*/ */
public static boolean canAccessSystemClipboard() { public static boolean canAccessSystemClipboard() {
boolean canAccess = false; boolean canAccess = false;
if (!GraphicsEnvironment.isHeadless()) { if (!GraphicsEnvironment.isHeadless()) {
SecurityManager sm = System.getSecurityManager(); SecurityManager sm = System.getSecurityManager();
if (sm == null) { if (sm == null) {
canAccess = true; canAccess = true;
} else { } else {
try { try {
sm.checkSystemClipboardAccess(); sm.checkSystemClipboardAccess();
canAccess = true; canAccess = true;
} catch (SecurityException e) { } catch (SecurityException e) {
} }
if (canAccess && ! isTrustedContext()) { if (canAccess && ! isTrustedContext()) {
canAccess = canCurrentEventAccessSystemClipboard(true); canAccess = canCurrentEventAccessSystemClipboard(true);
} }
} }
} }
return canAccess; return canAccess;
} }
/** /**
* Returns true if EventQueue.getCurrentEvent() has the permissions to * Returns true if EventQueue.getCurrentEvent() has the permissions to
* access the system clipboard * access the system clipboard
*/ */
public static boolean canCurrentEventAccessSystemClipboard() { public static boolean canCurrentEventAccessSystemClipboard() {
......
/*
* Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/* @test
*
* @bug 6797139
* @author Alexander Potochkin
* @summary tests that JButton's text is not incorrectly truncated
*/
import javax.swing.*;
import javax.swing.plaf.basic.BasicButtonUI;
import java.awt.*;
import java.awt.image.BufferedImage;
public class bug6797139 {
private static void createGui() {
JButton b = new JButton("Probably");
b.setUI(new BasicButtonUI() {
protected void paintText(Graphics g, AbstractButton b, Rectangle textRect, String text) {
super.paintText(g, b, textRect, text);
if (text.endsWith("...")) {
throw new RuntimeException("Text is truncated!");
}
}
});
b.setSize(b.getPreferredSize());
BufferedImage image = new BufferedImage(b.getWidth(), b.getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics g = image.getGraphics();
b.paint(g);
g.dispose();
}
public static void main(String[] args) throws Exception {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
createGui();
}
});
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册