diff --git a/make/sun/awt/Makefile b/make/sun/awt/Makefile index c7961dc556a19e8fe2e5e74891ea60a6eb7a08b0..87fd56b6dad73a6ff853031bf4f9da94a3fcfb59 100644 --- a/make/sun/awt/Makefile +++ b/make/sun/awt/Makefile @@ -175,6 +175,10 @@ endif include $(BUILDDIR)/common/Mapfile-vers.gmk include $(BUILDDIR)/common/Library.gmk +COMPILEFONTCONFIG_FLAGS = +ifdef ALT_COMPILEFONTCONFIG_FLAGS + COMPILEFONTCONFIG_FLAGS += $(ALT_COMPILEFONTCONFIG_FLAGS) +endif build: fontconfigs @@ -406,7 +410,7 @@ COMPILEFONTCONFIG_JARFILE = $(BUILDTOOLJARDIR)/compilefontconfig.jar $(LIBDIR)/%.bfc: $(FONTCONFIGS_SRC)/$(FONTCONFIGS_SRC_PREFIX)%.properties \ $(COMPILEFONTCONFIG_JARFILE) $(prep-target) - $(BOOT_JAVA_CMD) -jar $(COMPILEFONTCONFIG_JARFILE) $< $@ + $(BOOT_JAVA_CMD) -jar $(COMPILEFONTCONFIG_JARFILE) $(COMPILEFONTCONFIG_FLAGS) $< $@ $(install-module-file) $(call chmod-file, 444) @$(java-vm-cleanup) diff --git a/make/tools/src/build/tools/javazic/Zoneinfo.java b/make/tools/src/build/tools/javazic/Zoneinfo.java index 143c687d51b9357faf0a95419b6790f7578c686a..872cc1144c8568239e8f195dc9d24a70cef5060b 100644 --- a/make/tools/src/build/tools/javazic/Zoneinfo.java +++ b/make/tools/src/build/tools/javazic/Zoneinfo.java @@ -222,6 +222,7 @@ class Zoneinfo { boolean continued = false; Zone zone = null; String l; + lineNum = 0; try { while ((line = in.readLine()) != null) { diff --git a/src/share/classes/java/awt/font/NumericShaper.java b/src/share/classes/java/awt/font/NumericShaper.java index 0c57c299fb61ca770ce039cdd0ad00597ab153f9..c8100bfb0dea20c53dcce409127cca63ca884bf8 100644 --- a/src/share/classes/java/awt/font/NumericShaper.java +++ b/src/share/classes/java/awt/font/NumericShaper.java @@ -58,20 +58,20 @@ import java.util.Set; * It is also possible to perform numeric shaping explicitly using instances * of NumericShaper, as this code snippet demonstrates:
*
- *   char[] text = ...;
- *   // shape all EUROPEAN digits (except zero) to ARABIC digits
- *   NumericShaper shaper = NumericShaper.getShaper(NumericShaper.ARABIC);
- *   shaper.shape(text, start, count);
+ * char[] text = ...;
+ * // shape all EUROPEAN digits (except zero) to ARABIC digits
+ * NumericShaper shaper = NumericShaper.getShaper(NumericShaper.ARABIC);
+ * shaper.shape(text, start, count);
  *
- *   // shape European digits to ARABIC digits if preceding text is Arabic, or
- *   // shape European digits to TAMIL digits if preceding text is Tamil, or
- *   // leave European digits alone if there is no preceding text, or
- *   // preceding text is neither Arabic nor Tamil
- *   NumericShaper shaper =
- *      NumericShaper.getContextualShaper(NumericShaper.ARABIC |
- *                                              NumericShaper.TAMIL,
- *                                              NumericShaper.EUROPEAN);
- *   shaper.shape(text, start, count);
+ * // shape European digits to ARABIC digits if preceding text is Arabic, or
+ * // shape European digits to TAMIL digits if preceding text is Tamil, or
+ * // leave European digits alone if there is no preceding text, or
+ * // preceding text is neither Arabic nor Tamil
+ * NumericShaper shaper =
+ *     NumericShaper.getContextualShaper(NumericShaper.ARABIC |
+ *                                         NumericShaper.TAMIL,
+ *                                       NumericShaper.EUROPEAN);
+ * shaper.shape(text, start, count);
  * 
* *

Bit mask- and enum-based Unicode ranges

@@ -99,6 +99,37 @@ import java.util.Set; * values are specified, such as {@code NumericShaper.Range.BALINESE}, * those ranges are ignored. * + *

Decimal Digits Precedence

+ * + *

A Unicode range may have more than one set of decimal digits. If + * multiple decimal digits sets are specified for the same Unicode + * range, one of the sets will take precedence as follows. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Unicode RangeNumericShaper ConstantsPrecedence
Arabic{@link NumericShaper#ARABIC NumericShaper.ARABIC}
+ * {@link NumericShaper#EASTERN_ARABIC NumericShaper.EASTERN_ARABIC}
{@link NumericShaper#EASTERN_ARABIC NumericShaper.EASTERN_ARABIC}
{@link NumericShaper.Range#ARABIC}
+ * {@link NumericShaper.Range#EASTERN_ARABIC}
{@link NumericShaper.Range#EASTERN_ARABIC}
Tai Tham{@link NumericShaper.Range#TAI_THAM_HORA}
+ * {@link NumericShaper.Range#TAI_THAM_THAM}
{@link NumericShaper.Range#TAI_THAM_THAM}
+ * * @since 1.4 */ diff --git a/src/share/classes/java/text/MessageFormat.java b/src/share/classes/java/text/MessageFormat.java index ed155e9b2f7329781e7a6b0b2316886b7b6a96bb..6590e7677952f3dd347e00186d0b4db65789e640 100644 --- a/src/share/classes/java/text/MessageFormat.java +++ b/src/share/classes/java/text/MessageFormat.java @@ -93,73 +93,65 @@ import java.util.Locale; * currency * percent * SubformatPattern + * * - * String: - * StringPartopt - * String StringPart + *

Within a String, a pair of single quotes can be used to + * quote any arbitrary characters except single quotes. For example, + * pattern string "'{0}'" represents string + * "{0}", not a FormatElement. A single quote itself + * must be represented by doubled single quotes {@code ''} throughout a + * String. For example, pattern string "'{''}'" is + * interpreted as a sequence of '{ (start of quoting and a + * left curly brace), '' (a single quote), and + * }' (a right curly brace and end of quoting), + * not '{' and '}' (quoted left and + * right curly braces): representing string "{'}", + * not "{}". * - * StringPart: - * '' - * ' QuotedString ' - * UnquotedString + *

A SubformatPattern is interpreted by its corresponding + * subformat, and subformat-dependent pattern rules apply. For example, + * pattern string "{1,number,$'#',##}" + * (SubformatPattern with underline) will produce a number format + * with the pound-sign quoted, with a result such as: {@code + * "$#31,45"}. Refer to each {@code Format} subclass documentation for + * details. * - * SubformatPattern: - * SubformatPatternPartopt - * SubformatPattern SubformatPatternPart + *

Any unmatched quote is treated as closed at the end of the given + * pattern. For example, pattern string {@code "'{0}"} is treated as + * pattern {@code "'{0}'"}. * - * SubFormatPatternPart: - * ' QuotedPattern ' - * UnquotedPattern - * + *

Any curly braces within an unquoted pattern must be balanced. For + * example, "ab {0} de" and "ab '}' de" are + * valid patterns, but "ab {0'}' de", "ab } de" + * and "''{''" are not. * *

- * Within a String, "''" represents a single - * quote. A QuotedString can contain arbitrary characters - * except single quotes; the surrounding single quotes are removed. - * An UnquotedString can contain arbitrary characters - * except single quotes and left curly brackets. Thus, a string that - * should result in the formatted message "'{0}'" can be written as - * "'''{'0}''" or "'''{0}'''". - *

- * Within a SubformatPattern, different rules apply. - * A QuotedPattern can contain arbitrary characters - * except single quotes; but the surrounding single quotes are - * not removed, so they may be interpreted by the - * subformat. For example, "{1,number,$'#',##}" will - * produce a number format with the pound-sign quoted, with a result - * such as: "$#31,45". - * An UnquotedPattern can contain arbitrary characters - * except single quotes, but curly braces within it must be balanced. - * For example, "ab {0} de" and "ab '}' de" - * are valid subformat patterns, but "ab {0'}' de" and - * "ab } de" are not. - *

*

Warning:
The rules for using quotes within message * format patterns unfortunately have shown to be somewhat confusing. * In particular, it isn't always obvious to localizers whether single * quotes need to be doubled or not. Make sure to inform localizers about * the rules, and tell them (for example, by using comments in resource - * bundle source files) which strings will be processed by MessageFormat. + * bundle source files) which strings will be processed by {@code MessageFormat}. * Note that localizers may need to use single quotes in translated * strings where the original version doesn't have them. *
*

* The ArgumentIndex value is a non-negative integer written - * using the digits '0' through '9', and represents an index into the - * arguments array passed to the format methods - * or the result array returned by the parse methods. + * using the digits {@code '0'} through {@code '9'}, and represents an index into the + * {@code arguments} array passed to the {@code format} methods + * or the result array returned by the {@code parse} methods. *

* The FormatType and FormatStyle values are used to create - * a Format instance for the format element. The following - * table shows how the values map to Format instances. Combinations not + * a {@code Format} instance for the format element. The following + * table shows how the values map to {@code Format} instances. Combinations not * shown in the table are illegal. A SubformatPattern must - * be a valid pattern string for the Format subclass used. + * be a valid pattern string for the {@code Format} subclass used. *

* * - * * * * * * * * * * * * * * * * * * * *
Format Type - * Format Style - * Subformat Created + * FormatType + * FormatStyle + * Subformat Created *
(none) * (none) @@ -167,61 +159,61 @@ import java.util.Locale; *
number * (none) - * NumberFormat.getInstance(getLocale()) + * {@link NumberFormat#getInstance(Locale) NumberFormat.getInstance}{@code (getLocale())} *
integer - * NumberFormat.getIntegerInstance(getLocale()) + * {@link NumberFormat#getIntegerInstance(Locale) NumberFormat.getIntegerInstance}{@code (getLocale())} *
currency - * NumberFormat.getCurrencyInstance(getLocale()) + * {@link NumberFormat#getCurrencyInstance(Locale) NumberFormat.getCurrencyInstance}{@code (getLocale())} *
percent - * NumberFormat.getPercentInstance(getLocale()) + * {@link NumberFormat#getPercentInstance(Locale) NumberFormat.getPercentInstance}{@code (getLocale())} *
SubformatPattern - * new DecimalFormat(subformatPattern, DecimalFormatSymbols.getInstance(getLocale())) + * {@code new} {@link DecimalFormat#DecimalFormat(String,DecimalFormatSymbols) DecimalFormat}{@code (subformatPattern,} {@link DecimalFormatSymbols#getInstance(Locale) DecimalFormatSymbols.getInstance}{@code (getLocale()))} *
date * (none) - * DateFormat.getDateInstance(DateFormat.DEFAULT, getLocale()) + * {@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())} *
short - * DateFormat.getDateInstance(DateFormat.SHORT, getLocale()) + * {@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#SHORT}{@code , getLocale())} *
medium - * DateFormat.getDateInstance(DateFormat.DEFAULT, getLocale()) + * {@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())} *
long - * DateFormat.getDateInstance(DateFormat.LONG, getLocale()) + * {@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#LONG}{@code , getLocale())} *
full - * DateFormat.getDateInstance(DateFormat.FULL, getLocale()) + * {@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#FULL}{@code , getLocale())} *
SubformatPattern - * new SimpleDateFormat(subformatPattern, getLocale()) + * {@code new} {@link SimpleDateFormat#SimpleDateFormat(String,Locale) SimpleDateFormat}{@code (subformatPattern, getLocale())} *
time * (none) - * DateFormat.getTimeInstance(DateFormat.DEFAULT, getLocale()) + * {@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())} *
short - * DateFormat.getTimeInstance(DateFormat.SHORT, getLocale()) + * {@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#SHORT}{@code , getLocale())} *
medium - * DateFormat.getTimeInstance(DateFormat.DEFAULT, getLocale()) + * {@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())} *
long - * DateFormat.getTimeInstance(DateFormat.LONG, getLocale()) + * {@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#LONG}{@code , getLocale())} *
full - * DateFormat.getTimeInstance(DateFormat.FULL, getLocale()) + * {@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#FULL}{@code , getLocale())} *
SubformatPattern - * new SimpleDateFormat(subformatPattern, getLocale()) + * {@code new} {@link SimpleDateFormat#SimpleDateFormat(String,Locale) SimpleDateFormat}{@code (subformatPattern, getLocale())} *
choice * SubformatPattern - * new ChoiceFormat(subformatPattern) + * {@code new} {@link ChoiceFormat#ChoiceFormat(String) ChoiceFormat}{@code (subformatPattern)} *
*

* @@ -321,7 +313,7 @@ import java.util.Locale; * * *

- * Likewise, parsing with a MessageFormat object using patterns containing + * Likewise, parsing with a {@code MessageFormat} object using patterns containing * multiple occurrences of the same argument would return the last match. For * example, *

@@ -343,7 +335,11 @@ import java.util.Locale;
  * @see          Format
  * @see          NumberFormat
  * @see          DecimalFormat
+ * @see          DecimalFormatSymbols
  * @see          ChoiceFormat
+ * @see          DateFormat
+ * @see          SimpleDateFormat
+ *
  * @author       Mark Davis
  */
 
@@ -427,18 +423,19 @@ public class MessageFormat extends Format {
      * @exception IllegalArgumentException if the pattern is invalid
      */
     public void applyPattern(String pattern) {
-            StringBuffer[] segments = new StringBuffer[4];
-            for (int i = 0; i < segments.length; ++i) {
-                segments[i] = new StringBuffer();
-            }
-            int part = 0;
+            StringBuilder[] segments = new StringBuilder[4];
+            // Allocate only segments[SEG_RAW] here. The rest are
+            // allocated on demand.
+            segments[SEG_RAW] = new StringBuilder();
+
+            int part = SEG_RAW;
             int formatNumber = 0;
             boolean inQuote = false;
             int braceStack = 0;
             maxOffset = -1;
             for (int i = 0; i < pattern.length(); ++i) {
                 char ch = pattern.charAt(i);
-                if (part == 0) {
+                if (part == SEG_RAW) {
                     if (ch == '\'') {
                         if (i + 1 < pattern.length()
                             && pattern.charAt(i+1) == '\'') {
@@ -448,43 +445,61 @@ public class MessageFormat extends Format {
                             inQuote = !inQuote;
                         }
                     } else if (ch == '{' && !inQuote) {
-                        part = 1;
+                        part = SEG_INDEX;
+                        if (segments[SEG_INDEX] == null) {
+                            segments[SEG_INDEX] = new StringBuilder();
+                        }
                     } else {
                         segments[part].append(ch);
                     }
-                } else  if (inQuote) {              // just copy quotes in parts
-                    segments[part].append(ch);
-                    if (ch == '\'') {
-                        inQuote = false;
-                    }
-                } else {
-                    switch (ch) {
-                    case ',':
-                        if (part < 3)
-                            part += 1;
-                        else
-                            segments[part].append(ch);
-                        break;
-                    case '{':
-                        ++braceStack;
+                } else  {
+                    if (inQuote) {              // just copy quotes in parts
                         segments[part].append(ch);
-                        break;
-                    case '}':
-                        if (braceStack == 0) {
-                            part = 0;
-                            makeFormat(i, formatNumber, segments);
-                            formatNumber++;
-                        } else {
-                            --braceStack;
+                        if (ch == '\'') {
+                            inQuote = false;
+                        }
+                    } else {
+                        switch (ch) {
+                        case ',':
+                            if (part < SEG_MODIFIER) {
+                                if (segments[++part] == null) {
+                                    segments[part] = new StringBuilder();
+                                }
+                            } else {
+                                segments[part].append(ch);
+                            }
+                            break;
+                        case '{':
+                            ++braceStack;
                             segments[part].append(ch);
+                            break;
+                        case '}':
+                            if (braceStack == 0) {
+                                part = SEG_RAW;
+                                makeFormat(i, formatNumber, segments);
+                                formatNumber++;
+                                // throw away other segments
+                                segments[SEG_INDEX] = null;
+                                segments[SEG_TYPE] = null;
+                                segments[SEG_MODIFIER] = null;
+                            } else {
+                                --braceStack;
+                                segments[part].append(ch);
+                            }
+                            break;
+                        case ' ':
+                            // Skip any leading space chars for SEG_TYPE.
+                            if (part != SEG_TYPE || segments[SEG_TYPE].length() > 0) {
+                                segments[part].append(ch);
+                            }
+                            break;
+                        case '\'':
+                            inQuote = true;
+                            // fall through, so we keep quotes in other parts
+                        default:
+                            segments[part].append(ch);
+                            break;
                         }
-                        break;
-                    case '\'':
-                        inQuote = true;
-                        // fall through, so we keep quotes in other parts
-                    default:
-                        segments[part].append(ch);
-                        break;
                     }
                 }
             }
@@ -506,65 +521,57 @@ public class MessageFormat extends Format {
     public String toPattern() {
         // later, make this more extensible
         int lastOffset = 0;
-        StringBuffer result = new StringBuffer();
+        StringBuilder result = new StringBuilder();
         for (int i = 0; i <= maxOffset; ++i) {
-            copyAndFixQuotes(pattern, lastOffset, offsets[i],result);
+            copyAndFixQuotes(pattern, lastOffset, offsets[i], result);
             lastOffset = offsets[i];
-            result.append('{');
-            result.append(argumentNumbers[i]);
-            if (formats[i] == null) {
+            result.append('{').append(argumentNumbers[i]);
+            Format fmt = formats[i];
+            if (fmt == null) {
                 // do nothing, string format
-            } else if (formats[i] instanceof DecimalFormat) {
-                if (formats[i].equals(NumberFormat.getInstance(locale))) {
+            } else if (fmt instanceof NumberFormat) {
+                if (fmt.equals(NumberFormat.getInstance(locale))) {
                     result.append(",number");
-                } else if (formats[i].equals(NumberFormat.getCurrencyInstance(locale))) {
+                } else if (fmt.equals(NumberFormat.getCurrencyInstance(locale))) {
                     result.append(",number,currency");
-                } else if (formats[i].equals(NumberFormat.getPercentInstance(locale))) {
+                } else if (fmt.equals(NumberFormat.getPercentInstance(locale))) {
                     result.append(",number,percent");
-                } else if (formats[i].equals(NumberFormat.getIntegerInstance(locale))) {
+                } else if (fmt.equals(NumberFormat.getIntegerInstance(locale))) {
                     result.append(",number,integer");
                 } else {
-                    result.append(",number," +
-                                  ((DecimalFormat)formats[i]).toPattern());
+                    if (fmt instanceof DecimalFormat) {
+                        result.append(",number,").append(((DecimalFormat)fmt).toPattern());
+                    } else if (fmt instanceof ChoiceFormat) {
+                        result.append(",choice,").append(((ChoiceFormat)fmt).toPattern());
+                    } else {
+                        // UNKNOWN
+                    }
                 }
-            } else if (formats[i] instanceof SimpleDateFormat) {
-                if (formats[i].equals(DateFormat.getDateInstance(
-                                                               DateFormat.DEFAULT,locale))) {
-                    result.append(",date");
-                } else if (formats[i].equals(DateFormat.getDateInstance(
-                                                                      DateFormat.SHORT,locale))) {
-                    result.append(",date,short");
-                } else if (formats[i].equals(DateFormat.getDateInstance(
-                                                                      DateFormat.DEFAULT,locale))) {
-                    result.append(",date,medium");
-                } else if (formats[i].equals(DateFormat.getDateInstance(
-                                                                      DateFormat.LONG,locale))) {
-                    result.append(",date,long");
-                } else if (formats[i].equals(DateFormat.getDateInstance(
-                                                                      DateFormat.FULL,locale))) {
-                    result.append(",date,full");
-                } else if (formats[i].equals(DateFormat.getTimeInstance(
-                                                                      DateFormat.DEFAULT,locale))) {
-                    result.append(",time");
-                } else if (formats[i].equals(DateFormat.getTimeInstance(
-                                                                      DateFormat.SHORT,locale))) {
-                    result.append(",time,short");
-                } else if (formats[i].equals(DateFormat.getTimeInstance(
-                                                                      DateFormat.DEFAULT,locale))) {
-                    result.append(",time,medium");
-                } else if (formats[i].equals(DateFormat.getTimeInstance(
-                                                                      DateFormat.LONG,locale))) {
-                    result.append(",time,long");
-                } else if (formats[i].equals(DateFormat.getTimeInstance(
-                                                                      DateFormat.FULL,locale))) {
-                    result.append(",time,full");
-                } else {
-                    result.append(",date,"
-                                  + ((SimpleDateFormat)formats[i]).toPattern());
+            } else if (fmt instanceof DateFormat) {
+                int index;
+                for (index = MODIFIER_DEFAULT; index < DATE_TIME_MODIFIERS.length; index++) {
+                    DateFormat df = DateFormat.getDateInstance(DATE_TIME_MODIFIERS[index],
+                                                               locale);
+                    if (fmt.equals(df)) {
+                        result.append(",date");
+                        break;
+                    }
+                    df = DateFormat.getTimeInstance(DATE_TIME_MODIFIERS[index],
+                                                    locale);
+                    if (fmt.equals(df)) {
+                        result.append(",time");
+                        break;
+                    }
+                }
+                if (index >= DATE_TIME_MODIFIERS.length) {
+                    if (fmt instanceof SimpleDateFormat) {
+                        result.append(",date,").append(((SimpleDateFormat)fmt).toPattern());
+                    } else {
+                        // UNKNOWN
+                    }
+                } else if (index != MODIFIER_DEFAULT) {
+                    result.append(',').append(DATE_TIME_MODIFIER_KEYWORDS[index]);
                 }
-            } else if (formats[i] instanceof ChoiceFormat) {
-                result.append(",choice,"
-                              + ((ChoiceFormat)formats[i]).toPattern());
             } else {
                 //result.append(", unknown");
             }
@@ -678,7 +685,7 @@ public class MessageFormat extends Format {
      *
      * @param formatElementIndex the index of a format element within the pattern
      * @param newFormat the format to use for the specified format element
-     * @exception ArrayIndexOutOfBoundsException if formatElementIndex is equal to or
+     * @exception ArrayIndexOutOfBoundsException if {@code formatElementIndex} is equal to or
      *            larger than the number of format elements in the pattern string
      */
     public void setFormat(int formatElementIndex, Format newFormat) {
@@ -972,7 +979,8 @@ public class MessageFormat extends Format {
                 if (patternOffset >= tempLength) {
                     next = source.length();
                 }else{
-                    next = source.indexOf( pattern.substring(patternOffset,tempLength), sourceOffset);
+                    next = source.indexOf(pattern.substring(patternOffset, tempLength),
+                                          sourceOffset);
                 }
 
                 if (next < 0) {
@@ -1226,7 +1234,7 @@ public class MessageFormat extends Format {
             lastOffset = offsets[i];
             int argumentNumber = argumentNumbers[i];
             if (arguments == null || argumentNumber >= arguments.length) {
-                result.append("{" + argumentNumber + "}");
+                result.append('{').append(argumentNumber).append('}');
                 continue;
             }
             // int argRecursion = ((recursionProtection >> (argumentNumber*2)) & 0x3);
@@ -1338,25 +1346,83 @@ public class MessageFormat extends Format {
         }
     }
 
-    private static final String[] typeList =
-    {"", "", "number", "", "date", "", "time", "", "choice"};
-    private static final String[] modifierList =
-    {"", "", "currency", "", "percent", "", "integer"};
-    private static final String[] dateModifierList =
-    {"", "", "short", "", "medium", "", "long", "", "full"};
+    // Indices for segments
+    private static final int SEG_RAW      = 0;
+    private static final int SEG_INDEX    = 1;
+    private static final int SEG_TYPE     = 2;
+    private static final int SEG_MODIFIER = 3; // modifier or subformat
+
+    // Indices for type keywords
+    private static final int TYPE_NULL    = 0;
+    private static final int TYPE_NUMBER  = 1;
+    private static final int TYPE_DATE    = 2;
+    private static final int TYPE_TIME    = 3;
+    private static final int TYPE_CHOICE  = 4;
+
+    private static final String[] TYPE_KEYWORDS = {
+        "",
+        "number",
+        "date",
+        "time",
+        "choice"
+    };
+
+    // Indices for number modifiers
+    private static final int MODIFIER_DEFAULT  = 0; // common in number and date-time
+    private static final int MODIFIER_CURRENCY = 1;
+    private static final int MODIFIER_PERCENT  = 2;
+    private static final int MODIFIER_INTEGER  = 3;
+
+    private static final String[] NUMBER_MODIFIER_KEYWORDS = {
+        "",
+        "currency",
+        "percent",
+        "integer"
+    };
+
+    // Indices for date-time modifiers
+    private static final int MODIFIER_SHORT   = 1;
+    private static final int MODIFIER_MEDIUM  = 2;
+    private static final int MODIFIER_LONG    = 3;
+    private static final int MODIFIER_FULL    = 4;
+
+    private static final String[] DATE_TIME_MODIFIER_KEYWORDS = {
+        "",
+        "short",
+        "medium",
+        "long",
+        "full"
+    };
+
+    // Date-time style values corresponding to the date-time modifiers.
+    private static final int[] DATE_TIME_MODIFIERS = {
+        DateFormat.DEFAULT,
+        DateFormat.SHORT,
+        DateFormat.MEDIUM,
+        DateFormat.LONG,
+        DateFormat.FULL,
+    };
 
     private void makeFormat(int position, int offsetNumber,
-                            StringBuffer[] segments)
+                            StringBuilder[] textSegments)
     {
+        String[] segments = new String[textSegments.length];
+        for (int i = 0; i < textSegments.length; i++) {
+            StringBuilder oneseg = textSegments[i];
+            segments[i] = (oneseg != null) ? oneseg.toString() : "";
+        }
+
         // get the argument number
         int argumentNumber;
         try {
-            argumentNumber = Integer.parseInt(segments[1].toString()); // always unlocalized!
+            argumentNumber = Integer.parseInt(segments[SEG_INDEX]); // always unlocalized!
         } catch (NumberFormatException e) {
-            throw new IllegalArgumentException("can't parse argument number: " + segments[1]);
+            throw new IllegalArgumentException("can't parse argument number: "
+                                               + segments[SEG_INDEX], e);
         }
         if (argumentNumber < 0) {
-            throw new IllegalArgumentException("negative argument number: " + argumentNumber);
+            throw new IllegalArgumentException("negative argument number: "
+                                               + argumentNumber);
         }
 
         // resize format information arrays if necessary
@@ -1374,120 +1440,129 @@ public class MessageFormat extends Format {
         }
         int oldMaxOffset = maxOffset;
         maxOffset = offsetNumber;
-        offsets[offsetNumber] = segments[0].length();
+        offsets[offsetNumber] = segments[SEG_RAW].length();
         argumentNumbers[offsetNumber] = argumentNumber;
 
         // now get the format
         Format newFormat = null;
-        switch (findKeyword(segments[2].toString(), typeList)) {
-        case 0:
-            break;
-        case 1: case 2:// number
-            switch (findKeyword(segments[3].toString(), modifierList)) {
-            case 0: // default;
-                newFormat = NumberFormat.getInstance(locale);
-                break;
-            case 1: case 2:// currency
-                newFormat = NumberFormat.getCurrencyInstance(locale);
-                break;
-            case 3: case 4:// percent
-                newFormat = NumberFormat.getPercentInstance(locale);
-                break;
-            case 5: case 6:// integer
-                newFormat = NumberFormat.getIntegerInstance(locale);
-                break;
-            default: // pattern
-                newFormat = new DecimalFormat(segments[3].toString(), DecimalFormatSymbols.getInstance(locale));
+        if (segments[SEG_TYPE].length() != 0) {
+            int type = findKeyword(segments[SEG_TYPE], TYPE_KEYWORDS);
+            switch (type) {
+            case TYPE_NULL:
+                // Type "" is allowed. e.g., "{0,}", "{0,,}", and "{0,,#}"
+                // are treated as "{0}".
                 break;
-            }
-            break;
-        case 3: case 4: // date
-            switch (findKeyword(segments[3].toString(), dateModifierList)) {
-            case 0: // default
-                newFormat = DateFormat.getDateInstance(DateFormat.DEFAULT, locale);
-                break;
-            case 1: case 2: // short
-                newFormat = DateFormat.getDateInstance(DateFormat.SHORT, locale);
-                break;
-            case 3: case 4: // medium
-                newFormat = DateFormat.getDateInstance(DateFormat.DEFAULT, locale);
-                break;
-            case 5: case 6: // long
-                newFormat = DateFormat.getDateInstance(DateFormat.LONG, locale);
-                break;
-            case 7: case 8: // full
-                newFormat = DateFormat.getDateInstance(DateFormat.FULL, locale);
-                break;
-            default:
-                newFormat = new SimpleDateFormat(segments[3].toString(), locale);
-                break;
-            }
-            break;
-        case 5: case 6:// time
-            switch (findKeyword(segments[3].toString(), dateModifierList)) {
-            case 0: // default
-                newFormat = DateFormat.getTimeInstance(DateFormat.DEFAULT, locale);
-                break;
-            case 1: case 2: // short
-                newFormat = DateFormat.getTimeInstance(DateFormat.SHORT, locale);
-                break;
-            case 3: case 4: // medium
-                newFormat = DateFormat.getTimeInstance(DateFormat.DEFAULT, locale);
+
+            case TYPE_NUMBER:
+                switch (findKeyword(segments[SEG_MODIFIER], NUMBER_MODIFIER_KEYWORDS)) {
+                case MODIFIER_DEFAULT:
+                    newFormat = NumberFormat.getInstance(locale);
+                    break;
+                case MODIFIER_CURRENCY:
+                    newFormat = NumberFormat.getCurrencyInstance(locale);
+                    break;
+                case MODIFIER_PERCENT:
+                    newFormat = NumberFormat.getPercentInstance(locale);
+                    break;
+                case MODIFIER_INTEGER:
+                    newFormat = NumberFormat.getIntegerInstance(locale);
+                    break;
+                default: // DecimalFormat pattern
+                    try {
+                        newFormat = new DecimalFormat(segments[SEG_MODIFIER],
+                                                      DecimalFormatSymbols.getInstance(locale));
+                    } catch (IllegalArgumentException e) {
+                        maxOffset = oldMaxOffset;
+                        throw e;
+                    }
+                    break;
+                }
                 break;
-            case 5: case 6: // long
-                newFormat = DateFormat.getTimeInstance(DateFormat.LONG, locale);
+
+            case TYPE_DATE:
+            case TYPE_TIME:
+                int mod = findKeyword(segments[SEG_MODIFIER], DATE_TIME_MODIFIER_KEYWORDS);
+                if (mod >= 0 && mod < DATE_TIME_MODIFIER_KEYWORDS.length) {
+                    if (type == TYPE_DATE) {
+                        newFormat = DateFormat.getDateInstance(DATE_TIME_MODIFIERS[mod],
+                                                               locale);
+                    } else {
+                        newFormat = DateFormat.getTimeInstance(DATE_TIME_MODIFIERS[mod],
+                                                               locale);
+                    }
+                } else {
+                    // SimpleDateFormat pattern
+                    try {
+                        newFormat = new SimpleDateFormat(segments[SEG_MODIFIER], locale);
+                    } catch (IllegalArgumentException e) {
+                        maxOffset = oldMaxOffset;
+                        throw e;
+                    }
+                }
                 break;
-            case 7: case 8: // full
-                newFormat = DateFormat.getTimeInstance(DateFormat.FULL, locale);
+
+            case TYPE_CHOICE:
+                try {
+                    // ChoiceFormat pattern
+                    newFormat = new ChoiceFormat(segments[SEG_MODIFIER]);
+                } catch (Exception e) {
+                    maxOffset = oldMaxOffset;
+                    throw new IllegalArgumentException("Choice Pattern incorrect: "
+                                                       + segments[SEG_MODIFIER], e);
+                }
                 break;
+
             default:
-                newFormat = new SimpleDateFormat(segments[3].toString(), locale);
-                break;
-            }
-            break;
-        case 7: case 8:// choice
-            try {
-                newFormat = new ChoiceFormat(segments[3].toString());
-            } catch (Exception e) {
                 maxOffset = oldMaxOffset;
-                throw new IllegalArgumentException(
-                                         "Choice Pattern incorrect");
+                throw new IllegalArgumentException("unknown format type: " +
+                                                   segments[SEG_TYPE]);
             }
-            break;
-        default:
-            maxOffset = oldMaxOffset;
-            throw new IllegalArgumentException("unknown format type: " +
-                                               segments[2].toString());
         }
         formats[offsetNumber] = newFormat;
-        segments[1].setLength(0);   // throw away other segments
-        segments[2].setLength(0);
-        segments[3].setLength(0);
     }
 
     private static final int findKeyword(String s, String[] list) {
-        s = s.trim().toLowerCase();
         for (int i = 0; i < list.length; ++i) {
             if (s.equals(list[i]))
                 return i;
         }
+
+        // Try trimmed lowercase.
+        String ls = s.trim().toLowerCase(Locale.ROOT);
+        if (ls != s) {
+            for (int i = 0; i < list.length; ++i) {
+                if (ls.equals(list[i]))
+                    return i;
+            }
+        }
         return -1;
     }
 
-    private static final void copyAndFixQuotes(
-                                               String source, int start, int end, StringBuffer target) {
+    private static final void copyAndFixQuotes(String source, int start, int end,
+                                               StringBuilder target) {
+        boolean quoted = false;
+
         for (int i = start; i < end; ++i) {
             char ch = source.charAt(i);
             if (ch == '{') {
-                target.append("'{'");
-            } else if (ch == '}') {
-                target.append("'}'");
+                if (!quoted) {
+                    target.append('\'');
+                    quoted = true;
+                }
+                target.append(ch);
             } else if (ch == '\'') {
                 target.append("''");
             } else {
+                if (quoted) {
+                    target.append('\'');
+                    quoted = false;
+                }
                 target.append(ch);
             }
         }
+        if (quoted) {
+            target.append('\'');
+        }
     }
 
     /**
diff --git a/src/share/classes/java/text/SimpleDateFormat.java b/src/share/classes/java/text/SimpleDateFormat.java
index 9ae84f828d08bca6a3e43fd20b5e86ef2ef2eae8..fd2876aca056bc2bdf13279c613ff8aa4e961524 100644
--- a/src/share/classes/java/text/SimpleDateFormat.java
+++ b/src/share/classes/java/text/SimpleDateFormat.java
@@ -1662,6 +1662,81 @@ public class SimpleDateFormat extends DateFormat {
         return 0;
     }
 
+    /**
+     * Parses numeric forms of time zone offset, such as "hh:mm", and
+     * sets calb to the parsed value.
+     *
+     * @param text  the text to be parsed
+     * @param start the character position to start parsing
+     * @param sign  1: positive; -1: negative
+     * @param count 0: 'Z' or "GMT+hh:mm" parsing; 1 - 3: the number of 'X's
+     * @param colon true - colon required between hh and mm; false - no colon required
+     * @param calb  a CalendarBuilder in which the parsed value is stored
+     * @return updated parsed position, or its negative value to indicate a parsing error
+     */
+    private int subParseNumericZone(String text, int start, int sign, int count,
+                                    boolean colon, CalendarBuilder calb) {
+        int index = start;
+
+      parse:
+        try {
+            char c = text.charAt(index++);
+            // Parse hh
+            int hours;
+            if (!isDigit(c)) {
+                break parse;
+            }
+            hours = c - '0';
+            c = text.charAt(index++);
+            if (isDigit(c)) {
+                hours = hours * 10 + (c - '0');
+            } else {
+                // If no colon in RFC 822 or 'X' (ISO), two digits are
+                // required.
+                if (count > 0 || !colon) {
+                    break parse;
+                }
+                --index;
+            }
+            if (hours > 23) {
+                break parse;
+            }
+            int minutes = 0;
+            if (count != 1) {
+                // Proceed with parsing mm
+                c = text.charAt(index++);
+                if (colon) {
+                    if (c != ':') {
+                        break parse;
+                    }
+                    c = text.charAt(index++);
+                }
+                if (!isDigit(c)) {
+                    break parse;
+                }
+                minutes = c - '0';
+                c = text.charAt(index++);
+                if (!isDigit(c)) {
+                    break parse;
+                }
+                minutes = minutes * 10 + (c - '0');
+                if (minutes > 59) {
+                    break parse;
+                }
+            }
+            minutes += hours * 60;
+            calb.set(Calendar.ZONE_OFFSET, minutes * MILLIS_PER_MINUTE * sign)
+                .set(Calendar.DST_OFFSET, 0);
+            return index;
+        } catch (IndexOutOfBoundsException e) {
+        }
+        return  1 - index; // -(index - 1)
+    }
+
+    private boolean isDigit(char c) {
+        return c >= '0' && c <= '9';
+    }
+
     /**
      * Private member function that converts the parsed date strings into
      * timeFields. Returns -start (for ParsePosition) if failed.
@@ -1907,248 +1982,95 @@ public class SimpleDateFormat extends DateFormat {
 
             case PATTERN_ZONE_NAME:  // 'z'
             case PATTERN_ZONE_VALUE: // 'Z'
-                // First try to parse generic forms such as GMT-07:00. Do this first
-                // in case localized TimeZoneNames contains the string "GMT"
-                // for a zone; in that case, we don't want to match the first three
-                // characters of GMT+/-hh:mm etc.
                 {
                     int sign = 0;
-                    int offset;
-
-                    // For time zones that have no known names, look for strings
-                    // of the form:
-                    //    GMT[+-]hours:minutes or
-                    //    GMT.
-                    if ((text.length() - start) >= GMT.length() &&
-                        text.regionMatches(true, start, GMT, 0, GMT.length())) {
-                        int num;
-                        calb.set(Calendar.DST_OFFSET, 0);
-                        pos.index = start + GMT.length();
-
-                        try { // try-catch for "GMT" only time zone string
-                            char c = text.charAt(pos.index);
-                            if (c == '+') {
-                                sign = 1;
-                            } else if (c == '-') {
-                                sign = -1;
-                            }
-                        }
-                        catch(StringIndexOutOfBoundsException e) {}
-
-                        if (sign == 0) {    /* "GMT" without offset */
-                            calb.set(Calendar.ZONE_OFFSET, 0);
-                            return pos.index;
+                    try {
+                        char c = text.charAt(pos.index);
+                        if (c == '+') {
+                            sign = 1;
+                        } else if (c == '-') {
+                            sign = -1;
                         }
-
-                        // Look for hours.
-                        try {
-                            char c = text.charAt(++pos.index);
-                            if (c < '0' || c > '9') { /* must be from '0' to '9'. */
-                                break parsing;
-                            }
-                            num = c - '0';
-
-                            if (text.charAt(++pos.index) != ':') {
-                                c = text.charAt(pos.index);
-                                if (c < '0' || c > '9') { /* must be from '0' to '9'. */
-                                    break parsing;
+                        if (sign == 0) {
+                            // Try parsing a custom time zone "GMT+hh:mm" or "GMT".
+                            if ((c == 'G' || c == 'g')
+                                && (text.length() - start) >= GMT.length()
+                                && text.regionMatches(true, start, GMT, 0, GMT.length())) {
+                                pos.index = start + GMT.length();
+
+                                if ((text.length() - pos.index) > 0) {
+                                    c = text.charAt(pos.index);
+                                    if (c == '+') {
+                                        sign = 1;
+                                    } else if (c == '-') {
+                                        sign = -1;
+                                    }
                                 }
-                                num *= 10;
-                                num += c - '0';
-                                pos.index++;
-                            }
-                            if (num > 23) {
-                                --pos.index;
-                                break parsing;
-                            }
-                            if  (text.charAt(pos.index) != ':') {
-                                break parsing;
-                            }
 
-                            // Look for minutes.
-                            offset = num * 60;
-                            c = text.charAt(++pos.index);
-                            if (c < '0' || c > '9') { /* must be from '0' to '9'. */
-                                break parsing;
-                            }
-                            num = c - '0';
-                            c = text.charAt(++pos.index);
-                            if (c < '0' || c > '9') { /* must be from '0' to '9'. */
-                                break parsing;
-                            }
-                            num *= 10;
-                            num += c - '0';
+                                if (sign == 0) {    /* "GMT" without offset */
+                                    calb.set(Calendar.ZONE_OFFSET, 0)
+                                        .set(Calendar.DST_OFFSET, 0);
+                                    return pos.index;
+                                }
 
-                            if (num > 59) {
-                                break parsing;
-                            }
-                        } catch (StringIndexOutOfBoundsException e) {
-                            break parsing;
-                        }
-                        offset += num;
-                        // Fall through for final processing below of 'offset' and 'sign'.
-                    } else {
-                        // If the first character is a sign, look for numeric timezones of
-                        // the form [+-]hhmm as specified by RFC 822. Otherwise, check
-                        // for named time zones by looking through the locale data from
-                        // the TimeZoneNames strings.
-                        try {
-                            char c = text.charAt(pos.index);
-                            if (c == '+') {
-                                sign = 1;
-                            } else if (c == '-') {
-                                sign = -1;
+                                // Parse the rest as "hh:mm"
+                                int i = subParseNumericZone(text, ++pos.index,
+                                                            sign, 0, true, calb);
+                                if (i > 0) {
+                                    return i;
+                                }
+                                pos.index = -i;
                             } else {
-                                // Try parsing the text as a time zone name (abbr).
+                                // Try parsing the text as a time zone
+                                // name or abbreviation.
                                 int i = subParseZoneString(text, pos.index, calb);
-                                if (i != 0) {
+                                if (i > 0) {
                                     return i;
                                 }
-                                break parsing;
-                            }
-
-                            // Parse the text as an RFC 822 time zone string. This code is
-                            // actually a little more permissive than RFC 822.  It will
-                            // try to do its best with numbers that aren't strictly 4
-                            // digits long.
-
-                            // Look for hh.
-                            int hours = 0;
-                            c = text.charAt(++pos.index);
-                            if (c < '0' || c > '9') { /* must be from '0' to '9'. */
-                                break parsing;
+                                pos.index = -i;
                             }
-                            hours = c - '0';
-                            c = text.charAt(++pos.index);
-                            if (c < '0' || c > '9') { /* must be from '0' to '9'. */
-                                break parsing;
-                            }
-                            hours *= 10;
-                            hours += c - '0';
-
-                            if (hours > 23) {
-                                break parsing;
-                            }
-
-                            // Look for mm.
-                            int minutes = 0;
-                            c = text.charAt(++pos.index);
-                            if (c < '0' || c > '9') { /* must be from '0' to '9'. */
-                                break parsing;
-                            }
-                            minutes = c - '0';
-                            c = text.charAt(++pos.index);
-                            if (c < '0' || c > '9') { /* must be from '0' to '9'. */
-                                break parsing;
-                            }
-                            minutes *= 10;
-                            minutes += c - '0';
-
-                            if (minutes > 59) {
-                                break parsing;
+                        } else {
+                            // Parse the rest as "hhmm" (RFC 822)
+                            int i = subParseNumericZone(text, ++pos.index,
+                                                        sign, 0, false, calb);
+                            if (i > 0) {
+                                return i;
                             }
-
-                            offset = hours * 60 + minutes;
-                        } catch (StringIndexOutOfBoundsException e) {
-                            break parsing;
+                            pos.index = -i;
                         }
-                    }
-
-                    // Do the final processing for both of the above cases.  We only
-                    // arrive here if the form GMT+/-... or an RFC 822 form was seen.
-                    if (sign != 0) {
-                        offset *= MILLIS_PER_MINUTE * sign;
-                        calb.set(Calendar.ZONE_OFFSET, offset).set(Calendar.DST_OFFSET, 0);
-                        return ++pos.index;
+                    } catch (IndexOutOfBoundsException e) {
                     }
                 }
                 break parsing;
 
             case PATTERN_ISO_ZONE:   // 'X'
                 {
-                    int sign = 0;
-                    int offset = 0;
-
-                    iso8601: {
-                        try {
-                            char c = text.charAt(pos.index);
-                            if (c == 'Z') {
-                                calb.set(Calendar.ZONE_OFFSET, 0).set(Calendar.DST_OFFSET, 0);
-                                return ++pos.index;
-                            }
-
-                            // parse text as "+/-hh[[:]mm]" based on count
-                            if (c == '+') {
-                                sign = 1;
-                            } else if (c == '-') {
-                                sign = -1;
-                            }
-                            // Look for hh.
-                            int hours = 0;
-                            c = text.charAt(++pos.index);
-                            if (c < '0' || c > '9') { /* must be from '0' to '9'. */
-                                break parsing;
-                            }
-                            hours = c - '0';
-                            c = text.charAt(++pos.index);
-                            if (c < '0' || c > '9') { /* must be from '0' to '9'. */
-                                break parsing;
-                            }
-                            hours *= 10;
-                            hours += c - '0';
-                            if (hours > 23) {
-                                break parsing;
-                            }
-
-                            if (count == 1) { // "X"
-                                offset = hours * 60;
-                                break iso8601;
-                            }
-
-                            c = text.charAt(++pos.index);
-                            // Skip ':' if "XXX"
-                            if (c == ':') {
-                                if (count == 2) {
-                                    break parsing;
-                                }
-                                c = text.charAt(++pos.index);
-                            } else {
-                                if (count == 3) {
-                                    // missing ':'
-                                    break parsing;
-                                }
-                            }
-
-                            // Look for mm.
-                            int minutes = 0;
-                            if (c < '0' || c > '9') { /* must be from '0' to '9'. */
-                                break parsing;
-                            }
-                            minutes = c - '0';
-                            c = text.charAt(++pos.index);
-                            if (c < '0' || c > '9') { /* must be from '0' to '9'. */
-                                break parsing;
-                            }
-                            minutes *= 10;
-                            minutes += c - '0';
-
-                            if (minutes > 59) {
-                                break parsing;
-                            }
-
-                            offset = hours * 60 + minutes;
-                        } catch (StringIndexOutOfBoundsException e) {
-                            break parsing;
-                        }
+                    if ((text.length() - pos.index) <= 0) {
+                        break parsing;
                     }
 
-                    // Do the final processing for both of the above cases.  We only
-                    // arrive here if the form GMT+/-... or an RFC 822 form was seen.
-                    if (sign != 0) {
-                        offset *= MILLIS_PER_MINUTE * sign;
-                        calb.set(Calendar.ZONE_OFFSET, offset).set(Calendar.DST_OFFSET, 0);
+                    int sign = 0;
+                    char c = text.charAt(pos.index);
+                    if (c == 'Z') {
+                        calb.set(Calendar.ZONE_OFFSET, 0).set(Calendar.DST_OFFSET, 0);
                         return ++pos.index;
                     }
+
+                    // parse text as "+/-hh[[:]mm]" based on count
+                    if (c == '+') {
+                        sign = 1;
+                    } else if (c == '-') {
+                        sign = -1;
+                    } else {
+                        ++pos.index;
+                        break parsing;
+                    }
+                    int i = subParseNumericZone(text, ++pos.index, sign, count,
+                                                count == 3, calb);
+                    if (i > 0) {
+                        return i;
+                    }
+                    pos.index = -i;
                 }
                 break parsing;
 
diff --git a/src/share/classes/java/util/Locale.java b/src/share/classes/java/util/Locale.java
index ecaa9cca68a4a35feeb266d6f06194e2a4949e53..1f0fbba1eaea8214b94ade566cddc02b94b0830b 100644
--- a/src/share/classes/java/util/Locale.java
+++ b/src/share/classes/java/util/Locale.java
@@ -1449,10 +1449,15 @@ public final class Locale implements Cloneable, Serializable {
      * three-letter language abbreviation is not available for this locale.
      */
     public String getISO3Language() throws MissingResourceException {
-        String language3 = getISO3Code(_baseLocale.getLanguage(), LocaleISOData.isoLanguageTable);
+        String lang = _baseLocale.getLanguage();
+        if (lang.length() == 3) {
+            return lang;
+        }
+
+        String language3 = getISO3Code(lang, LocaleISOData.isoLanguageTable);
         if (language3 == null) {
             throw new MissingResourceException("Couldn't find 3-letter language code for "
-                    + _baseLocale.getLanguage(), "FormatData_" + toString(), "ShortLanguage");
+                    + lang, "FormatData_" + toString(), "ShortLanguage");
         }
         return language3;
     }
diff --git a/src/share/classes/javax/sound/midi/MidiSystem.java b/src/share/classes/javax/sound/midi/MidiSystem.java
index d3ce81e22939160461f62e9f22014999d35bb259..b2a47dc96540cbf76878015be43f5a941706e9f5 100644
--- a/src/share/classes/javax/sound/midi/MidiSystem.java
+++ b/src/share/classes/javax/sound/midi/MidiSystem.java
@@ -310,7 +310,7 @@ public class MidiSystem {
         } else {
             transmitter = device.getTransmitter();
         }
-        if (!(transmitter instanceof MidiDeviceReceiver)) {
+        if (!(transmitter instanceof MidiDeviceTransmitter)) {
             transmitter = new MidiDeviceTransmitterEnvelope(device, transmitter);
         }
         return transmitter;
diff --git a/src/share/classes/javax/swing/JSlider.java b/src/share/classes/javax/swing/JSlider.java
index 156b9e4fb99ed32700204703856a0af14d236e91..8d188b95bf8d2a42b639d9aef2daeff0d1b179c4 100644
--- a/src/share/classes/javax/swing/JSlider.java
+++ b/src/share/classes/javax/swing/JSlider.java
@@ -40,7 +40,8 @@ import java.beans.*;
 
 /**
  * A component that lets the user graphically select a value by sliding
- * a knob within a bounded interval.
+ * a knob within a bounded interval. The knob is always positioned
+ * at the points that match integer values within the specified interval.
  * 

* The slider can show both * major tick marks, and minor tick marks between the major ones. The number of diff --git a/src/share/classes/javax/swing/plaf/basic/BasicSpinnerUI.java b/src/share/classes/javax/swing/plaf/basic/BasicSpinnerUI.java index b26f226c043a32df235121c29515219f36c76ea6..a57638e39ebb5c01121b679aac07017351c91a32 100644 --- a/src/share/classes/javax/swing/plaf/basic/BasicSpinnerUI.java +++ b/src/share/classes/javax/swing/plaf/basic/BasicSpinnerUI.java @@ -908,6 +908,14 @@ public class BasicSpinnerUI extends SpinnerUI int height = parent.getHeight(); Insets insets = parent.getInsets(); + + if (nextButton == null && previousButton == null) { + setBounds(editor, insets.left, insets.top, width - insets.left - insets.right, + height - insets.top - insets.bottom); + + return; + } + Dimension nextD = preferredSize(nextButton); Dimension previousD = preferredSize(previousButton); int buttonsWidth = Math.max(nextD.width, previousD.width); diff --git a/src/share/classes/sun/awt/FontConfiguration.java b/src/share/classes/sun/awt/FontConfiguration.java index a2593cc2ff5ea98ebcfdc4e96b92ff5c8ab9736c..ba8f6e56a014f0b9a254cf917361293e572541de 100644 --- a/src/share/classes/sun/awt/FontConfiguration.java +++ b/src/share/classes/sun/awt/FontConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -37,10 +37,10 @@ import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; import java.security.AccessController; import java.security.PrivilegedAction; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; -import java.util.Iterator; import java.util.Locale; import java.util.Map.Entry; import java.util.Properties; @@ -329,6 +329,8 @@ public abstract class FontConfiguration { * tables. */ public static void saveBinary(OutputStream out) throws IOException { + sanityCheck(); + DataOutputStream dataOut = new DataOutputStream(out); writeShortTable(dataOut, head); writeShortTable(dataOut, table_scriptIDs); @@ -350,7 +352,6 @@ public abstract class FontConfiguration { if (verbose) { dump(); } - sanityCheck(); } //private static boolean loadingProperties; @@ -1343,6 +1344,11 @@ public abstract class FontConfiguration { private static short[] table_stringIDs; private static char[] table_stringTable; + /** + * Checks consistencies of complied fontconfig data. This method + * is called only at the build-time from + * build.tools.compilefontconfig.CompileFontConfig. + */ private static void sanityCheck() { int errors = 0; @@ -1358,12 +1364,20 @@ public abstract class FontConfiguration { //componentFontNameID starts from "1" for (int ii = 1; ii < table_filenames.length; ii++) { if (table_filenames[ii] == -1) { - System.out.println("\n Warning: " - + " entry is missing!!!"); - if (!osName.contains("Linux")) { + // The corresponding finename entry for a component + // font name is mandatory on Windows, but it's + // optional on Solaris and Linux. + if (osName.contains("Windows")) { + System.err.println("\n Error: entry is missing!!!"); errors++; + } else { + if (verbose && !isEmpty(table_filenames)) { + System.err.println("\n Note: 'filename' entry is undefined for \"" + + getString(table_componentFontNameIDs[ii]) + + "\""); + } } } } @@ -1382,7 +1396,7 @@ public abstract class FontConfiguration { int jj = iii * NUM_STYLES + iij; short ffid = table_scriptFonts[fid + jj]; if (ffid == 0) { - System.out.println("\n Error: <" + System.err.println("\n Error: <" + getFontName(iii) + "." + getStyleName(iij) + "." + getString(table_scriptIDs[ii]) @@ -1402,7 +1416,7 @@ public abstract class FontConfiguration { script.contains("symbol")) { continue; } - System.out.println("\nError: " + System.err.println("\nError: " + " entry is missing!!!"); @@ -1411,11 +1425,19 @@ public abstract class FontConfiguration { } } if (errors != 0) { - System.out.println("!!THERE ARE " + errors + " ERROR(S) IN " + System.err.println("!!THERE ARE " + errors + " ERROR(S) IN " + "THE FONTCONFIG FILE, PLEASE CHECK ITS CONTENT!!\n"); System.exit(1); + } + } + private static boolean isEmpty(short[] a) { + for (short s : a) { + if (s != -1) { + return false; + } } + return true; } //dump the fontconfig data tables @@ -1652,20 +1674,16 @@ public abstract class FontConfiguration { private static void writeShortTable(DataOutputStream out, short[] data) throws IOException { - for (int i = 0; i < data.length; i++) { - out.writeShort(data[i]); + for (short val : data) { + out.writeShort(val); } } - private static short[] toList(HashMap map) { + private static short[] toList(HashMap map) { short[] list = new short[map.size()]; - for (int i = 0; i < list.length; i++) { - list[i] = -1; - } - Iterator iterator = map.entrySet().iterator(); - while (iterator.hasNext()) { - Entry entry = (Entry )iterator.next(); - list[entry.getValue().shortValue()] = getStringID(entry.getKey()); + Arrays.fill(list, (short) -1); + for (Entry entry : map.entrySet()) { + list[entry.getValue()] = getStringID(entry.getKey()); } return list; } @@ -1763,25 +1781,19 @@ public abstract class FontConfiguration { int len = table_scriptIDs.length + scriptFonts.size() * 20; table_scriptFonts = new short[len]; - Iterator iterator = scriptAllfonts.entrySet().iterator(); - while (iterator.hasNext()) { - Entry entry = (Entry )iterator.next(); - table_scriptFonts[entry.getKey().intValue()] = (short)entry.getValue().shortValue(); + for (Entry entry : scriptAllfonts.entrySet()) { + table_scriptFonts[entry.getKey().intValue()] = entry.getValue(); } int off = table_scriptIDs.length; - iterator = scriptFonts.entrySet().iterator(); - while (iterator.hasNext()) { - Entry entry = (Entry )iterator.next(); + for (Entry entry : scriptFonts.entrySet()) { table_scriptFonts[entry.getKey().intValue()] = (short)-off; Short[] v = entry.getValue(); - int i = 0; - while (i < 20) { + for (int i = 0; i < 20; i++) { if (v[i] != null) { - table_scriptFonts[off++] = v[i].shortValue(); + table_scriptFonts[off++] = v[i]; } else { table_scriptFonts[off++] = 0; } - i++; } } @@ -1792,9 +1804,7 @@ public abstract class FontConfiguration { //(3) sequences elcID -> XXXX[1|5] -> scriptID[] head[INDEX_sequences] = (short)(head[INDEX_elcIDs] + table_elcIDs.length); table_sequences = new short[elcIDs.size() * NUM_FONTS]; - iterator = sequences.entrySet().iterator(); - while (iterator.hasNext()) { - Entry entry = (Entry )iterator.next(); + for (Entry entry : sequences.entrySet()) { //table_sequences[entry.getKey().intValue()] = (short)-off; int k = entry.getKey().intValue(); short[] v = entry.getValue(); @@ -1827,31 +1837,24 @@ public abstract class FontConfiguration { //(6)componentFontNameID -> filenameID head[INDEX_filenames] = (short)(head[INDEX_componentFontNameIDs] + table_componentFontNameIDs.length); table_filenames = new short[table_componentFontNameIDs.length]; - for (int i = 0; i < table_filenames.length; i++) { - table_filenames[i] = -1; - } - iterator = filenames.entrySet().iterator(); - while (iterator.hasNext()) { - Entry entry = (Entry )iterator.next(); - table_filenames[entry.getKey().shortValue()] = entry.getValue().shortValue(); + Arrays.fill(table_filenames, (short) -1); + + for (Entry entry : filenames.entrySet()) { + table_filenames[entry.getKey()] = entry.getValue(); } //(7)scriptID-> awtfontpath //the paths are stored as scriptID -> stringID in awtfontpahts head[INDEX_awtfontpaths] = (short)(head[INDEX_filenames] + table_filenames.length); table_awtfontpaths = new short[table_scriptIDs.length]; - iterator = awtfontpaths.entrySet().iterator(); - while (iterator.hasNext()) { - Entry entry = (Entry )iterator.next(); - table_awtfontpaths[entry.getKey().shortValue()] = entry.getValue().shortValue(); + for (Entry entry : awtfontpaths.entrySet()) { + table_awtfontpaths[entry.getKey()] = entry.getValue(); } //(8)exclusions head[INDEX_exclusions] = (short)(head[INDEX_awtfontpaths] + table_awtfontpaths.length); table_exclusions = new short[scriptIDs.size()]; - iterator = exclusions.entrySet().iterator(); - while (iterator.hasNext()) { - Entry entry = (Entry )iterator.next(); + for (Entry entry : exclusions.entrySet()) { int[] exI = entry.getValue(); char[] exC = new char[exI.length * 2]; int j = 0; @@ -1859,17 +1862,15 @@ public abstract class FontConfiguration { exC[j++] = (char) (exI[i] >> 16); exC[j++] = (char) (exI[i] & 0xffff); } - table_exclusions[entry.getKey().shortValue()] = getStringID(new String (exC)); + table_exclusions[entry.getKey()] = getStringID(new String (exC)); } //(9)proportionals head[INDEX_proportionals] = (short)(head[INDEX_exclusions] + table_exclusions.length); table_proportionals = new short[proportionals.size() * 2]; - iterator = proportionals.entrySet().iterator(); int j = 0; - while (iterator.hasNext()) { - Entry entry = (Entry )iterator.next(); - table_proportionals[j++] = entry.getKey().shortValue(); - table_proportionals[j++] = entry.getValue().shortValue(); + for (Entry entry : proportionals.entrySet()) { + table_proportionals[j++] = entry.getKey(); + table_proportionals[j++] = entry.getValue(); } //(10) see (1) for info, the only difference is "xxx.motif" @@ -1878,22 +1879,18 @@ public abstract class FontConfiguration { len = table_scriptIDs.length + scriptFontsMotif.size() * 20; table_scriptFontsMotif = new short[len]; - iterator = scriptAllfontsMotif.entrySet().iterator(); - while (iterator.hasNext()) { - Entry entry = (Entry )iterator.next(); + for (Entry entry : scriptAllfontsMotif.entrySet()) { table_scriptFontsMotif[entry.getKey().intValue()] = - (short)entry.getValue().shortValue(); + (short)entry.getValue(); } off = table_scriptIDs.length; - iterator = scriptFontsMotif.entrySet().iterator(); - while (iterator.hasNext()) { - Entry entry = (Entry )iterator.next(); + for (Entry entry : scriptFontsMotif.entrySet()) { table_scriptFontsMotif[entry.getKey().intValue()] = (short)-off; Short[] v = entry.getValue(); int i = 0; while (i < 20) { if (v[i] != null) { - table_scriptFontsMotif[off++] = v[i].shortValue(); + table_scriptFontsMotif[off++] = v[i]; } else { table_scriptFontsMotif[off++] = 0; } @@ -1907,12 +1904,10 @@ public abstract class FontConfiguration { //(11)short[] alphabeticSuffix head[INDEX_alphabeticSuffix] = (short)(head[INDEX_scriptFontsMotif] + table_scriptFontsMotif.length); table_alphabeticSuffix = new short[alphabeticSuffix.size() * 2]; - iterator = alphabeticSuffix.entrySet().iterator(); j = 0; - while (iterator.hasNext()) { - Entry entry = (Entry )iterator.next(); - table_alphabeticSuffix[j++] = entry.getKey().shortValue(); - table_alphabeticSuffix[j++] = entry.getValue().shortValue(); + for (Entry entry : alphabeticSuffix.entrySet()) { + table_alphabeticSuffix[j++] = entry.getKey(); + table_alphabeticSuffix[j++] = entry.getValue(); } //(15)short[] fallbackScriptIDs; just put the ID in head diff --git a/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_CommonUtils.c b/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_CommonUtils.c index 3128efe252e120789feaadfcfe75dd2a5a9082a8..73ec25671d1e39bfc18f1a5e000eed14123c751a 100644 --- a/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_CommonUtils.c +++ b/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_CommonUtils.c @@ -137,41 +137,43 @@ void getALSAVersion(char* buffer, int len) { file = fopen(ALSA_VERSION_PROC_FILE, "r"); ALSAVersionString[0] = 0; if (file) { - fgets(ALSAVersionString, ALSAVersionString_LENGTH, file); - // parse for version number - totalLen = strlen(ALSAVersionString); - inVersionString = FALSE; - len = 0; - curr = 0; - while (curr < totalLen) { - if (!inVersionString) { - // is this char the beginning of a version string ? - if (ALSAVersionString[curr] >= '0' - && ALSAVersionString[curr] <= '9') { - inVersionString = TRUE; + if (NULL != fgets(ALSAVersionString, ALSAVersionString_LENGTH, file)) { + // parse for version number + totalLen = strlen(ALSAVersionString); + inVersionString = FALSE; + len = 0; + curr = 0; + while (curr < totalLen) { + if (!inVersionString) { + // is this char the beginning of a version string ? + if (ALSAVersionString[curr] >= '0' + && ALSAVersionString[curr] <= '9') { + inVersionString = TRUE; + } } - } - if (inVersionString) { - // the version string ends with white space - if (ALSAVersionString[curr] <= 32) { - break; - } - if (curr != len) { - // copy this char to the beginning of the string - ALSAVersionString[len] = ALSAVersionString[curr]; + if (inVersionString) { + // the version string ends with white space + if (ALSAVersionString[curr] <= 32) { + break; + } + if (curr != len) { + // copy this char to the beginning of the string + ALSAVersionString[len] = ALSAVersionString[curr]; + } + len++; } - len++; + curr++; } - curr++; - } - // remove trailing dots - while ((len > 0) && (ALSAVersionString[len - 1] == '.')) { - len--; + // remove trailing dots + while ((len > 0) && (ALSAVersionString[len - 1] == '.')) { + len--; + } + // null terminate + ALSAVersionString[len] = 0; } - // null terminate - ALSAVersionString[len] = 0; + fclose(file); + hasGottenALSAVersion = TRUE; } - hasGottenALSAVersion = TRUE; } strncpy(buffer, ALSAVersionString, len); } diff --git a/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_MidiIn.c b/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_MidiIn.c index a2277bdb6a0b3535b3e18bc4d13693b9c48fd2b1..db4a30ca330a0a9114b85c6ce69fbfbab2a75b0a 100644 --- a/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_MidiIn.c +++ b/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_MidiIn.c @@ -32,6 +32,9 @@ #include #include "PlatformMidi.h" #include "PLATFORM_API_LinuxOS_ALSA_MidiUtils.h" +#if defined(i586) +#include +#endif /* * Helper methods @@ -73,9 +76,38 @@ char* MIDI_IN_GetErrorStr(INT32 err) { return (char*) getErrorStr(err); } - INT32 MIDI_IN_GetNumDevices() { +/* Workaround for 6842956: 32bit app on 64bit linux + * gets assertion failure trying to open midiIn ports. + * Untill the issue is fixed in ALSA + * (https://bugtrack.alsa-project.org/alsa-bug/view.php?id=4807) + * report no midi in devices in the configuration. + */ +#if defined(i586) + static int jre32onlinux64 = -1; + if (jre32onlinux64 < 0) { + jre32onlinux64 = 0; + /* The workaround may be disabled setting "JAVASOUND_ENABLE_MIDIIN" + * environment variable. + */ + if (getenv("JAVASOUND_ENABLE_MIDIIN") == NULL) { + struct utsname u; + jre32onlinux64 = 0; + if (uname(&u) == 0) { + if (strstr(u.machine, "64") != NULL) { + TRACE0("jre32 on linux64 detected - report no midiIn devices\n"); + jre32onlinux64 = 1; + } + } + } + } + if (jre32onlinux64) { + return 0; + } +#endif + TRACE0("MIDI_IN_GetNumDevices()\n"); + return getMidiDeviceCount(SND_RAWMIDI_STREAM_INPUT); } diff --git a/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_MidiUtils.c b/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_MidiUtils.c index 74af23ef0420f86c025d0ee9df0e90067834feb3..7d2ac11923442835a582038a4fd7e45de2a1893d 100644 --- a/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_MidiUtils.c +++ b/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_MidiUtils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -372,7 +372,7 @@ INT32 openMidiDevice(snd_rawmidi_stream_t direction, INT32 deviceIndex, snd_rawmidi_t* native_handle; snd_midi_event_t* event_parser = NULL; int err; - UINT32 deviceID; + UINT32 deviceID = 0; char devicename[100]; #ifdef ALSA_MIDI_USE_PLUGHW int usePlugHw = 1; diff --git a/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_PCM.c b/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_PCM.c index 58ca8abfcc2980a01998e3d2551d1cccc3fd2974..fb2ba3c5da36a940d8d7a7e741bdfac65b44cf85 100644 --- a/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_PCM.c +++ b/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_PCM.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -127,7 +127,7 @@ void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* cre int ret; int sampleSizeInBytes, significantBits, isSigned, isBigEndian, enc; int origSampleSizeInBytes, origSignificantBits; - int channels, minChannels, maxChannels; + unsigned int channels, minChannels, maxChannels; int rate, bitIndex; for (bitIndex = 0; bitIndex <= MAX_BIT_INDEX; bitIndex++) handledBits[bitIndex] = FALSE; @@ -152,7 +152,6 @@ void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* cre } } snd_pcm_hw_params_get_format_mask(hwParams, formatMask); -#ifdef ALSA_PCM_NEW_HW_PARAMS_API if (ret == 0) { ret = snd_pcm_hw_params_get_channels_min(hwParams, &minChannels); if (ret != 0) { @@ -165,13 +164,6 @@ void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* cre ERROR1("snd_pcm_hw_params_get_channels_max returned error %d\n", ret); } } -#else - minChannels = snd_pcm_hw_params_get_channels_min(hwParams); - maxChannels = snd_pcm_hw_params_get_channels_max(hwParams); - if (minChannels > maxChannels) { - ERROR2("MinChannels=%d, maxChannels=%d\n", minChannels, maxChannels); - } -#endif // since we queried the hw: device, for many soundcards, it will only // report the maximum number of channels (which is the only way to talk @@ -222,7 +214,7 @@ void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* cre } else { for (channels = minChannels; channels <= maxChannels; channels++) { DAUDIO_AddAudioFormat(creator, significantBits, - (channels < 0)?-1:(sampleSizeInBytes * channels), + sampleSizeInBytes * channels, channels, rate, enc, isSigned, isBigEndian); } @@ -254,7 +246,7 @@ typedef struct tag_AlsaPcmInfo { snd_pcm_sw_params_t* swParams; int bufferSizeInBytes; int frameSize; // storage size in Bytes - int periods; + unsigned int periods; snd_pcm_uframes_t periodSize; #ifdef GET_POSITION_METHOD2 // to be used exclusively by getBytePosition! @@ -305,8 +297,8 @@ int setHWParams(AlsaPcmInfo* info, int channels, int bufferSizeInFrames, snd_pcm_format_t format) { - unsigned int rrate; - int ret, dir, periods, periodTime; + unsigned int rrate, periodTime, periods; + int ret, dir; snd_pcm_uframes_t alsaBufferSizeInFrames = (snd_pcm_uframes_t) bufferSizeInFrames; /* choose all parameters */ @@ -335,12 +327,8 @@ int setHWParams(AlsaPcmInfo* info, } /* set the stream rate */ rrate = (int) (sampleRate + 0.5f); -#ifdef ALSA_PCM_NEW_HW_PARAMS_API dir = 0; ret = snd_pcm_hw_params_set_rate_near(info->handle, info->hwParams, &rrate, &dir); -#else - ret = snd_pcm_hw_params_set_rate_near(info->handle, info->hwParams, rrate, 0); -#endif if (ret < 0) { ERROR2("Rate %dHz not available for playback: %s\n", (int) (sampleRate+0.5f), snd_strerror(ret)); return FALSE; @@ -350,12 +338,7 @@ int setHWParams(AlsaPcmInfo* info, return FALSE; } /* set the buffer time */ -#ifdef ALSA_PCM_NEW_HW_PARAMS_API - ret = snd_pcm_hw_params_set_buffer_size_near(info->handle, info->hwParams, &alsaBufferSizeInFrames); -#else - ret = snd_pcm_hw_params_set_buffer_size_near(info->handle, info->hwParams, alsaBufferSizeInFrames); -#endif if (ret < 0) { ERROR2("Unable to set buffer size to %d frames: %s\n", (int) alsaBufferSizeInFrames, snd_strerror(ret)); @@ -366,12 +349,7 @@ int setHWParams(AlsaPcmInfo* info, if (bufferSizeInFrames > 1024) { dir = 0; periodTime = DEFAULT_PERIOD_TIME; -#ifdef ALSA_PCM_NEW_HW_PARAMS_API ret = snd_pcm_hw_params_set_period_time_near(info->handle, info->hwParams, &periodTime, &dir); -#else - periodTime = snd_pcm_hw_params_set_period_time_near(info->handle, info->hwParams, periodTime, &dir); - ret = periodTime; -#endif if (ret < 0) { ERROR2("Unable to set period time to %d: %s\n", DEFAULT_PERIOD_TIME, snd_strerror(ret)); return FALSE; @@ -380,12 +358,7 @@ int setHWParams(AlsaPcmInfo* info, /* set the period count for very small buffer sizes to 2 */ dir = 0; periods = 2; -#ifdef ALSA_PCM_NEW_HW_PARAMS_API ret = snd_pcm_hw_params_set_periods_near(info->handle, info->hwParams, &periods, &dir); -#else - periods = snd_pcm_hw_params_set_periods_near(info->handle, info->hwParams, periods, &dir); - ret = periods; -#endif if (ret < 0) { ERROR2("Unable to set period count to %d: %s\n", /*periods*/ 2, snd_strerror(ret)); return FALSE; @@ -421,12 +394,6 @@ int setSWParams(AlsaPcmInfo* info) { ERROR1("Unable to set avail min for playback: %s\n", snd_strerror(ret)); return FALSE; } - /* align all transfers to 1 sample */ - ret = snd_pcm_sw_params_set_xfer_align(info->handle, info->swParams, 1); - if (ret < 0) { - ERROR1("Unable to set transfer align: %s\n", snd_strerror(ret)); - return FALSE; - } /* write the parameters to the playback device */ ret = snd_pcm_sw_params(info->handle, info->swParams); if (ret < 0) { @@ -448,7 +415,6 @@ void* DAUDIO_Open(INT32 mixerIndex, INT32 deviceID, int isSource, int ret = 0; AlsaPcmInfo* info = NULL; /* snd_pcm_uframes_t is 64 bit on 64-bit systems */ - snd_pcm_uframes_t alsaPeriodSize = 0; snd_pcm_uframes_t alsaBufferSizeInFrames = 0; @@ -484,21 +450,13 @@ void* DAUDIO_Open(INT32 mixerIndex, INT32 deviceID, int isSource, bufferSizeInBytes / frameSize, format)) { info->frameSize = frameSize; -#ifdef ALSA_PCM_NEW_HW_PARAMS_API - ret = snd_pcm_hw_params_get_period_size(info->hwParams, &alsaPeriodSize, &dir); - info->periodSize = (int) alsaPeriodSize; + ret = snd_pcm_hw_params_get_period_size(info->hwParams, &info->periodSize, &dir); if (ret < 0) { ERROR1("ERROR: snd_pcm_hw_params_get_period: %s\n", snd_strerror(ret)); } snd_pcm_hw_params_get_periods(info->hwParams, &(info->periods), &dir); snd_pcm_hw_params_get_buffer_size(info->hwParams, &alsaBufferSizeInFrames); info->bufferSizeInBytes = (int) alsaBufferSizeInFrames * frameSize; -#else - info->periodSize = snd_pcm_hw_params_get_period_size(info->hwParams, &dir); - info->periods = snd_pcm_hw_params_get_periods(info->hwParams, &dir); - info->bufferSizeInBytes = snd_pcm_hw_params_get_buffer_size(info->hwParams) * frameSize; - ret = 0; -#endif TRACE3(" DAUDIO_Open: period size = %d frames, periods = %d. Buffer size: %d bytes.\n", (int) info->periodSize, info->periods, info->bufferSizeInBytes); } diff --git a/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_PCMUtils.h b/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_PCMUtils.h index c8d920f8de6b61a115a7faefa6c18e3230d390bb..ca911d2f486d918cd983eef7ea06690cbdd82383 100644 --- a/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_PCMUtils.h +++ b/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_PCMUtils.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -24,6 +24,7 @@ */ // define this with a later version of ALSA than 0.9.0rc3 +// (starting from 1.0.0 it became default behaviour) #define ALSA_PCM_NEW_HW_PARAMS_API #include #include "Utilities.h" diff --git a/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_Ports.c b/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_Ports.c index 465ecadf0f92b1de9052189706d9db49be0d62f6..0db0e6c4b53ae1f994a8c9a96d10e9d3595312f5 100644 --- a/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_Ports.c +++ b/src/solaris/native/com/sun/media/sound/PLATFORM_API_LinuxOS_ALSA_Ports.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -380,7 +380,7 @@ void PORT_GetControls(void* id, INT32 portIndex, PortControlCreator* creator) { void* controls[10]; int numControls; char* portName; - int isPlayback; + int isPlayback = 0; int isMono; int isStereo; char* type; diff --git a/src/windows/lib/tzmappings b/src/windows/lib/tzmappings index bbc3ca09ce23c0baebc929c26bbd0ddc05a628ee..7f6f0d36052fc4ab7f514482cb944c1205a1d391 100644 --- a/src/windows/lib/tzmappings +++ b/src/windows/lib/tzmappings @@ -188,5 +188,6 @@ UTC-02:920,920::GMT-0200: UTC-11:921,921::GMT-1100: Ulaanbaatar Standard Time:922,922::Asia/Ulaanbaatar: Venezuela Standard Time:923,923::America/Caracas: -Western Brazilian Standard Time:924,924:BR:America/Rio_Branco: -Armenian Standard Time:925,925:AM:Asia/Yerevan: +Magadan Standard Time:924,924::Asia/Magadan: +Western Brazilian Standard Time:925,925:BR:America/Rio_Branco: +Armenian Standard Time:926,926:AM:Asia/Yerevan: diff --git a/test/java/text/Format/DateFormat/ISO8601ZoneTest.java b/test/java/text/Format/DateFormat/ISO8601ZoneTest.java index 2179948a849c2c0373d89163a9a1c060546a75d9..2a5c24125855398be4c64ae3c052ebbcc33bac19 100644 --- a/test/java/text/Format/DateFormat/ISO8601ZoneTest.java +++ b/test/java/text/Format/DateFormat/ISO8601ZoneTest.java @@ -60,48 +60,51 @@ public class ISO8601ZoneTest { "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", }; + // badData[][0] - format + // badData[][1] - (bad) text to be parsed + // badData[][2] - subtext at the end of which a parse error is detected static final String[][] badData = { - { "X", "1" }, - { "X", "+1" }, - { "X", "-2" }, - { "X", "-24" }, - { "X", "+24" }, - - { "XX", "9" }, - { "XX", "23" }, - { "XX", "234" }, - { "XX", "3456" }, - { "XX", "23456" }, - { "XX", "+1" }, - { "XX", "-12" }, - { "XX", "+123" }, - { "XX", "-12:34" }, - { "XX", "+12:34" }, - { "XX", "-2423" }, - { "XX", "+2423" }, - { "XX", "-1260" }, - { "XX", "+1260" }, - - { "XXX", "9" }, - { "XXX", "23" }, - { "XXX", "234" }, - { "XXX", "3456" }, - { "XXX", "23456" }, - { "XXX", "2:34" }, - { "XXX", "12:4" }, - { "XXX", "12:34" }, - { "XXX", "-1" }, - { "XXX", "+1" }, - { "XXX", "-12" }, - { "XXX", "+12" }, - { "XXX", "-123" }, - { "XXX", "+123" }, - { "XXX", "-1234" }, - { "XXX", "+1234" }, - { "XXX", "+24:23" }, - { "XXX", "+12:60" }, - { "XXX", "+1:23" }, - { "XXX", "+12:3" }, + { "X", "1", "1" }, + { "X", "+1", "+1" }, + { "X", "-2", "-2" }, + { "X", "-24", "-2" }, + { "X", "+24", "+2" }, + + { "XX", "9", "9" }, + { "XX", "23", "2" }, + { "XX", "234", "2" }, + { "XX", "3456", "3" }, + { "XX", "23456", "2" }, + { "XX", "+1", "+1" }, + { "XX", "-12", "-12" }, + { "XX", "+123", "+123" }, + { "XX", "-12:34", "-12" }, + { "XX", "+12:34", "+12" }, + { "XX", "-2423", "-2" }, + { "XX", "+2423", "+2" }, + { "XX", "-1260", "-126" }, + { "XX", "+1260", "+126" }, + + { "XXX", "9", "9" }, + { "XXX", "23", "2" }, + { "XXX", "234", "2" }, + { "XXX", "3456", "3" }, + { "XXX", "23456", "2" }, + { "XXX", "2:34", "2" }, + { "XXX", "12:4", "1" }, + { "XXX", "12:34", "1" }, + { "XXX", "-1", "-1" }, + { "XXX", "+1", "+1" }, + { "XXX", "-12", "-12" }, + { "XXX", "+12", "+12" }, + { "XXX", "-123", "-12" }, + { "XXX", "+123", "+12" }, + { "XXX", "-1234", "-12" }, + { "XXX", "+1234", "+12" }, + { "XXX", "+24:23", "+2" }, + { "XXX", "+12:60", "+12:6" }, + { "XXX", "+1:23", "+1" }, + { "XXX", "+12:3", "+12:3" }, }; static String[] badFormats = { @@ -110,6 +113,8 @@ public class ISO8601ZoneTest { public static void main(String[] args) throws Exception { TimeZone tz = TimeZone.getDefault(); + Locale loc = Locale.getDefault(); + Locale.setDefault(Locale.US); try { for (int i = 0; i < formatData.length; i++) { @@ -128,7 +133,7 @@ public class ISO8601ZoneTest { } for (String[] d : badData) { - badDataParsing(d[0], d[1]); + badDataParsing(d[0], d[1], d[2].length()); } for (String fmt : badFormats) { @@ -136,6 +141,7 @@ public class ISO8601ZoneTest { } } finally { TimeZone.setDefault(tz); + Locale.setDefault(loc); } } @@ -188,15 +194,24 @@ public class ISO8601ZoneTest { } - static void badDataParsing(String fmt, String text) { + static void badDataParsing(String fmt, String text, int expectedErrorIndex) { + SimpleDateFormat sdf = new SimpleDateFormat(fmt); try { - SimpleDateFormat sdf = new SimpleDateFormat(fmt); sdf.parse(text); throw new RuntimeException("didn't throw an exception: fmt=" + fmt + ", text=" + text); } catch (ParseException e) { // OK } + + ParsePosition pos = new ParsePosition(0); + Date d = sdf.parse(text, pos); + int errorIndex = pos.getErrorIndex(); + if (d != null || errorIndex != expectedErrorIndex) { + throw new RuntimeException("Bad error index=" + errorIndex + + ", expected=" + expectedErrorIndex + + ", fmt=" + fmt + ", text=" + text); + } } static void badFormat(String fmt) { diff --git a/test/java/text/Format/MessageFormat/Bug7003643.java b/test/java/text/Format/MessageFormat/Bug7003643.java new file mode 100644 index 0000000000000000000000000000000000000000..aeb722cac17203193811133c8b0ece4dc7d19528 --- /dev/null +++ b/test/java/text/Format/MessageFormat/Bug7003643.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 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 + * 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 7003643 + * @summary Make sure MessageFormat.toPattern produces correct quoting. (SPI part is tested in PluggableLocale tests.) + */ + +import java.text.*; +import java.util.*; + +public class Bug7003643 { + private static final int N = 5; + + private static final String[] elements = { + "'{'", "'{", "{", "''", "}", "a", "'", + }; + + public static void main(String[] args) { + Random rand = new Random(); + int count = 0; + int max = (int) (Math.pow((double)elements.length, (double)N)/0.52); + while (count < max) { + // Create a random pattern. If the produced pattern is + // valid, then proceed with the round-trip testing. + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < N; i++) { + sb.append(elements[rand.nextInt(elements.length)]); + } + String pattern = sb.toString(); + MessageFormat mf = null; + try { + mf = new MessageFormat(pattern); + } catch (IllegalArgumentException e) { + // bad pattern data + } + if (mf == null) { + continue; + } + count++; + String res1 = MessageFormat.format(pattern, 123); + String toPattern = mf.toPattern(); + String res2 = MessageFormat.format(toPattern, 123); + if (!res1.equals(res2)) { + String s = String.format("Failed%n pattern=\"%s\" => result=\"%s\"%n" + + " toPattern()=\"%s\" => result=\"%s\"%n", + pattern, res1, toPattern, res2); + throw new RuntimeException(s); + } + } + } +} diff --git a/test/java/util/Locale/LocaleTest.java b/test/java/util/Locale/LocaleTest.java index af00c6bba6cd83df197aca1a7cd62a77fb3252be..0c21a8ef3544b870269a16349a482425dafb5e80 100644 --- a/test/java/util/Locale/LocaleTest.java +++ b/test/java/util/Locale/LocaleTest.java @@ -24,7 +24,8 @@ * @test * @bug 4052404 4052440 4084688 4092475 4101316 4105828 4107014 4107953 4110613 * 4118587 4118595 4122371 4126371 4126880 4135316 4135752 4139504 4139940 4143951 - * 4147315 4147317 4147552 4335196 4778440 5010672 6475525 6544471 6627549 6786276 + * 4147315 4147317 4147552 4335196 4778440 4940539 5010672 6475525 6544471 6627549 + * 6786276 * @summary test Locales */ /* @@ -895,17 +896,28 @@ test commented out pending API-change approval } /** - * @bug 4147317 - * java.util.Locale.getISO3Language() works wrong for non ISO-3166 codes. - * Should throw an exception for unknown locales + * @bug 4147317 4940539 + * java.util.Locale.getISO3Language() works wrong for non ISO-639 codes. + * Should throw an exception for unknown locales, except they have three + * letter language codes. */ public void Test4147317() { - // Try with codes that are the wrong length but happen to match text - // at a valid offset in the mapping table + // Try a three letter language code, and check whether it is + // returned as is. Locale locale = new Locale("aaa", "CCC"); + String result = locale.getISO3Language(); + if (!result.equals("aaa")) { + errln("ERROR: getISO3Language() returns: " + result + + " for locale '" + locale + "' rather than returning it as is" ); + } + + // Try an invalid two letter language code, and check whether it + // throws a MissingResourceException. + locale = new Locale("zz", "CCC"); + try { - String result = locale.getISO3Language(); + result = locale.getISO3Language(); errln("ERROR: getISO3Language() returns: " + result + " for locale '" + locale + "' rather than exception" ); diff --git a/test/java/util/PluggableLocale/DateFormatProviderTest.java b/test/java/util/PluggableLocale/DateFormatProviderTest.java index 6112b6836a437472d97d0f8844631730315e8479..6d5ecd23f3a2e340e48bfa8b4812f30e69a5e02f 100644 --- a/test/java/util/PluggableLocale/DateFormatProviderTest.java +++ b/test/java/util/PluggableLocale/DateFormatProviderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -44,6 +44,7 @@ public class DateFormatProviderTest extends ProviderTest { availableLocalesTest(); objectValidityTest(); extendedVariantTest(); + messageFormatTest(); } void availableLocalesTest() { @@ -118,4 +119,48 @@ public class DateFormatProviderTest extends ProviderTest { } } } + + + private static final String[] TYPES = { + "date", + "time" + }; + private static final String[] MODIFIERS = { + "", + "short", + "medium", // Same as DEFAULT + "long", + "full" + }; + + void messageFormatTest() { + for (Locale target : providerloc) { + for (String type : TYPES) { + for (String modifier : MODIFIERS) { + String pattern, expected; + if (modifier.equals("")) { + pattern = String.format("%s={0,%s}", type, type); + } else { + pattern = String.format("%s={0,%s,%s}", type, type, modifier); + } + if (modifier.equals("medium")) { + // medium is default. + expected = String.format("%s={0,%s}", type, type); + } else { + expected = pattern; + } + MessageFormat mf = new MessageFormat(pattern, target); + Format[] fmts = mf.getFormats(); + if (fmts[0] instanceof SimpleDateFormat) { + continue; + } + String toPattern = mf.toPattern(); + if (!toPattern.equals(expected)) { + throw new RuntimeException("messageFormatTest: got '" + toPattern + + "', expected '" + expected + "'"); + } + } + } + } + } } diff --git a/test/java/util/PluggableLocale/DateFormatProviderTest.sh b/test/java/util/PluggableLocale/DateFormatProviderTest.sh index 0d7ad953fe209af41be14765e50cf35a94cf5954..228a2484a100b09bd22da771dad20e0add0f10d9 100644 --- a/test/java/util/PluggableLocale/DateFormatProviderTest.sh +++ b/test/java/util/PluggableLocale/DateFormatProviderTest.sh @@ -1,5 +1,5 @@ # -# Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2007, 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 @@ -23,6 +23,6 @@ #!/bin/sh # # @test -# @bug 4052440 +# @bug 4052440 7003643 # @summary DateFormatProvider tests # @run shell ExecTest.sh foo DateFormatProviderTest true diff --git a/test/java/util/PluggableLocale/NumberFormatProviderTest.java b/test/java/util/PluggableLocale/NumberFormatProviderTest.java index 93540bf1764da7281305d1b3702098b2181200b4..a7ebfb794975b15b3e95d350911244e9ebde2be0 100644 --- a/test/java/util/PluggableLocale/NumberFormatProviderTest.java +++ b/test/java/util/PluggableLocale/NumberFormatProviderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -29,6 +29,8 @@ import java.util.*; import sun.util.*; import sun.util.resources.*; +import com.foo.FooNumberFormat; + public class NumberFormatProviderTest extends ProviderTest { com.foo.NumberFormatProviderImpl nfp = new com.foo.NumberFormatProviderImpl(); @@ -43,6 +45,7 @@ public class NumberFormatProviderTest extends ProviderTest { NumberFormatProviderTest() { availableLocalesTest(); objectValidityTest(); + messageFormatTest(); } void availableLocalesTest() { @@ -72,14 +75,10 @@ public class NumberFormatProviderTest extends ProviderTest { } // result object - String resultCur = - ((DecimalFormat)NumberFormat.getCurrencyInstance(target)).toPattern(); - String resultInt = - ((DecimalFormat)NumberFormat.getIntegerInstance(target)).toPattern(); - String resultNum = - ((DecimalFormat)NumberFormat.getNumberInstance(target)).toPattern(); - String resultPer = - ((DecimalFormat)NumberFormat.getPercentInstance(target)).toPattern(); + String resultCur = getPattern(NumberFormat.getCurrencyInstance(target)); + String resultInt = getPattern(NumberFormat.getIntegerInstance(target)); + String resultNum = getPattern(NumberFormat.getNumberInstance(target)); + String resultPer = getPattern(NumberFormat.getPercentInstance(target)); // provider's object (if any) String providersCur = null; @@ -87,21 +86,21 @@ public class NumberFormatProviderTest extends ProviderTest { String providersNum = null; String providersPer = null; if (providerloc.contains(target)) { - DecimalFormat dfCur = (DecimalFormat)nfp.getCurrencyInstance(target); + NumberFormat dfCur = nfp.getCurrencyInstance(target); if (dfCur != null) { - providersCur = dfCur.toPattern(); + providersCur = getPattern(dfCur); } - DecimalFormat dfInt = (DecimalFormat)nfp.getIntegerInstance(target); + NumberFormat dfInt = nfp.getIntegerInstance(target); if (dfInt != null) { - providersInt = dfInt.toPattern(); + providersInt = getPattern(dfInt); } - DecimalFormat dfNum = (DecimalFormat)nfp.getNumberInstance(target); + NumberFormat dfNum = nfp.getNumberInstance(target); if (dfNum != null) { - providersNum = dfNum.toPattern(); + providersNum = getPattern(dfNum); } - DecimalFormat dfPer = (DecimalFormat)nfp.getPercentInstance(target); + NumberFormat dfPer = nfp.getPercentInstance(target); if (dfPer != null) { - providersPer = dfPer.toPattern(); + providersPer = getPattern(dfPer); } } @@ -174,4 +173,35 @@ public class NumberFormatProviderTest extends ProviderTest { } } } + + private static String getPattern(NumberFormat nf) { + if (nf instanceof DecimalFormat) { + return ((DecimalFormat)nf).toPattern(); + } + if (nf instanceof FooNumberFormat) { + return ((FooNumberFormat)nf).toPattern(); + } + return null; + } + + private static final String[] NUMBER_PATTERNS = { + "num={0,number}", + "num={0,number,currency}", + "num={0,number,percent}", + "num={0,number,integer}" + }; + + void messageFormatTest() { + for (Locale target : providerloc) { + for (String pattern : NUMBER_PATTERNS) { + MessageFormat mf = new MessageFormat(pattern, target); + String toPattern = mf.toPattern(); + if (!pattern.equals(toPattern)) { + throw new RuntimeException("MessageFormat.toPattern: got '" + + toPattern + + "', expected '" + pattern + "'"); + } + } + } + } } diff --git a/test/java/util/PluggableLocale/NumberFormatProviderTest.sh b/test/java/util/PluggableLocale/NumberFormatProviderTest.sh index 7967da9f070d1f4a9bd66a7bee05e8cc983a7c4f..7f4e902a91451bb0bf5daca113600d355109f14b 100644 --- a/test/java/util/PluggableLocale/NumberFormatProviderTest.sh +++ b/test/java/util/PluggableLocale/NumberFormatProviderTest.sh @@ -1,5 +1,5 @@ # -# Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2007, 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 @@ -23,6 +23,6 @@ #!/bin/sh # # @test -# @bug 4052440 +# @bug 4052440 7003643 # @summary NumberFormatProvider tests # @run shell ExecTest.sh foo NumberFormatProviderTest true diff --git a/test/java/util/PluggableLocale/fooprovider.jar b/test/java/util/PluggableLocale/fooprovider.jar index 29ea53fcca62228087b1f864009aa21447af46c2..c1b5723f9b95dad064ed0393dd878cd7d82f3c51 100644 Binary files a/test/java/util/PluggableLocale/fooprovider.jar and b/test/java/util/PluggableLocale/fooprovider.jar differ diff --git a/test/java/util/PluggableLocale/providersrc/DateFormatProviderImpl.java b/test/java/util/PluggableLocale/providersrc/DateFormatProviderImpl.java index 25e7b1769462d8df3c650854e588339e94797bb5..55bc8d5ae73f3d1c8cb9a7b40b7acc078c71ef51 100644 --- a/test/java/util/PluggableLocale/providersrc/DateFormatProviderImpl.java +++ b/test/java/util/PluggableLocale/providersrc/DateFormatProviderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -42,7 +42,7 @@ public class DateFormatProviderImpl extends DateFormatProvider { static String[] datePattern = { "yyyy'\u5e74'M'\u6708'd'\u65e5'", // full date pattern - "yyyy/MM/dd", // long date pattern + "yyyy/MMM/dd", // long date pattern "yyyy/MM/dd", // medium date pattern "yy/MM/dd" // short date pattern }; @@ -68,7 +68,7 @@ public class DateFormatProviderImpl extends DateFormatProvider { public DateFormat getDateInstance(int style, Locale locale) { for (int i = 0; i < avail.length; i ++) { if (Utils.supportsLocale(avail[i], locale)) { - return new SimpleDateFormat(datePattern[style]+dialect[i], locale); + return new FooDateFormat(datePattern[style]+dialect[i], locale); } } throw new IllegalArgumentException("locale is not supported: "+locale); @@ -77,7 +77,7 @@ public class DateFormatProviderImpl extends DateFormatProvider { public DateFormat getTimeInstance(int style, Locale locale) { for (int i = 0; i < avail.length; i ++) { if (Utils.supportsLocale(avail[i], locale)) { - return new SimpleDateFormat(timePattern[style]+dialect[i], locale); + return new FooDateFormat(timePattern[style]+dialect[i], locale); } } throw new IllegalArgumentException("locale is not supported: "+locale); @@ -86,7 +86,7 @@ public class DateFormatProviderImpl extends DateFormatProvider { public DateFormat getDateTimeInstance(int dateStyle, int timeStyle, Locale locale) { for (int i = 0; i < avail.length; i ++) { if (Utils.supportsLocale(avail[i], locale)) { - return new SimpleDateFormat( + return new FooDateFormat( datePattern[dateStyle]+" "+timePattern[timeStyle]+dialect[i], locale); } } diff --git a/test/java/util/PluggableLocale/providersrc/FooDateFormat.java b/test/java/util/PluggableLocale/providersrc/FooDateFormat.java new file mode 100644 index 0000000000000000000000000000000000000000..80d4ce2010fb6555b8ea6042f3a7b0dcd094d11f --- /dev/null +++ b/test/java/util/PluggableLocale/providersrc/FooDateFormat.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 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 + * 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. + */ + +package com.foo; + +import java.text.*; +import java.util.*; + +/** + * FooDateFormat provides SimpleDateFormat methods required for the SPI testing. + */ +public class FooDateFormat extends DateFormat { + private SimpleDateFormat sdf; + + public FooDateFormat(String pattern, Locale loc) { + sdf = new SimpleDateFormat(pattern, loc); + } + + @Override + public StringBuffer format(Date date, + StringBuffer toAppendTo, + FieldPosition fieldPosition) { + return sdf.format(date, toAppendTo, fieldPosition); + } + + @Override + public Date parse(String source, ParsePosition pos) { + return sdf.parse(source, pos); + } + + @Override + public boolean equals(Object other) { + return other instanceof FooDateFormat + && sdf.equals(((FooDateFormat)other).sdf); + } + + @Override + public int hashCode() { + return sdf.hashCode(); + } +} diff --git a/test/java/util/PluggableLocale/providersrc/FooNumberFormat.java b/test/java/util/PluggableLocale/providersrc/FooNumberFormat.java new file mode 100644 index 0000000000000000000000000000000000000000..d13bd7362fed3bb046ae3053479d971d1ec3f076 --- /dev/null +++ b/test/java/util/PluggableLocale/providersrc/FooNumberFormat.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 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 + * 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. + */ + +package com.foo; + +import java.text.*; + +/** + * FooNumberFormat provides DecimalFormat methods required for the SPI testing. + */ +public class FooNumberFormat extends NumberFormat { + private DecimalFormat df; + + public FooNumberFormat(String pattern, DecimalFormatSymbols dfs) { + df = new DecimalFormat(pattern, dfs); + } + + @Override + public StringBuffer format(double number, + StringBuffer toAppendTo, + FieldPosition pos) { + return df.format(number, toAppendTo, pos); + } + + @Override + public StringBuffer format(long number, + StringBuffer toAppendTo, + FieldPosition pos) { + return df.format(number, toAppendTo, pos); + } + + @Override + public Number parse(String source, ParsePosition parsePosition) { + return df.parse(source, parsePosition); + } + + @Override + public boolean equals(Object other) { + return other instanceof FooNumberFormat + && df.equals(((FooNumberFormat)other).df); + } + + @Override + public int hashCode() { + return df.hashCode(); + } + + // DecimalFormat specific methods required for testing + + public String toPattern() { + return df.toPattern(); + } + + public DecimalFormatSymbols getDecimalFormatSymbols() { + return df.getDecimalFormatSymbols(); + } + + public void setDecimalSeparatorAlwaysShown(boolean newValue) { + df.setDecimalSeparatorAlwaysShown(newValue); + } +} diff --git a/test/java/util/PluggableLocale/providersrc/Makefile b/test/java/util/PluggableLocale/providersrc/Makefile index a85ea065e981950aa2e5b8a3f872657f4f23beaa..8d2fa9cab808568a238929fef8847c7bc926c73b 100644 --- a/test/java/util/PluggableLocale/providersrc/Makefile +++ b/test/java/util/PluggableLocale/providersrc/Makefile @@ -28,6 +28,8 @@ FOOFILES_JAVA = \ DateFormatSymbolsProviderImpl.java \ DecimalFormatSymbolsProviderImpl.java \ NumberFormatProviderImpl.java \ + FooDateFormat.java \ + FooNumberFormat.java \ Utils.java BARFILES_JAVA = \ diff --git a/test/java/util/PluggableLocale/providersrc/NumberFormatProviderImpl.java b/test/java/util/PluggableLocale/providersrc/NumberFormatProviderImpl.java index 164de5e1db634982482a24c2e1f9697e4fd49d73..9aa677cf89bcaf004b3c1fd9c4a12c536a4d3d9a 100644 --- a/test/java/util/PluggableLocale/providersrc/NumberFormatProviderImpl.java +++ b/test/java/util/PluggableLocale/providersrc/NumberFormatProviderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -49,13 +49,15 @@ public class NumberFormatProviderImpl extends NumberFormatProvider { static String[] patterns = { "#,##0.###{0};-#,##0.###{1}", // decimal pattern + "#{0};(#){1}", // integer pattern "\u00A4#,##0{0};-\u00A4#,##0{1}", // currency pattern "#,##0%{0}" // percent pattern }; // Constants used by factory methods to specify a style of format. static final int NUMBERSTYLE = 0; - static final int CURRENCYSTYLE = 1; - static final int PERCENTSTYLE = 2; + static final int INTEGERSTYLE = 1; + static final int CURRENCYSTYLE = 2; + static final int PERCENTSTYLE = 3; public Locale[] getAvailableLocales() { return avail; @@ -68,10 +70,10 @@ public class NumberFormatProviderImpl extends NumberFormatProvider { MessageFormat.format(patterns[CURRENCYSTYLE], dialect[i], dialect[i]); - DecimalFormat df = new DecimalFormat(pattern, + FooNumberFormat nf = new FooNumberFormat(pattern, DecimalFormatSymbols.getInstance(locale)); - adjustForCurrencyDefaultFractionDigits(df); - return df; + adjustForCurrencyDefaultFractionDigits(nf); + return nf; } } throw new IllegalArgumentException("locale is not supported: "+locale); @@ -81,15 +83,15 @@ public class NumberFormatProviderImpl extends NumberFormatProvider { for (int i = 0; i < avail.length; i ++) { if (Utils.supportsLocale(avail[i], locale)) { String pattern = - MessageFormat.format(patterns[NUMBERSTYLE], + MessageFormat.format(patterns[INTEGERSTYLE], dialect[i], dialect[i]); - DecimalFormat df = new DecimalFormat(pattern, + FooNumberFormat nf = new FooNumberFormat(pattern, DecimalFormatSymbols.getInstance(locale)); - df.setMaximumFractionDigits(0); - df.setDecimalSeparatorAlwaysShown(false); - df.setParseIntegerOnly(true); - return df; + nf.setMaximumFractionDigits(0); + nf.setDecimalSeparatorAlwaysShown(false); + nf.setParseIntegerOnly(true); + return nf; } } throw new IllegalArgumentException("locale is not supported: "+locale); @@ -102,7 +104,7 @@ public class NumberFormatProviderImpl extends NumberFormatProvider { MessageFormat.format(patterns[NUMBERSTYLE], dialect[i], dialect[i]); - return new DecimalFormat(pattern, + return new FooNumberFormat(pattern, DecimalFormatSymbols.getInstance(locale)); } } @@ -115,7 +117,7 @@ public class NumberFormatProviderImpl extends NumberFormatProvider { String pattern = MessageFormat.format(patterns[PERCENTSTYLE], dialect[i]); - return new DecimalFormat(pattern, + return new FooNumberFormat(pattern, DecimalFormatSymbols.getInstance(locale)); } } @@ -126,8 +128,8 @@ public class NumberFormatProviderImpl extends NumberFormatProvider { * Adjusts the minimum and maximum fraction digits to values that * are reasonable for the currency's default fraction digits. */ - void adjustForCurrencyDefaultFractionDigits(DecimalFormat df) { - DecimalFormatSymbols dfs = df.getDecimalFormatSymbols(); + void adjustForCurrencyDefaultFractionDigits(FooNumberFormat nf) { + DecimalFormatSymbols dfs = nf.getDecimalFormatSymbols(); Currency currency = dfs.getCurrency(); if (currency == null) { try { @@ -138,15 +140,15 @@ public class NumberFormatProviderImpl extends NumberFormatProvider { if (currency != null) { int digits = currency.getDefaultFractionDigits(); if (digits != -1) { - int oldMinDigits = df.getMinimumFractionDigits(); + int oldMinDigits = nf.getMinimumFractionDigits(); // Common patterns are "#.##", "#.00", "#". // Try to adjust all of them in a reasonable way. - if (oldMinDigits == df.getMaximumFractionDigits()) { - df.setMinimumFractionDigits(digits); - df.setMaximumFractionDigits(digits); + if (oldMinDigits == nf.getMaximumFractionDigits()) { + nf.setMinimumFractionDigits(digits); + nf.setMaximumFractionDigits(digits); } else { - df.setMinimumFractionDigits(Math.min(digits, oldMinDigits)); - df.setMaximumFractionDigits(digits); + nf.setMinimumFractionDigits(Math.min(digits, oldMinDigits)); + nf.setMaximumFractionDigits(digits); } } } diff --git a/test/javax/swing/JFileChooser/4847375/bug4847375.java b/test/javax/swing/JFileChooser/4847375/bug4847375.java new file mode 100644 index 0000000000000000000000000000000000000000..8a9af80b672fe93699ba40034e4febee42cbf8c6 --- /dev/null +++ b/test/javax/swing/JFileChooser/4847375/bug4847375.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 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 + * 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 4847375 + * @summary JFileChooser Create New Folder button is disabled incorrectly + * @author Pavel Porvatov + */ + +import sun.awt.OSInfo; +import sun.awt.shell.ShellFolder; + +import javax.swing.*; +import java.awt.*; +import java.lang.reflect.Method; + +public class bug4847375 { + private final String newFolderToolTipText; + + private final String lookAndFeel; + + public static void main(String[] args) throws Exception { + if (OSInfo.getOSType() != OSInfo.OSType.WINDOWS) { + System.out.println("The test is suitable only for Windows OS. Skipped."); + + return; + } + + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + new bug4847375("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + + new bug4847375("javax.swing.plaf.metal.MetalLookAndFeel"); + } + }); + } + + private static Object[][] DIRECTORIES = new Object[][]{ + {"getDesktop", Boolean.TRUE}, + {"getDrives", Boolean.FALSE}, // My computer + {"getRecent", Boolean.TRUE}, + {"getNetwork", Boolean.FALSE}, + {"getPersonal", Boolean.TRUE}, + }; + + private bug4847375(String lookAndFeel) { + this.lookAndFeel = lookAndFeel; + + try { + UIManager.setLookAndFeel(lookAndFeel); + } catch (Exception e) { + fail("Cannot set LookAndFeel", e); + } + + JFileChooser fileChooser = new JFileChooser(); + + // Find button NewFolder + newFolderToolTipText = UIManager.getString("FileChooser.newFolderToolTipText", fileChooser.getLocale()); + + if (newFolderToolTipText == null || newFolderToolTipText.length() == 0) { + fail("Cannot find NewFolderButton in FileChooser (tooltip doesn't exist)"); + + return; + } + + JButton newFolderButton = findNewFolderButton(fileChooser); + + if (newFolderButton == null) { + fail("Cannot find NewFolderButton in FileChooser"); + + return; + } + + for (Object[] objects : DIRECTORIES) { + String getterName = (String) objects[0]; + Boolean enabledNewFolder = (Boolean) objects[1]; + + fileChooser.setCurrentDirectory(getWin32Folder(getterName)); + + if (newFolderButton.isEnabled() != enabledNewFolder) { + fail("Enabled state of NewFolderButton should be " + enabledNewFolder + + " for Win32ShellFolderManager2." + getterName + "()"); + } + } + } + + private JButton findNewFolderButton(Container container) { + JButton result = null; + + for (int i = 0; i < container.getComponentCount(); i++) { + Component c = container.getComponent(i); + + if (c instanceof JButton && newFolderToolTipText.equals(((JButton) c).getToolTipText())) { + if (result != null) { + fail("Two or more NewFolderButton found in FileChooser"); + } + + result = (JButton) c; + } + + if (c instanceof Container) { + JButton button = findNewFolderButton((Container) c); + + if (result == null) { + result = button; + } else { + if (button != null) { + fail("Two or more NewFolderButton found in FileChooser"); + } + } + } + } + + return result; + } + + private ShellFolder getWin32Folder(String getterName) { + try { + Class win32ShellFolderManager2 = Class.forName("sun.awt.shell.Win32ShellFolderManager2"); + + Method method = win32ShellFolderManager2.getDeclaredMethod(getterName); + method.setAccessible(true); + + return (ShellFolder) method.invoke(null); + } catch (Exception e) { + fail("Cannot call '" + getterName + "' in the Win32ShellFolderManager2 class", e); + + return null; + } + } + + private void fail(String s) { + throw new RuntimeException("Test failed: " + s); + } + + private void fail(String s, Throwable e) { + throw new RuntimeException("Test failed for LookAndFeel " + lookAndFeel + ": " + s, e); + } +} diff --git a/test/javax/swing/JScrollBar/6542335/bug6542335.java b/test/javax/swing/JScrollBar/6542335/bug6542335.java index 33e95d8ecac74a6c9c3963b5fc6f1566ef8e5c9b..d4ed4736e346a2f440632d5be534d37169619d3e 100644 --- a/test/javax/swing/JScrollBar/6542335/bug6542335.java +++ b/test/javax/swing/JScrollBar/6542335/bug6542335.java @@ -40,11 +40,13 @@ public class bug6542335 { private static MyScrollBarUI ui; public static void main(String[] args) throws Exception { - Robot robot = new Robot(); + final Robot robot = new Robot(); robot.setAutoDelay(10); SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit(); + final Rectangle[] thumbBounds = new Rectangle[1]; + SwingUtilities.invokeAndWait(new Runnable() { public void run() { final JFrame frame = new JFrame("bug6542335"); @@ -63,25 +65,39 @@ public class bug6542335 { rangeModel.setValue(50); sb.setModel(rangeModel); - frame.add(sb); + frame.add(sb, BorderLayout.NORTH); frame.setSize(200, 100); frame.setVisible(true); + + thumbBounds[0] = new Rectangle(ui.getThumbBounds()); } }); - Rectangle thumbBounds = new Rectangle(ui.getThumbBounds()); - toolkit.realSync(); - Point l = sb.getLocationOnScreen(); - robot.mouseMove(l.x + (int) (0.75 * sb.getWidth()), l.y + sb.getHeight()/2); - robot.mousePress(InputEvent.BUTTON1_MASK); - robot.mouseRelease(InputEvent.BUTTON1_MASK); + + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + Point l = sb.getLocationOnScreen(); + + robot.mouseMove(l.x + (int) (0.75 * sb.getWidth()), l.y + sb.getHeight() / 2); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + } + }); + toolkit.realSync(); - if (!thumbBounds.equals(ui.getThumbBounds())) { - throw new RuntimeException("Test failed"); - } + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + Rectangle newThumbBounds = ui.getThumbBounds(); + + if (!thumbBounds[0].equals(newThumbBounds)) { + throw new RuntimeException("Test failed.\nOld bounds: " + thumbBounds[0] + + "\nNew bounds: " + newThumbBounds); + } + } + }); } static class MyScrollBarUI extends BasicScrollBarUI { diff --git a/test/javax/swing/JSpinner/6532833/bug6532833.java b/test/javax/swing/JSpinner/6532833/bug6532833.java new file mode 100644 index 0000000000000000000000000000000000000000..184fe69d96d345d557e91137aa7ca63207317db5 --- /dev/null +++ b/test/javax/swing/JSpinner/6532833/bug6532833.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 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 + * 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 6532833 + @summary PIT: Metal LAF - The right side border is not shown for the Spinner after the removing the buttons + @author Pavel Porvatov +*/ + +import javax.swing.*; +import java.awt.*; + +public class bug6532833 { + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + JSpinner[] spinners = new JSpinner[2]; + + for (int i = 0; i < spinners.length; i++) { + JSpinner spinner = new JSpinner(); + + spinner.setValue(2010); + + Component arrowUp = spinner.getComponent(0); + Component arrowDown = spinner.getComponent(1); + + LayoutManager layout = spinner.getLayout(); + + layout.removeLayoutComponent(arrowUp); + layout.removeLayoutComponent(arrowDown); + + if (i == 1) { + spinner.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); + } + + spinners[i] = spinner; + } + + // Do layout of spinners components + JFrame frame = new JFrame(); + + for (JSpinner spinner : spinners) { + frame.getContentPane().add(spinner); + } + + frame.pack(); + + for (JSpinner spinner : spinners) { + Insets insets = spinner.getInsets(); + + if (spinner.getWidth() != insets.left + insets.right + spinner.getEditor().getWidth()) { + throw new RuntimeException("Spinner editor width is invalid"); + } + } + + frame.dispose(); + } + }); + } +}