From f771851eb28642e8e57c059847ba4b7623c93179 Mon Sep 17 00:00:00 2001 From: Pavel Porvatov Date: Thu, 27 Jan 2011 14:23:42 +0300 Subject: [PATCH 01/12] 6902615: Method JTextComponent.getKeyStrokesForAction() throws StackOverflowError Reviewed-by: peterz --- jdk/src/share/classes/javax/swing/text/Keymap.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jdk/src/share/classes/javax/swing/text/Keymap.java b/jdk/src/share/classes/javax/swing/text/Keymap.java index 082d7707e44..cf503b0f335 100644 --- a/jdk/src/share/classes/javax/swing/text/Keymap.java +++ b/jdk/src/share/classes/javax/swing/text/Keymap.java @@ -137,6 +137,8 @@ public interface Keymap { /** * Sets the parent keymap, which will be used to * resolve key-bindings. + * The behavior is unspecified if a {@code Keymap} has itself + * as one of its resolve parents. * * @param parent the parent keymap */ From 777ccc075e652685ecf23ff4aa4b86db11eea68b Mon Sep 17 00:00:00 2001 From: Pavel Porvatov Date: Thu, 27 Jan 2011 14:33:30 +0300 Subject: [PATCH 02/12] 6935155: @since tag is missing in JTextComponent.save/restoreComposedText Reviewed-by: alexp --- jdk/src/share/classes/javax/swing/text/JTextComponent.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jdk/src/share/classes/javax/swing/text/JTextComponent.java b/jdk/src/share/classes/javax/swing/text/JTextComponent.java index eccf8a5ee7c..c38c7c9a77d 100644 --- a/jdk/src/share/classes/javax/swing/text/JTextComponent.java +++ b/jdk/src/share/classes/javax/swing/text/JTextComponent.java @@ -4822,6 +4822,7 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A * @return {@code true} if the composed text exists and is saved, * {@code false} otherwise * @see #restoreComposedText + * @since 1.7 */ protected boolean saveComposedText(int pos) { if (composedTextExists()) { @@ -4845,6 +4846,7 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A * should be invoked only if {@code saveComposedText} returns {@code true}. * * @see #saveComposedText + * @since 1.7 */ protected void restoreComposedText() { Document doc = getDocument(); From 066a92efdace9f35de6f8a82db0b10081c72e0bf Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Mon, 31 Jan 2011 21:22:42 +0300 Subject: [PATCH 03/12] 7001484: DOC: Method javax.swing.border.StrokeBorder.getBorderInsets() should specify how it converts float Reviewed-by: alexp --- jdk/src/share/classes/javax/swing/border/StrokeBorder.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/jdk/src/share/classes/javax/swing/border/StrokeBorder.java b/jdk/src/share/classes/javax/swing/border/StrokeBorder.java index b2538bae2dc..eed8c00aa63 100644 --- a/jdk/src/share/classes/javax/swing/border/StrokeBorder.java +++ b/jdk/src/share/classes/javax/swing/border/StrokeBorder.java @@ -118,13 +118,17 @@ public class StrokeBorder extends AbstractBorder { /** * Reinitializes the {@code insets} parameter * with this border's current insets. - * All insets are equal to the line width of the stroke. + * Every inset is the smallest (closest to negative infinity) integer value + * that is greater than or equal to the line width of the stroke + * that is used to paint the border. * * @param c the component for which this border insets value applies * @param insets the {@code Insets} object to be reinitialized * @return the reinitialized {@code insets} parameter * * @throws NullPointerException if the specified {@code insets} is {@code null} + * + * @see Math#ceil */ @Override public Insets getBorderInsets(Component c, Insets insets) { From d12c1d0e4942e1cc987dc4d22d84f1eee142709d Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Mon, 31 Jan 2011 21:31:39 +0300 Subject: [PATCH 04/12] 7001118: DOC: javax.swing.border.StrokeBorder.paintBorder() doesn't throw NPE in all specified cases Reviewed-by: alexp --- .../share/classes/javax/swing/border/StrokeBorder.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/jdk/src/share/classes/javax/swing/border/StrokeBorder.java b/jdk/src/share/classes/javax/swing/border/StrokeBorder.java index eed8c00aa63..34e81f024b3 100644 --- a/jdk/src/share/classes/javax/swing/border/StrokeBorder.java +++ b/jdk/src/share/classes/javax/swing/border/StrokeBorder.java @@ -88,6 +88,10 @@ public class StrokeBorder extends AbstractBorder { /** * Paints the border for the specified component * with the specified position and size. + * If the border was not specified with a {@link Paint} object, + * the component's foreground color will be used to render the border. + * If the component's foreground color is not available, + * the default color of the {@link Graphics} object will be used. * * @param c the component for which this border is being painted * @param g the paint graphics @@ -96,7 +100,7 @@ public class StrokeBorder extends AbstractBorder { * @param width the width of the painted border * @param height the height of the painted border * - * @throws NullPointerException if the specified {@code c} or {@code g} are {@code null} + * @throws NullPointerException if the specified {@code g} is {@code null} */ @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { @@ -106,7 +110,7 @@ public class StrokeBorder extends AbstractBorder { if (g instanceof Graphics2D) { Graphics2D g2d = (Graphics2D) g; g2d.setStroke(this.stroke); - g2d.setPaint(this.paint != null ? this.paint : c.getForeground()); + g2d.setPaint(this.paint != null ? this.paint : c == null ? null : c.getForeground()); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.draw(new Rectangle2D.Float(x + size / 2, y + size / 2, width - size, height - size)); From a09ca04b628b6e04d04cc28542cfdcacbd08fd83 Mon Sep 17 00:00:00 2001 From: Sergey Malenkov Date: Mon, 31 Jan 2011 21:49:27 +0300 Subject: [PATCH 05/12] 6999045: DOC: Unclear spec for BevelBorder constructor and BorderFactory factory method (colors switching) Reviewed-by: alexp --- jdk/src/share/classes/javax/swing/BorderFactory.java | 3 --- jdk/src/share/classes/javax/swing/border/BevelBorder.java | 6 +----- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/jdk/src/share/classes/javax/swing/BorderFactory.java b/jdk/src/share/classes/javax/swing/BorderFactory.java index 8da7dd9579a..19b392ac198 100644 --- a/jdk/src/share/classes/javax/swing/BorderFactory.java +++ b/jdk/src/share/classes/javax/swing/BorderFactory.java @@ -159,9 +159,6 @@ public class BorderFactory * Creates a beveled border of the specified type, using * the specified colors for the inner and outer highlight * and shadow areas. - *

- * Note: The shadow inner and outer colors are - * switched for a lowered bevel border. * * @param type an integer specifying either * BevelBorder.LOWERED or diff --git a/jdk/src/share/classes/javax/swing/border/BevelBorder.java b/jdk/src/share/classes/javax/swing/border/BevelBorder.java index 564d316c43b..bd041aece0c 100644 --- a/jdk/src/share/classes/javax/swing/border/BevelBorder.java +++ b/jdk/src/share/classes/javax/swing/border/BevelBorder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2010, 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 @@ -26,7 +26,6 @@ package javax.swing.border; import java.awt.Graphics; import java.awt.Insets; -import java.awt.Rectangle; import java.awt.Color; import java.awt.Component; import java.beans.ConstructorProperties; @@ -82,9 +81,6 @@ public class BevelBorder extends AbstractBorder /** * Creates a bevel border with the specified type, highlight and * shadow colors. - *

- * Note: The shadow inner and outer colors are - * switched for a lowered bevel border. * * @param bevelType the type of bevel for the border * @param highlightOuterColor the color to use for the bevel outer highlight From 069ec3aa004045f6793983ec4869a5a80c7d1f61 Mon Sep 17 00:00:00 2001 From: Pavel Porvatov Date: Wed, 2 Feb 2011 18:37:31 +0300 Subject: [PATCH 06/12] 6988168: Press the "Toggle Font" button.The size of the combo box didn't change Reviewed-by: alexp --- .../share/classes/javax/swing/plaf/basic/BasicComboBoxUI.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/src/share/classes/javax/swing/plaf/basic/BasicComboBoxUI.java b/jdk/src/share/classes/javax/swing/plaf/basic/BasicComboBoxUI.java index 08e8c6fa718..d55e4490cd0 100644 --- a/jdk/src/share/classes/javax/swing/plaf/basic/BasicComboBoxUI.java +++ b/jdk/src/share/classes/javax/swing/plaf/basic/BasicComboBoxUI.java @@ -1721,6 +1721,7 @@ public class BasicComboBoxUI extends ComboBoxUI { editor.setFont( comboBox.getFont() ); } isMinimumSizeDirty = true; + isDisplaySizeDirty = true; comboBox.validate(); } else if ( propertyName == JComponent.TOOL_TIP_TEXT_KEY ) { From dd26efb159f7c6f224388b1caa4f79d706e2a165 Mon Sep 17 00:00:00 2001 From: Pavel Porvatov Date: Wed, 2 Feb 2011 18:41:30 +0300 Subject: [PATCH 07/12] 6988176: There is focus painted inside the button Reviewed-by: alexp --- jdk/src/share/classes/sun/swing/WindowsPlacesBar.java | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/src/share/classes/sun/swing/WindowsPlacesBar.java b/jdk/src/share/classes/sun/swing/WindowsPlacesBar.java index fcc8717ec80..313ba7ecf26 100644 --- a/jdk/src/share/classes/sun/swing/WindowsPlacesBar.java +++ b/jdk/src/share/classes/sun/swing/WindowsPlacesBar.java @@ -120,6 +120,7 @@ public class WindowsPlacesBar extends JToolBar buttons[i].setForeground(fgColor); } buttons[i].setMargin(new Insets(3, 2, 1, 2)); + buttons[i].setFocusPainted(false); buttons[i].setIconTextGap(0); buttons[i].setHorizontalTextPosition(JToggleButton.CENTER); buttons[i].setVerticalTextPosition(JToggleButton.BOTTOM); From d48bd086df5d153224840d42fd66cdc829a57932 Mon Sep 17 00:00:00 2001 From: Pavel Porvatov Date: Thu, 3 Feb 2011 16:30:51 +0300 Subject: [PATCH 08/12] 7013453: BufferStrategyPaintManager.dispose will cause IllegalMonitorStateException in event thread Reviewed-by: alexp --- .../swing/BufferStrategyPaintManager.java | 2 +- .../RepaintManager/7013453/bug7013453.java | 103 ++++++++++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 jdk/test/javax/swing/RepaintManager/7013453/bug7013453.java diff --git a/jdk/src/share/classes/javax/swing/BufferStrategyPaintManager.java b/jdk/src/share/classes/javax/swing/BufferStrategyPaintManager.java index 781fb4c0e3a..4a7f87085c2 100644 --- a/jdk/src/share/classes/javax/swing/BufferStrategyPaintManager.java +++ b/jdk/src/share/classes/javax/swing/BufferStrategyPaintManager.java @@ -209,7 +209,7 @@ class BufferStrategyPaintManager extends RepaintManager.PaintManager { synchronized(BufferStrategyPaintManager.this) { while (showing) { try { - wait(); + BufferStrategyPaintManager.this.wait(); } catch (InterruptedException ie) { } } diff --git a/jdk/test/javax/swing/RepaintManager/7013453/bug7013453.java b/jdk/test/javax/swing/RepaintManager/7013453/bug7013453.java new file mode 100644 index 00000000000..2314e3d749b --- /dev/null +++ b/jdk/test/javax/swing/RepaintManager/7013453/bug7013453.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2011, 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. + */ + +/* @test + @bug 7013453 + @summary BufferStrategyPaintManager.dispose will cause IllegalMonitorStateException in event thread + @author Pavel Porvatov +*/ + +import javax.swing.*; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class bug7013453 { + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + try { + Method getPaintManagerMethod = RepaintManager.class.getDeclaredMethod("getPaintManager"); + + getPaintManagerMethod.setAccessible(true); + + final Object paintManager = getPaintManagerMethod.invoke(RepaintManager.currentManager(new JLabel())); + + String paintManagerName = paintManager.getClass().getCanonicalName(); + + if (!paintManagerName.equals("javax.swing.BufferStrategyPaintManager")) { + System.out.println("The test is not suitable for the " + paintManagerName + + " paint manager. The test skipped."); + + return; + } + + final Field showingField = paintManager.getClass().getDeclaredField("showing"); + + showingField.setAccessible(true); + + synchronized (paintManager) { + showingField.setBoolean(paintManager, true); + } + + // Postpone reset the showing field + Thread thread = new Thread(new Runnable() { + public void run() { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + synchronized (paintManager) { + try { + showingField.setBoolean(paintManager, false); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + } + }); + + thread.start(); + + Method disposeMethod = paintManager.getClass().getDeclaredMethod("dispose"); + + disposeMethod.setAccessible(true); + + disposeMethod.invoke(paintManager); + + System.out.println("The test passed."); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } + } + }); + } +} From 3ed07d01b93b020050385a9d94560d554c1c7cd4 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Thu, 3 Feb 2011 09:59:20 -0800 Subject: [PATCH 09/12] 7013282: No appropriate CCC request for listed JDK 7 changes in java.util.spi package (b121) Reviewed-by: peytoia --- jdk/src/share/classes/java/util/spi/LocaleNameProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/share/classes/java/util/spi/LocaleNameProvider.java b/jdk/src/share/classes/java/util/spi/LocaleNameProvider.java index 5277738f0c1..741895f1128 100644 --- a/jdk/src/share/classes/java/util/spi/LocaleNameProvider.java +++ b/jdk/src/share/classes/java/util/spi/LocaleNameProvider.java @@ -77,7 +77,7 @@ public abstract class LocaleNameProvider extends LocaleServiceProvider { * is "Cyrl" and locale is fr_FR, getDisplayScript() will return "cyrillique". * If the name returned cannot be localized according to locale, * (say, the provider does not have a Japanese name for Cyrillic), - * this method returns null. + * this method returns null. The default implementation returns null. * @param scriptCode the four letter script code string in the form of title-case * letters (the first letter is upper-case character between 'A' (U+0041) and * 'Z' (U+005A) followed by three lower-case character between 'a' (U+0061) From 4c2196918e0dd7b1cf2ed7db8aa4236a7acacccd Mon Sep 17 00:00:00 2001 From: Alexander Potochkin Date: Mon, 7 Feb 2011 21:15:51 +0300 Subject: [PATCH 10/12] 7016942: Revert a refactoring in TooltipManager to allow reflection hack Reviewed-by: rupashka --- .../share/classes/javax/swing/ToolTipManager.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/jdk/src/share/classes/javax/swing/ToolTipManager.java b/jdk/src/share/classes/javax/swing/ToolTipManager.java index 4088ac3c2d5..b985254f6fa 100644 --- a/jdk/src/share/classes/javax/swing/ToolTipManager.java +++ b/jdk/src/share/classes/javax/swing/ToolTipManager.java @@ -75,6 +75,9 @@ public class ToolTipManager extends MouseAdapter implements MouseMotionListener private MouseMotionListener moveBeforeEnterListener = null; private KeyListener accessibilityKeyListener = null; + private KeyStroke postTip; + private KeyStroke hideTip; + // PENDING(ges) protected boolean lightWeightPopupEnabled = true; protected boolean heavyWeightPopupEnabled = false; @@ -89,6 +92,9 @@ public class ToolTipManager extends MouseAdapter implements MouseMotionListener moveBeforeEnterListener = new MoveBeforeEnterListener(); accessibilityKeyListener = new AccessibilityKeyListener(); + + postTip = KeyStroke.getKeyStroke(KeyEvent.VK_F1, InputEvent.CTRL_MASK); + hideTip = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); } /** @@ -805,13 +811,13 @@ public class ToolTipManager extends MouseAdapter implements MouseMotionListener public void keyPressed(KeyEvent e) { if (!e.isConsumed()) { JComponent source = (JComponent) e.getComponent(); - if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { + KeyStroke keyStrokeForEvent = KeyStroke.getKeyStrokeForEvent(e); + if (hideTip.equals(keyStrokeForEvent)) { if (tipWindow != null) { hide(source); e.consume(); } - } else if (e.getKeyCode() == KeyEvent.VK_F1 - && e.getModifiers() == Event.CTRL_MASK) { + } else if (postTip.equals(keyStrokeForEvent)) { // Shown tooltip will be hidden ToolTipManager.this.show(source); e.consume(); From 98f1ff044f0b05036e205c0e5bc895f254f9a206 Mon Sep 17 00:00:00 2001 From: Alexander Potochkin Date: Mon, 7 Feb 2011 21:34:31 +0300 Subject: [PATCH 11/12] 6979537: closed/javax/swing/JSplitPane/UnitTest/UnitTest.java fails Reviewed-by: rupashka --- .../javax/swing/plaf/basic/BasicSplitPaneUI.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/jdk/src/share/classes/javax/swing/plaf/basic/BasicSplitPaneUI.java b/jdk/src/share/classes/javax/swing/plaf/basic/BasicSplitPaneUI.java index bf97bff882c..e4e82b1bf10 100644 --- a/jdk/src/share/classes/javax/swing/plaf/basic/BasicSplitPaneUI.java +++ b/jdk/src/share/classes/javax/swing/plaf/basic/BasicSplitPaneUI.java @@ -342,12 +342,10 @@ public class BasicSplitPaneUI extends SplitPaneUI setOrientation(splitPane.getOrientation()); - // This plus 2 here is to provide backwards consistancy. Previously, - // the old size did not include the 2 pixel border around the divider, - // it now does. - Integer dividerSize = (Integer)UIManager.get("SplitPane.dividerSize"); - if (divider == null) dividerSize = 10; - LookAndFeel.installProperty(splitPane, "dividerSize", dividerSize); + // note: don't rename this temp variable to dividerSize + // since it will conflict with "this.dividerSize" field + Integer temp = (Integer)UIManager.get("SplitPane.dividerSize"); + LookAndFeel.installProperty(splitPane, "dividerSize", temp == null? 10: temp); divider.setDividerSize(splitPane.getDividerSize()); dividerSize = divider.getDividerSize(); From 47a983f28a8ae837351f070ec22c7fe1e3938a98 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Tue, 8 Feb 2011 09:04:30 -0800 Subject: [PATCH 12/12] 7015500: Locale.toLanguageTag() uses "und" as lang subtag for private use only Locale Reviewed-by: srl --- jdk/src/share/classes/java/util/Locale.java | 9 +++++-- .../classes/sun/util/locale/LanguageTag.java | 18 +++++++++---- .../java/util/Locale/LocaleEnhanceTest.java | 25 ++++++++++++++++--- 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/jdk/src/share/classes/java/util/Locale.java b/jdk/src/share/classes/java/util/Locale.java index 1f0fbba1eae..efe200ed0db 100644 --- a/jdk/src/share/classes/java/util/Locale.java +++ b/jdk/src/share/classes/java/util/Locale.java @@ -1265,7 +1265,9 @@ public final class Locale implements Cloneable, Serializable { StringBuilder buf = new StringBuilder(); String subtag = tag.getLanguage(); - buf.append(LanguageTag.canonicalizeLanguage(subtag)); + if (subtag.length() > 0) { + buf.append(LanguageTag.canonicalizeLanguage(subtag)); + } subtag = tag.getScript(); if (subtag.length() > 0) { @@ -1294,7 +1296,10 @@ public final class Locale implements Cloneable, Serializable { subtag = tag.getPrivateuse(); if (subtag.length() > 0) { - buf.append(LanguageTag.SEP).append(LanguageTag.PRIVATEUSE).append(LanguageTag.SEP); + if (buf.length() > 0) { + buf.append(LanguageTag.SEP); + } + buf.append(LanguageTag.PRIVATEUSE).append(LanguageTag.SEP); // preserve casing buf.append(subtag); } diff --git a/jdk/src/share/classes/sun/util/locale/LanguageTag.java b/jdk/src/share/classes/sun/util/locale/LanguageTag.java index 653bb8e05fb..cf35e18e144 100644 --- a/jdk/src/share/classes/sun/util/locale/LanguageTag.java +++ b/jdk/src/share/classes/sun/util/locale/LanguageTag.java @@ -421,11 +421,11 @@ public class LanguageTag { String region = baseLocale.getRegion(); String variant = baseLocale.getVariant(); + boolean hasSubtag = false; + String privuseVar = null; // store ill-formed variant subtags - if (language.length() == 0 || !isLanguage(language)) { - tag._language = UNDETERMINED; - } else { + if (language.length() > 0 && isLanguage(language)) { // Convert a deprecated language code used by Java to // a new code if (language.equals("iw")) { @@ -440,10 +440,12 @@ public class LanguageTag { if (script.length() > 0 && isScript(script)) { tag._script = canonicalizeScript(script); + hasSubtag = true; } if (region.length() > 0 && isRegion(region)) { tag._region = canonicalizeRegion(region); + hasSubtag = true; } // Special handling for no_NO_NY - use nn_NO for language tag @@ -468,6 +470,7 @@ public class LanguageTag { } if (variants != null) { tag._variants = variants; + hasSubtag = true; } if (!varitr.isDone()) { // ill-formed variant subtags @@ -508,6 +511,7 @@ public class LanguageTag { if (extensions != null) { tag._extensions = extensions; + hasSubtag = true; } // append ill-formed variant subtags to private use @@ -521,8 +525,12 @@ public class LanguageTag { if (privateuse != null) { tag._privateuse = privateuse; - } else if (tag._language.length() == 0) { - // use "und" if neither language nor privateuse is available + } + + if (tag._language.length() == 0 && (hasSubtag || privateuse == null)) { + // use lang "und" when 1) no language is available AND + // 2) any of other subtags other than private use are available or + // no private use tag is available tag._language = UNDETERMINED; } diff --git a/jdk/test/java/util/Locale/LocaleEnhanceTest.java b/jdk/test/java/util/Locale/LocaleEnhanceTest.java index f7ed5ab3dfb..5d816bc2eee 100644 --- a/jdk/test/java/util/Locale/LocaleEnhanceTest.java +++ b/jdk/test/java/util/Locale/LocaleEnhanceTest.java @@ -478,6 +478,23 @@ public class LocaleEnhanceTest extends LocaleTestFmwk { Locale locale = new Locale(test[0], test[1], test[2]); assertEquals("case " + i, test[3], locale.toLanguageTag()); } + + // test locales created from forLanguageTag + String[][] tests1 = { + // case is normalized during the round trip + { "EN-us", "en-US" }, + { "en-Latn-US", "en-Latn-US" }, + // reordering Unicode locale extensions + { "de-u-co-phonebk-ca-gregory", "de-u-ca-gregory-co-phonebk" }, + // private use only language tag is preserved (no extra "und") + { "x-elmer", "x-elmer" }, + { "x-lvariant-JP", "x-lvariant-JP" }, + }; + for (String[] test : tests1) { + Locale locale = Locale.forLanguageTag(test[0]); + assertEquals("case " + test[0], test[1], locale.toLanguageTag()); + } + } public void testForLanguageTag() { @@ -488,9 +505,9 @@ public class LocaleEnhanceTest extends LocaleTestFmwk { String[][] tests = { // private use tags only - { "x-abc", "und-x-abc" }, - { "x-a-b-c", "und-x-a-b-c" }, - { "x-a-12345678", "und-x-a-12345678" }, + { "x-abc", "x-abc" }, + { "x-a-b-c", "x-a-b-c" }, + { "x-a-12345678", "x-a-12345678" }, // grandfathered tags with preferred mappings { "i-ami", "ami" }, @@ -517,7 +534,7 @@ public class LocaleEnhanceTest extends LocaleTestFmwk { // grandfathered irregular tags, no preferred mappings, drop illegal fields // from end. If no subtag is mappable, fallback to 'und' { "i-default", "en-x-i-default" }, - { "i-enochian", "und-x-i-enochian" }, + { "i-enochian", "x-i-enochian" }, { "i-mingo", "see-x-i-mingo" }, { "en-GB-oed", "en-GB-x-oed" }, { "zh-min", "nan-x-zh-min" },