diff options
-rw-r--r-- | ChangeLog | 58 | ||||
-rw-r--r-- | java/text/DateFormatSymbols.java | 304 | ||||
-rw-r--r-- | native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkFontPeer.c | 6 |
3 files changed, 322 insertions, 46 deletions
@@ -1,3 +1,60 @@ +2012-07-01 Andrew John Hughes <ahughes@redhat.com> + + PR classpath/44052 + * java/text/DateFormatSymbols.java: + (DFSData): Inner immutable class for storing parsed + locale data. + (DFSData.DFSData(String[],String[],String,String[], + String[],String[],String[],String[],String[], + String[][])): Constructor to initialise a new instance + with property data. + (DFSData.getAMPMs()): Return a clone of the ampms array. + (DFSData.getEras()): Likewise for eras. + (DFSData.getLocalPatternChars()): Return the local pattern + characters. + (DFSData.getMonths()): Return a clone of the (long) months + array. + (DFSData.getShortMonths()): Likewise for the short months array. + (DFSData.getWeekdays()): Likewise for (long) weekdays. + (DFSData.getShortWeekdays()): Likewise for short weekdays. + (DFSData.getDateFormats()): Likewise for date formats. + (DFSData.getTimeFormats()): Likewise for time formats. + (DFSData.getZoneStrings()): Likewise for zone strings. + (dataCache): Cache of parsed locale data. + (getZoneStrings(List<ResourceBundle>,Locale)): + Make static so it can be called by retrieveData. + (formatsForKey(List<ResourceBundle>,String)): + Likewise. + (getString(List<ResourceBundle>, String)): Likewise. + (retrieveData(Locale)): Separate out retrieval of + locale data from constructor and store it in the cache. + (DateFormatSymbols(Locale)): Modify to call retrieveData + and set fields from the returned DFSData instance. + +2012-05-30 Andrew John Hughes <ahughes@redhat.com> + + * java/text/DateFormatSymbols.java: + (getZoneStrings(List<ResourceBundle>, Locale)): + Refactor to use existing list of resource bundles. + (formatsForKey(List<ResourceBundle>, String)): + Likewise and use new local getString method. + (getString(List<ResourceBundle>, String)): + Use first available String from most-specific locale + rather than the least-specific. + (DateFormatSymbols(Locale)): Use bundles for resolving + localPatternChars, dateFormats, timeFormats and runtimeZoneStrings + as well. + +2012-05-04 Andrew John Hughes <ahughes@redhat.com> + + * native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkFontPeer.c, + (font_map): Renamed from ft2_map. + (Java_gnu_java_awt_peer_gtk_GdkFontPeer_initStaticState(JNIEnv, + jclass)): Remove cast to pango_ft2_font_map_new. + (Java_gnu_java_awt_peer_gtk_GdKFontPeer_setFont(JNIEnv, + jobject,jstring,jint,jint)): Call pango_font_map_create_context + rather than deprecated pango_ft2_font_map_create_context. + 2012-05-01 Andrew John Hughes <ahughes@redhat.com> * java/text/DateFormatSymbols.java: @@ -7,6 +64,7 @@ 2012-04-30 Andreas Sewe <sewe@st.informatik.tu-darmstadt.de> + PR classpath/53171 * java/text/DateFormatSymbols.java: (U00A9): Pre-compile pattern for zone separation. (U00AE): Likewise for fields. diff --git a/java/text/DateFormatSymbols.java b/java/text/DateFormatSymbols.java index 6b0d3a13f..9d0ace65a 100644 --- a/java/text/DateFormatSymbols.java +++ b/java/text/DateFormatSymbols.java @@ -55,6 +55,10 @@ import java.util.Properties; import java.util.ResourceBundle; import java.util.ServiceLoader; import java.util.TimeZone; + +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ConcurrentHashMap; + import java.util.regex.Pattern; import java.util.spi.TimeZoneNameProvider; @@ -72,14 +76,6 @@ import java.util.spi.TimeZoneNameProvider; */ public class DateFormatSymbols implements java.io.Serializable, Cloneable { - String[] ampms; - String[] eras; - private String localPatternChars; - String[] months; - String[] shortMonths; - String[] shortWeekdays; - String[] weekdays; - /** * The set of properties for obtaining the metazone data. */ @@ -106,6 +102,169 @@ public class DateFormatSymbols implements java.io.Serializable, Cloneable private static final Pattern FIELD_SEP = Pattern.compile("\u00ae"); /** + * Class for storing DateFormatSymbols data parsed from the property files. + */ + private static class DFSData + { + private String[] ampms; + private String[] eras; + private String localPatternChars; + private String[] months; + private String[] shortMonths; + private String[] weekdays; + private String[] shortWeekdays; + private String[] dateFormats; + private String[] timeFormats; + private String[][] runtimeZoneStrings; + + /** + * Construct a new instance with the parsed data. + * + * @param ampms strings for "am" and "pm". + * @param eras strings for calendar eras. + * @param localPatternChars localised pattern characters. + * @param months strings for the months of the year. + * @param shortMonths short strings for the months of the year. + * @param weekdays strings for the days of the week. + * @param shortWeekdays short strings for the days of the week. + * @param dateFormats localised date formats. + * @param timeFormats localised time formats. + * @param runtimeZoneStrings localised time zone names. + */ + public DFSData(String[] ampms, String[] eras, String localPatternChars, + String[] months, String[] shortMonths, String[] weekdays, + String[] shortWeekdays, String[] dateFormats, + String[] timeFormats, String[][] runtimeZoneStrings) + { + this.ampms = ampms; + this.eras = eras; + this.localPatternChars = localPatternChars; + this.months = months; + this.shortMonths = shortMonths; + this.weekdays = weekdays; + this.shortWeekdays = shortWeekdays; + this.dateFormats = dateFormats; + this.timeFormats = timeFormats; + this.runtimeZoneStrings = runtimeZoneStrings; + } + + /** + * Accessor for the AM/PM data. + * + * @return the AM/PM strings. + */ + public String[] getAMPMs() + { + return ampms.clone(); + } + + /** + * Accessor for the era data. + * + * @return the era strings. + */ + public String[] getEras() + { + return eras.clone(); + } + + /** + * Accessor for the local pattern characters. + * + * @return the local pattern characters. + */ + public String getLocalPatternChars() + { + return localPatternChars; + } + + /** + * Accessor for the months of the year (long form). + * + * @return the months of the year (long form). + */ + public String[] getMonths() + { + return months.clone(); + } + + /** + * Accessor for the months of the year (short form). + * + * @return the months of the year (short form). + */ + public String[] getShortMonths() + { + return shortMonths.clone(); + } + + /** + * Accessor for the days of the week (long form). + * + * @return the days of the week (long form). + */ + public String[] getWeekdays() + { + return weekdays.clone(); + } + + /** + * Accessor for the days of the week (short form). + * + * @return the days of the week (short form). + */ + public String[] getShortWeekdays() + { + return shortWeekdays.clone(); + } + + /** + * Accessor for the date formats. + * + * @return the date formats. + */ + public String[] getDateFormats() + { + return dateFormats.clone(); + } + + /** + * Accessor for the time formats. + * + * @return the time formats. + */ + public String[] getTimeFormats() + { + return timeFormats.clone(); + } + + /** + * Accessor for the zone strings. + * + * @return the zone strings. + */ + public String[][] getZoneStrings() + { + // Perform a deep clone so subarrays aren't modifiable + String[][] clone = runtimeZoneStrings.clone(); + for (int a = 0; a < clone.length; ++a) + clone[a] = runtimeZoneStrings[a].clone(); + return clone; + } + + } + + private static final ConcurrentMap<Locale, DFSData> dataCache = new ConcurrentHashMap<Locale, DFSData>(); + + String[] ampms; + String[] eras; + private String localPatternChars; + String[] months; + String[] shortMonths; + String[] shortWeekdays; + String[] weekdays; + + /** * The timezone strings supplied by the runtime. */ private String[][] runtimeZoneStrings; @@ -185,17 +344,16 @@ public class DateFormatSymbols implements java.io.Serializable, Cloneable return data; } - private String[][] getZoneStrings(ResourceBundle res, Locale locale) + private static String[][] getZoneStrings(List<ResourceBundle> bundles, Locale locale) { List<String[]> allZones = new ArrayList<String[]>(); try { Map<String,String[]> systemZones = new HashMap<String,String[]>(); - while (true) + for (ResourceBundle bundle : bundles) { - int index = 0; String country = locale.getCountry(); - String data = res.getString("zoneStrings"); + String data = bundle.getString("zoneStrings"); String[] zones = ZONE_SEP.split(data); for (int a = 0; a < zones.length; ++a) { @@ -222,12 +380,6 @@ public class DateFormatSymbols implements java.io.Serializable, Cloneable } systemZones.put(strings[0], strings); } - if (res.getLocale() == Locale.ROOT) - break; - else - res = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", - LocaleHelper.getFallbackLocale(res.getLocale()), - ClassLoader.getSystemClassLoader()); } /* Final sanity check for missing values */ for (String[] zstrings : systemZones.values()) @@ -293,17 +445,95 @@ public class DateFormatSymbols implements java.io.Serializable, Cloneable return allZones.toArray(new String[allZones.size()][]); } - private String[] formatsForKey(ResourceBundle res, String key) + /** + * Retrieve the date or time formats for a specific key e.g. + * asking for "DateFormat" will return an array containing the + * full, long, medium and short date formats localised for + * the locales in the specified bundle. + * + * @param bundles the stack of bundles to check, most-specific first. + * @param key the type of format to retrieve. + * @param an array of localised strings for each format prefix. + */ + private static String[] formatsForKey(List<ResourceBundle> bundles, String key) { String[] values = new String[formatPrefixes.length]; for (int i = 0; i < formatPrefixes.length; i++) - values[i] = res.getString(formatPrefixes[i] + key); + values[i] = getString(bundles, formatPrefixes[i] + key); return values; } /** + * Simple wrapper around extracting a {@code String} from a + * {@code ResourceBundle}. Keep searching less-specific locales + * until a non-null non-empty value is found. + * + * @param bundles the stack of bundles to check, most-specific first. + * @param key the key of the value to retrieve. + * @return the first non-null non-empty String found or the last + * retrieved if one isn't found. + */ + private static String getString(List<ResourceBundle> bundles, String key) + { + String val = null; + for (ResourceBundle bundle : bundles) + { + val = bundle.getString(key); + if (val != null && !val.isEmpty()) + return val; + } + return val; + } + + /** + * Retrieves the locale data from the property files and constructs a + * {@code DFSData} instance for it. + * + * @param the locale for which data should be retrieved. + * @return the parsed data. + * @throws MissingResourceException if the resources for the specified + * locale could not be found or loaded. + */ + private static DFSData retrieveData(Locale locale) + throws MissingResourceException + { + DFSData data = dataCache.get(locale); + if (data == null) + { + ClassLoader ldr = ClassLoader.getSystemClassLoader(); + List<ResourceBundle> bundles = new ArrayList<ResourceBundle>(); + ResourceBundle res + = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", locale, ldr); + bundles.add(res); + Locale resLocale = res.getLocale(); + while (resLocale != Locale.ROOT) + { + res = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", + LocaleHelper.getFallbackLocale(resLocale), ldr); + bundles.add(res); + resLocale = res.getLocale(); + } + String[] lMonths = getStringArray(bundles, "months", 13); + String[] lWeekdays = getStringArray(bundles, "weekdays", 8); + data = new DFSData(getStringArray(bundles, "ampms", 2), + getStringArray(bundles, "eras", 2), + getString(bundles, "localPatternChars"), + lMonths, getStringArray(bundles, "shortMonths", 13, lMonths), + lWeekdays, getStringArray(bundles, "shortWeekdays", 8, lWeekdays), + formatsForKey(bundles, "DateFormat"), + formatsForKey(bundles, "TimeFormat"), + getZoneStrings(bundles, locale)); + DFSData cachedData = dataCache.putIfAbsent(locale, data); + // Use the earlier version if another thread beat us to it. + if (cachedData != null) + data = cachedData; + } + return data; + } + + /** * This method initializes a new instance of <code>DateFormatSymbols</code> * by loading the date format information for the specified locale. * This constructor only obtains instances using the runtime's resources; @@ -319,29 +549,17 @@ public class DateFormatSymbols implements java.io.Serializable, Cloneable public DateFormatSymbols (Locale locale) throws MissingResourceException { - ClassLoader ldr = ClassLoader.getSystemClassLoader(); - List<ResourceBundle> bundles = new ArrayList<ResourceBundle>(); - ResourceBundle res - = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", locale, ldr); - bundles.add(res); - Locale resLocale = res.getLocale(); - while (resLocale != Locale.ROOT) - { - res = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", - LocaleHelper.getFallbackLocale(resLocale), ldr); - bundles.add(res); - resLocale = res.getLocale(); - } - ampms = getStringArray(bundles, "ampms", 2); - eras = getStringArray(bundles, "eras", 2); - localPatternChars = res.getString("localPatternChars"); - months = getStringArray(bundles, "months", 13); - shortMonths = getStringArray(bundles, "shortMonths", 13, months); - weekdays = getStringArray(bundles, "weekdays", 8); - shortWeekdays = getStringArray(bundles, "shortWeekdays", 8, weekdays); - dateFormats = formatsForKey(res, "DateFormat"); - timeFormats = formatsForKey(res, "TimeFormat"); - runtimeZoneStrings = getZoneStrings(res, locale); + DFSData data = retrieveData(locale); + ampms = data.getAMPMs(); + eras = data.getEras(); + localPatternChars = data.getLocalPatternChars(); + months = data.getMonths(); + shortMonths = data.getShortMonths(); + weekdays = data.getWeekdays(); + shortWeekdays = data.getShortWeekdays(); + dateFormats = data.getDateFormats(); + timeFormats = data.getTimeFormats(); + runtimeZoneStrings = data.getZoneStrings(); } /** diff --git a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkFontPeer.c b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkFontPeer.c index a5e59f7e4..771b23e37 100644 --- a/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkFontPeer.c +++ b/native/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkFontPeer.c @@ -59,14 +59,14 @@ enum java_awt_font_baseline { java_awt_font_HANGING_BASELINE = 2 }; -static PangoFT2FontMap *ft2_map = NULL; +static PangoFontMap *font_map = NULL; JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkFontPeer_initStaticState (JNIEnv *env, jclass clazz __attribute__((unused))) { gtkpeer_init_font_IDs(env); - ft2_map = PANGO_FT2_FONT_MAP(pango_ft2_font_map_new()); + font_map = pango_ft2_font_map_new(); } JNIEXPORT void JNICALL @@ -287,7 +287,7 @@ Java_gnu_java_awt_peer_gtk_GdkFontPeer_setFont pango_font_description_set_size (pfont->desc, size * PANGO_SCALE); /* Create new context */ - pfont->ctx = pango_ft2_font_map_create_context (ft2_map); + pfont->ctx = pango_font_map_create_context (font_map); g_assert (pfont->ctx != NULL); pango_context_set_font_description (pfont->ctx, pfont->desc); |