Bug 1391628 - Use fallback locale on nsICollation if locale is invalid. r=emk, a=lizzard
authorMakoto Kato <m_kato@ga2.so-net.ne.jp>
Thu, 24 Aug 2017 23:13:42 +0900
changeset 408520 e08568b12c294e87a2b0035cee4d9d174ccac0e8
parent 408519 b20ed3e703900cc9a64ebd17bb026a55a1e3f4ac
child 408521 b185b492e4eedf396ce4ca68bbfce04523025046
push idunknown
push userunknown
push dateunknown
reviewersemk, lizzard
bugs1391628
milestone56.0
Bug 1391628 - Use fallback locale on nsICollation if locale is invalid. r=emk, a=lizzard Original issue is that Microsoft Dynamics CRM uses invalid lang attribute in <xsl:sort>. <xsl:sort order="descending" select="@displayname[$sortColumnName='displayname'] | @name[$sortColumnName='name'] | exslt:node-set($FriendlyTypeNames)/types/type[@xmlName=current()/@datatype and $sortColumnName='datatype']" lang="$languageName"/> Our XSLT implementation detects "$languageName" as locale name, then use it to nsICollation. Until Gecko 54 for Windows, even if using invalid locale name for nsICollation, it uses platform locale as fallback. But from 55, we use same implementation as macOS's to use ICU. So this issue occurs. ICU implementation doesn't use fallback locale if it is invalid. We should use fallback locale if locale is invalid. Most code for fallback locale such as FallbackEncoding uses application locale, so use it. MozReview-Commit-ID: EKYkZG7Hnz0
intl/locale/nsCollation.cpp
intl/locale/tests/gtest/TestCollation.cpp
intl/locale/tests/gtest/moz.build
--- a/intl/locale/nsCollation.cpp
+++ b/intl/locale/nsCollation.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsCollation.h"
+#include "mozilla/intl/LocaleService.h"
 #include "nsIServiceManager.h"
 #include "nsString.h"
 
 NS_IMPL_ISUPPORTS(nsCollation, nsICollation)
 
 nsCollation::nsCollation()
   : mInit(false)
   , mHasCollator(false)
@@ -112,17 +113,30 @@ nsCollation::CleanUpCollator(void)
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCollation::Initialize(const nsACString& locale)
 {
   NS_ENSURE_TRUE((!mInit), NS_ERROR_ALREADY_INITIALIZED);
 
-  mLocale = locale;
+  // Check whether locale parameter is valid.  If no, use application locale
+  UErrorCode status = U_ZERO_ERROR;
+  UCollator* collator = ucol_open(PromiseFlatCString(locale).get(), &status);
+  if (U_SUCCESS(status)) {
+    mLocale = locale;
+  } else {
+    status = U_ZERO_ERROR;
+    mozilla::LocaleService::GetInstance()->GetAppLocaleAsLangTag(mLocale);
+    collator = ucol_open(mLocale.get(), &status);
+    if (NS_WARN_IF(U_FAILURE(status))) {
+      return NS_ERROR_UNEXPECTED;
+    }
+  }
+  ucol_close(collator);
 
   mInit = true;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsCollation::AllocateRawSortKey(int32_t strength, const nsAString& stringIn,
                                 uint8_t** key, uint32_t* outLen)
new file mode 100644
--- /dev/null
+++ b/intl/locale/tests/gtest/TestCollation.cpp
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+#include "mozilla/Services.h"
+#include "nsCollationCID.h"
+#include "nsComponentManagerUtils.h"
+#include "nsCOMPtr.h"
+#include "nsICollation.h"
+#include "nsString.h"
+
+TEST(Collation, AllocateRowSortKey) {
+  nsCOMPtr<nsICollationFactory> colFactory =
+    do_CreateInstance(NS_COLLATIONFACTORY_CONTRACTID);
+  ASSERT_TRUE(colFactory);
+
+  // Don't throw error even if locale name is invalid
+  nsCOMPtr<nsICollation> collator;
+  nsresult rv =
+    colFactory->CreateCollationForLocale(NS_LITERAL_CSTRING("$languageName"),
+                                         getter_AddRefs(collator));
+  ASSERT_TRUE(NS_SUCCEEDED(rv));
+
+  uint8_t* sortKey1 = nullptr;
+  uint32_t sortKeyLen1 = 0;
+  // Don't throw error even if locale name is invalid
+  rv = collator->AllocateRawSortKey(nsICollation::kCollationStrengthDefault,
+                                    NS_LITERAL_STRING("ABC"),
+                                    &sortKey1, &sortKeyLen1);
+  ASSERT_TRUE(NS_SUCCEEDED(rv));
+
+  uint8_t* sortKey2 = nullptr;
+  uint32_t sortKeyLen2 = 0;
+  // Don't throw error even if locale name is invalid
+  rv = collator->AllocateRawSortKey(nsICollation::kCollationStrengthDefault,
+                                    NS_LITERAL_STRING("DEF"),
+                                    &sortKey2, &sortKeyLen2);
+  ASSERT_TRUE(NS_SUCCEEDED(rv));
+
+  int32_t result;
+  rv = collator->CompareRawSortKey(sortKey1, sortKeyLen1,
+                                   sortKey2, sortKeyLen2, &result);
+  ASSERT_TRUE(NS_SUCCEEDED(rv));
+
+  ASSERT_TRUE(result < 0);
+
+  free(sortKey1);
+  free(sortKey2);
+}
--- a/intl/locale/tests/gtest/moz.build
+++ b/intl/locale/tests/gtest/moz.build
@@ -1,15 +1,16 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 UNIFIED_SOURCES += [
+    'TestCollation.cpp',
     'TestLocaleService.cpp',
     'TestLocaleServiceNegotiate.cpp',
 ]
 
 if CONFIG['ENABLE_INTL_API']:
     UNIFIED_SOURCES += [
         'TestDateTimeFormat.cpp',
         'TestOSPreferences.cpp',