CVSROOT: /cvsroot/classpath Module name: classpath Changes by: Roman Kennke <rabbit78> 06/06/21 13:13:40
Modified files: . : ChangeLog javax/swing/plaf/basic: BasicButtonListener.java BasicButtonUI.java BasicGraphicsUtils.java BasicMenuItemUI.java BasicMenuUI.java Log message: 2006-06-21 Roman Kennke <[EMAIL PROTECTED]> * javax/swing/plaf/basic/BasicButtonListener.java (propertyChange): Create a TextLayout and store it in the button when the 'text' property changes. * javax/swing/plaf/basic/BasicButtonUI.java (paintText): Call BasicGraphicsUtils utility method for drawing strings, instead of Graphics.drawString(). * javax/swing/plaf/basic/BasicGraphicsUtils.java (CACHE_TEXT_LAYOUT): New constant field. Used as a key for storing cached text layouts as client properties in JComponents. (drawString(JComponent,Graphics,String,int,int)): New helper method. (drawStringUnderlineCharAt): New helper method. * javax/swing/plaf/basic/BasicMenuItemUI.java (PropertyChangeHandler.propertyChange): Update cached text layout when 'text' property changes. Use equals() instead of == for string comparison. (paintText): Use new BasicGraphicsUtils methods for painting the cached text layout. (installListeners): Call super.installListeners() and remove the unneeded listener installs. (uninstallListeners): Call super.uninstallListeners() and remove the unneeded listener uninstalls. CVSWeb URLs: http://cvs.savannah.gnu.org/viewcvs/classpath/ChangeLog?cvsroot=classpath&r1=1.7896&r2=1.7897 http://cvs.savannah.gnu.org/viewcvs/classpath/javax/swing/plaf/basic/BasicButtonListener.java?cvsroot=classpath&r1=1.13&r2=1.14 http://cvs.savannah.gnu.org/viewcvs/classpath/javax/swing/plaf/basic/BasicButtonUI.java?cvsroot=classpath&r1=1.38&r2=1.39 http://cvs.savannah.gnu.org/viewcvs/classpath/javax/swing/plaf/basic/BasicGraphicsUtils.java?cvsroot=classpath&r1=1.17&r2=1.18 http://cvs.savannah.gnu.org/viewcvs/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java?cvsroot=classpath&r1=1.47&r2=1.48 http://cvs.savannah.gnu.org/viewcvs/classpath/javax/swing/plaf/basic/BasicMenuUI.java?cvsroot=classpath&r1=1.23&r2=1.24 Patches: Index: ChangeLog =================================================================== RCS file: /cvsroot/classpath/classpath/ChangeLog,v retrieving revision 1.7896 retrieving revision 1.7897 diff -u -b -r1.7896 -r1.7897 --- ChangeLog 21 Jun 2006 12:57:05 -0000 1.7896 +++ ChangeLog 21 Jun 2006 13:13:39 -0000 1.7897 @@ -1,5 +1,29 @@ 2006-06-21 Roman Kennke <[EMAIL PROTECTED]> + * javax/swing/plaf/basic/BasicButtonListener.java + (propertyChange): Create a TextLayout and store it in the button + when the 'text' property changes. + * javax/swing/plaf/basic/BasicButtonUI.java + (paintText): Call BasicGraphicsUtils utility method for + drawing strings, instead of Graphics.drawString(). + * javax/swing/plaf/basic/BasicGraphicsUtils.java + (CACHE_TEXT_LAYOUT): New constant field. Used as a key for storing + cached text layouts as client properties in JComponents. + (drawString(JComponent,Graphics,String,int,int)): New helper method. + (drawStringUnderlineCharAt): New helper method. + * javax/swing/plaf/basic/BasicMenuItemUI.java + (PropertyChangeHandler.propertyChange): Update cached text layout + when 'text' property changes. Use equals() instead of == for + string comparison. + (paintText): Use new BasicGraphicsUtils methods for painting + the cached text layout. + (installListeners): Call super.installListeners() and remove + the unneeded listener installs. + (uninstallListeners): Call super.uninstallListeners() and remove + the unneeded listener uninstalls. + +2006-06-21 Roman Kennke <[EMAIL PROTECTED]> + * javax/swing/plaf/basic/BasicTextUI.java (PropertyChangeHandler.propertyChange): Handle document listener update here. Index: javax/swing/plaf/basic/BasicButtonListener.java =================================================================== RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicButtonListener.java,v retrieving revision 1.13 retrieving revision 1.14 diff -u -b -r1.13 -r1.14 --- javax/swing/plaf/basic/BasicButtonListener.java 4 May 2006 14:45:50 -0000 1.13 +++ javax/swing/plaf/basic/BasicButtonListener.java 21 Jun 2006 13:13:40 -0000 1.14 @@ -41,10 +41,12 @@ import java.awt.event.ActionEvent; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; -import java.awt.event.InputEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; +import java.awt.font.FontRenderContext; +import java.awt.font.TextLayout; +import java.awt.geom.AffineTransform; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; @@ -66,7 +68,21 @@ public void propertyChange(PropertyChangeEvent e) { - // TODO: What should be done here, if anything? + // Store the TextLayout for this in a client property for speed-up + // painting of the label. + String property = e.getPropertyName(); + if (property.equals(AbstractButton.TEXT_CHANGED_PROPERTY) + || property.equals("font")) + { + AbstractButton b = (AbstractButton) e.getSource(); + String text = b.getText(); + if (text == null) + text = ""; + FontRenderContext frc = new FontRenderContext(new AffineTransform(), + false, false); + TextLayout layout = new TextLayout(text, b.getFont(), frc); + b.putClientProperty(BasicGraphicsUtils.CACHED_TEXT_LAYOUT, layout); + } } protected void checkOpacity(AbstractButton b) Index: javax/swing/plaf/basic/BasicButtonUI.java =================================================================== RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicButtonUI.java,v retrieving revision 1.38 retrieving revision 1.39 diff -u -b -r1.38 -r1.39 --- javax/swing/plaf/basic/BasicButtonUI.java 1 Jun 2006 05:17:02 -0000 1.38 +++ javax/swing/plaf/basic/BasicButtonUI.java 21 Jun 2006 13:13:40 -0000 1.39 @@ -442,13 +442,17 @@ if (b.isEnabled()) { g.setColor(b.getForeground()); - g.drawString(text, textRect.x, textRect.y + fm.getAscent()); + // FIXME: Underline mnemonic. + BasicGraphicsUtils.drawString(b, g, text, -1, textRect.x, + textRect.y + fm.getAscent()); } else { String prefix = getPropertyPrefix(); g.setColor(UIManager.getColor(prefix + "disabledText")); - g.drawString(text, textRect.x, textRect.y + fm.getAscent()); + // FIXME: Underline mnemonic. + BasicGraphicsUtils.drawString(b, g, text, -1, textRect.x, + textRect.y + fm.getAscent()); } } } Index: javax/swing/plaf/basic/BasicGraphicsUtils.java =================================================================== RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicGraphicsUtils.java,v retrieving revision 1.17 retrieving revision 1.18 diff -u -b -r1.17 -r1.18 --- javax/swing/plaf/basic/BasicGraphicsUtils.java 18 Oct 2005 22:10:32 -0000 1.17 +++ javax/swing/plaf/basic/BasicGraphicsUtils.java 21 Jun 2006 13:13:40 -0000 1.18 @@ -37,6 +37,8 @@ package javax.swing.plaf.basic; +import gnu.classpath.SystemProperties; + import java.awt.Color; import java.awt.Dimension; import java.awt.Font; @@ -65,6 +67,14 @@ public class BasicGraphicsUtils { /** + * Used as a key for a client property to store cached TextLayouts in. This + * is used for speed-up drawing of text in + * [EMAIL PROTECTED] #drawString(Graphics, String, int, int, int)}. + */ + static final String CACHED_TEXT_LAYOUT = + "BasicGraphicsUtils.cachedTextLayout"; + + /** * Constructor. It is utterly unclear why this class should * be constructable, but this is what the API specification * says. @@ -536,6 +546,170 @@ g2.fill(underline); } + /** + * Draws a string on the specified component. + * + * @param c the component + * @param g the Graphics context + * @param text the string + * @param underlinedChar the character to be underlined + * @param x the X location + * @param y the Y location + */ + static void drawString(JComponent c, Graphics g, String text, + int underlinedChar, int x, int y) + { + int index = -1; + + /* It is intentional that lower case is used. In some languages, + * the set of lowercase characters is larger than the set of + * uppercase ones. Therefore, it is good practice to use lowercase + * for such comparisons (which really means that the author of this + * code can vaguely remember having read some Unicode techreport + * with this recommendation, but is too lazy to look for the URL). + */ + if ((underlinedChar >= 0) || (underlinedChar <= 0xffff)) + index = text.toLowerCase().indexOf( + Character.toLowerCase((char) underlinedChar)); + + drawStringUnderlineCharAt(c, g, text, index, x, y); + } + + + /** + * Draws a String at the given location, underlining the character + * at the specified index. Drawing is performed in the current color + * and font of <code>g</code>. + * + * <p><img src="doc-files/BasicGraphicsUtils-5.png" width="500" + * height="100" alt="[An illustration showing how to use the + * method]" /> + * + * This is an accelerated version of the method with the same name. It + * uses a pre-laid out TextLayout stored in a client property. + * + * @param c the component that is drawn + * @param g the graphics into which the String is drawn. + * + * @param text the String to draw. + * + * @param underlinedIndex the index of the underlined character in + * <code>text</code>. If <code>underlinedIndex</code> falls + * outside the range <code>[0, text.length() - 1]</code>, the + * text will be drawn without underlining anything. + * + * @param x the x coordinate of the text, as it would be passed to + * [EMAIL PROTECTED] java.awt.Graphics#drawString(java.lang.String, + * int, int)}. + * + * @param y the y coordinate of the text, as it would be passed to + * [EMAIL PROTECTED] java.awt.Graphics#drawString(java.lang.String, + * int, int)}. + */ + static void drawStringUnderlineCharAt(JComponent c, Graphics g, String text, + int underlinedIndex, + int x, int y) + { + Graphics2D g2; + Rectangle2D.Double underline; + FontRenderContext frc; + FontMetrics fmet; + LineMetrics lineMetrics; + Font font; + TextLayout layout; + double underlineX1, underlineX2; + boolean drawUnderline; + int textLength; + + textLength = text.length(); + if (textLength == 0) + return; + + drawUnderline = (underlinedIndex >= 0) && (underlinedIndex < textLength); + + // FIXME: unfortunately pango and cairo can't agree on metrics + // so for the time being we continue to *not* use TextLayouts. + if (!(g instanceof Graphics2D) + || SystemProperties.getProperty("gnu.javax.swing.noGraphics2D") != null) + { + /* Fall-back. This is likely to produce garbage for any text + * containing right-to-left (Hebrew or Arabic) characters, even + * if the underlined character is left-to-right. + */ + g.drawString(text, x, y); + if (drawUnderline) + { + fmet = g.getFontMetrics(); + g.fillRect( + /* x */ x + fmet.stringWidth(text.substring(0, underlinedIndex)), + /* y */ y + fmet.getDescent() - 1, + /* width */ fmet.charWidth(text.charAt(underlinedIndex)), + /* height */ 1); + } + + return; + } + + g2 = (Graphics2D) g; + font = g2.getFont(); + frc = g2.getFontRenderContext(); + lineMetrics = font.getLineMetrics(text, frc); + layout = (TextLayout) c.getClientProperty(CACHED_TEXT_LAYOUT); + if (layout == null) + { + layout = new TextLayout(text, font, frc); + System.err.println("Unable to use cached TextLayout for: " + text); + } + + /* Draw the text. */ + layout.draw(g2, x, y); + if (!drawUnderline) + return; + + underlineX1 = x + layout.getLogicalHighlightShape( + underlinedIndex, underlinedIndex).getBounds2D().getX(); + underlineX2 = x + layout.getLogicalHighlightShape( + underlinedIndex + 1, underlinedIndex + 1).getBounds2D().getX(); + + underline = new Rectangle2D.Double(); + if (underlineX1 < underlineX2) + { + underline.x = underlineX1; + underline.width = underlineX2 - underlineX1; + } + else + { + underline.x = underlineX2; + underline.width = underlineX1 - underlineX2; + } + + + underline.height = lineMetrics.getUnderlineThickness(); + underline.y = lineMetrics.getUnderlineOffset(); + if (underline.y == 0) + { + /* Some fonts do not specify an underline offset, although they + * actually should do so. In that case, the result of calling + * lineMetrics.getUnderlineOffset() will be zero. Since it would + * look very ugly if the underline was be positioned immediately + * below the baseline, we check for this and move the underline + * below the descent, as shown in the following ASCII picture: + * + * ##### ##### # + * # # # # + * # # # # + * # # # # + * ##### ###### ---- baseline (0) + * # + * # + * ------------------###----------- lineMetrics.getDescent() + */ + underline.y = lineMetrics.getDescent(); + } + + underline.y += y; + g2.fill(underline); + } /** * Draws a rectangle, simulating a dotted stroke by painting only Index: javax/swing/plaf/basic/BasicMenuItemUI.java =================================================================== RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java,v retrieving revision 1.47 retrieving revision 1.48 diff -u -b -r1.47 -r1.48 --- javax/swing/plaf/basic/BasicMenuItemUI.java 13 Jun 2006 09:28:57 -0000 1.47 +++ javax/swing/plaf/basic/BasicMenuItemUI.java 21 Jun 2006 13:13:40 -0000 1.48 @@ -52,11 +52,15 @@ import java.awt.event.ItemListener; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; +import java.awt.font.FontRenderContext; +import java.awt.font.TextLayout; +import java.awt.geom.AffineTransform; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import javax.swing.AbstractAction; +import javax.swing.AbstractButton; import javax.swing.ActionMap; import javax.swing.ButtonModel; import javax.swing.Icon; @@ -237,7 +241,8 @@ */ public void propertyChange(PropertyChangeEvent e) { - if (e.getPropertyName() == "accelerator") + String property = e.getPropertyName(); + if (property.equals("accelerator")) { InputMap map = SwingUtilities.getUIInputMap(menuItem, JComponent.WHEN_IN_FOCUSED_WINDOW); @@ -250,6 +255,19 @@ if (accelerator != null) map.put(accelerator, "doClick"); } + // TextLayout caching for speed-up drawing of text. + else if (property.equals(AbstractButton.TEXT_CHANGED_PROPERTY) + || property.equals("font")) + { + AbstractButton b = (AbstractButton) e.getSource(); + String text = b.getText(); + if (text == null) + text = ""; + FontRenderContext frc = new FontRenderContext(new AffineTransform(), + false, false); + TextLayout layout = new TextLayout(text, b.getFont(), frc); + b.putClientProperty(BasicGraphicsUtils.CACHED_TEXT_LAYOUT, layout); + } } } @@ -833,12 +851,13 @@ int mnemonicIndex = menuItem.getDisplayedMnemonicIndex(); if (mnemonicIndex != -1) - BasicGraphicsUtils.drawStringUnderlineCharAt(g, text, mnemonicIndex, + BasicGraphicsUtils.drawStringUnderlineCharAt(menuItem, g, text, + mnemonicIndex, textRect.x, textRect.y + fm.getAscent()); else - BasicGraphicsUtils.drawString(g, text, 0, textRect.x, + BasicGraphicsUtils.drawString(menuItem, g, text, 0, textRect.x, textRect.y + fm.getAscent()); } } Index: javax/swing/plaf/basic/BasicMenuUI.java =================================================================== RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicMenuUI.java,v retrieving revision 1.23 retrieving revision 1.24 diff -u -b -r1.23 -r1.24 --- javax/swing/plaf/basic/BasicMenuUI.java 17 Apr 2006 07:41:05 -0000 1.23 +++ javax/swing/plaf/basic/BasicMenuUI.java 21 Jun 2006 13:13:40 -0000 1.24 @@ -230,10 +230,8 @@ */ protected void installListeners() { - ((JMenu) menuItem).addMouseListener(mouseInputListener); - ((JMenu) menuItem).addMouseMotionListener(mouseInputListener); + super.installListeners(); ((JMenu) menuItem).addMenuListener(menuListener); - ((JMenu) menuItem).addMenuDragMouseListener(menuDragMouseListener); } protected void setupPostTimer(JMenu menu) @@ -276,9 +274,8 @@ */ protected void uninstallListeners() { - ((JMenu) menuItem).removeMouseListener(mouseInputListener); + super.uninstallListeners(); ((JMenu) menuItem).removeMenuListener(menuListener); - ((JMenu) menuItem).removePropertyChangeListener(propertyChangeListener); } /**