Update ANGLE
[WebKit-https.git] / Source / WebCore / platform / Language.cpp
index e28e76e..ec4b349 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2013, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #include "Language.h"
 
 #include <wtf/HashMap.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/PlatformUserPreferredLanguages.h>
 #include <wtf/RetainPtr.h>
 #include <wtf/text/WTFString.h>
 
-#if PLATFORM(MAC)
+#if USE(CF) && !PLATFORM(WIN)
 #include <CoreFoundation/CoreFoundation.h>
 #endif
 
 namespace WebCore {
 
+static StaticLock userPreferredLanguagesMutex;
+
+static void registerLanguageDidChangeCallbackIfNecessary()
+{
+    static std::once_flag once;
+    std::call_once(
+        once,
+        [] {
+            setPlatformUserPreferredLanguagesChangedCallback(languageDidChange);
+        });
+}
+
 typedef HashMap<void*, LanguageChangeObserverFunction> ObserverMap;
 static ObserverMap& observerMap()
 {
-    DEFINE_STATIC_LOCAL(ObserverMap, map, ());
-    return map;
+    static NeverDestroyed<ObserverMap> map;
+    return map.get();
 }
 
 void addLanguageChangeObserver(void* context, LanguageChangeObserverFunction customObserver)
 {
+    registerLanguageDidChangeCallbackIfNecessary();
     observerMap().set(context, customObserver);
 }
 
@@ -72,27 +87,46 @@ String defaultLanguage()
 
 static Vector<String>& preferredLanguagesOverride()
 {
-    DEFINE_STATIC_LOCAL(Vector<String>, override, ());
+    static NeverDestroyed<Vector<String>> override;
     return override;
 }
 
+Vector<String> userPreferredLanguagesOverride()
+{
+    return preferredLanguagesOverride();
+}
+
 void overrideUserPreferredLanguages(const Vector<String>& override)
 {
     preferredLanguagesOverride() = override;
+    languageDidChange();
 }
-    
+
+static Vector<String> isolatedCopy(const Vector<String>& strings)
+{
+    Vector<String> copy;
+    copy.reserveInitialCapacity(strings.size());
+    for (auto& language : strings)
+        copy.uncheckedAppend(language.isolatedCopy());
+    return copy;
+}
+
 Vector<String> userPreferredLanguages()
 {
-    Vector<String>& override = preferredLanguagesOverride();
-    if (!override.isEmpty())
-        return override;
+    {
+        std::lock_guard<StaticLock> lock(userPreferredLanguagesMutex);
+        Vector<String>& override = preferredLanguagesOverride();
+        if (!override.isEmpty())
+            return isolatedCopy(override);
+    }
     
+    registerLanguageDidChangeCallbackIfNecessary();
     return platformUserPreferredLanguages();
 }
 
 static String canonicalLanguageIdentifier(const String& languageCode)
 {
-    String lowercaseLanguageCode = languageCode.lower();
+    String lowercaseLanguageCode = languageCode.convertToASCIILowercase();
     
     if (lowercaseLanguageCode.length() >= 3 && lowercaseLanguageCode[2] == '_')
         lowercaseLanguageCode.replace(2, 1, "-");
@@ -100,59 +134,56 @@ static String canonicalLanguageIdentifier(const String& languageCode)
     return lowercaseLanguageCode;
 }
 
-static String bestMatchingLanguage(const String& language, const Vector<String>& languageList)
+size_t indexOfBestMatchingLanguageInList(const String& language, const Vector<String>& languageList, bool& exactMatch)
 {
-    bool canMatchLanguageOnly = (language.length() == 2 || (language.length() >= 3 && language[2] == '-'));
+    String lowercaseLanguage = language.convertToASCIILowercase();
     String languageWithoutLocaleMatch;
     String languageMatchButNotLocale;
+    size_t languageWithoutLocaleMatchIndex = 0;
+    size_t languageMatchButNotLocaleMatchIndex = 0;
+    bool canMatchLanguageOnly = (lowercaseLanguage.length() == 2 || (lowercaseLanguage.length() >= 3 && lowercaseLanguage[2] == '-'));
 
     for (size_t i = 0; i < languageList.size(); ++i) {
         String canonicalizedLanguageFromList = canonicalLanguageIdentifier(languageList[i]);
 
-        if (language == canonicalizedLanguageFromList)
-            return languageList[i];
+        if (lowercaseLanguage == canonicalizedLanguageFromList) {
+            exactMatch = true;
+            return i;
+        }
 
         if (canMatchLanguageOnly && canonicalizedLanguageFromList.length() >= 2) {
-            if (language[0] == canonicalizedLanguageFromList[0] && language[1] == canonicalizedLanguageFromList[1]) {
-                if (!languageWithoutLocaleMatch.length() && canonicalizedLanguageFromList.length() == 2)
+            if (lowercaseLanguage[0] == canonicalizedLanguageFromList[0] && lowercaseLanguage[1] == canonicalizedLanguageFromList[1]) {
+                if (!languageWithoutLocaleMatch.length() && canonicalizedLanguageFromList.length() == 2) {
                     languageWithoutLocaleMatch = languageList[i];
-                if (!languageMatchButNotLocale.length() && canonicalizedLanguageFromList.length() >= 3)
+                    languageWithoutLocaleMatchIndex = i;
+                }
+                if (!languageMatchButNotLocale.length() && canonicalizedLanguageFromList.length() >= 3) {
                     languageMatchButNotLocale = languageList[i];
+                    languageMatchButNotLocaleMatchIndex = i;
+                }
             }
         }
     }
 
-    // If we have both a language-only match and a languge-but-not-locale match, return the 
+    exactMatch = false;
+
+    // If we have both a language-only match and a languge-but-not-locale match, return the
     // languge-only match as is considered a "better" match. For example, if the list
     // provided has both "en-GB" and "en" and the user prefers "en-US" we will return "en".
     if (languageWithoutLocaleMatch.length())
-        return languageWithoutLocaleMatch;
+        return languageWithoutLocaleMatchIndex;
 
     if (languageMatchButNotLocale.length())
-        return languageMatchButNotLocale;
-    
-    return emptyString();
-}
+        return languageMatchButNotLocaleMatchIndex;
 
-String preferredLanguageFromList(const Vector<String>& languageList)
-{
-    Vector<String> preferredLanguages = userPreferredLanguages();
-
-    for (size_t i = 0; i < preferredLanguages.size(); ++i) {
-        String bestMatch = bestMatchingLanguage(canonicalLanguageIdentifier(preferredLanguages[i]), languageList);
-
-        if (bestMatch.length())
-            return bestMatch;
-    }
-
-    return emptyString();
+    return languageList.size();
 }
 
 String displayNameForLanguageLocale(const String& localeName)
 {
-#if PLATFORM(MAC)
-    if (!localeName.isNull() && !localeName.isEmpty())
-        return CFLocaleCopyDisplayNameForPropertyValue(CFLocaleCopyCurrent(), kCFLocaleIdentifier, localeName.createCFString().get());
+#if USE(CF) && !PLATFORM(WIN)
+    if (!localeName.isEmpty())
+        return adoptCF(CFLocaleCopyDisplayNameForPropertyValue(adoptCF(CFLocaleCopyCurrent()).get(), kCFLocaleIdentifier, localeName.createCFString().get())).get();
 #endif
     return localeName;
 }