mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 15:23:51 +00:00
dd679562b1
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 --HG-- extra : rebase_source : fec89c67317d7df041f3b237122fb7e20e32fe1b
231 lines
6.3 KiB
C++
231 lines
6.3 KiB
C++
/* -*- 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)
|
|
, mLastStrength(-1)
|
|
, mCollatorICU(nullptr)
|
|
{ }
|
|
|
|
nsCollation::~nsCollation()
|
|
{
|
|
#ifdef DEBUG
|
|
nsresult res =
|
|
#endif
|
|
CleanUpCollator();
|
|
NS_ASSERTION(NS_SUCCEEDED(res), "CleanUpCollator failed");
|
|
}
|
|
|
|
nsresult
|
|
nsCollation::ConvertStrength(const int32_t aNSStrength,
|
|
UCollationStrength* aICUStrength,
|
|
UColAttributeValue* aCaseLevelOut)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aICUStrength);
|
|
NS_ENSURE_TRUE((aNSStrength < 4), NS_ERROR_FAILURE);
|
|
|
|
UCollationStrength strength = UCOL_DEFAULT;
|
|
UColAttributeValue caseLevel = UCOL_OFF;
|
|
switch (aNSStrength) {
|
|
case kCollationCaseInSensitive:
|
|
strength = UCOL_PRIMARY;
|
|
break;
|
|
case kCollationCaseInsensitiveAscii:
|
|
strength = UCOL_SECONDARY;
|
|
break;
|
|
case kCollationAccentInsenstive:
|
|
caseLevel = UCOL_ON;
|
|
strength = UCOL_PRIMARY;
|
|
break;
|
|
case kCollationCaseSensitive:
|
|
strength = UCOL_TERTIARY;
|
|
break;
|
|
default:
|
|
NS_WARNING("Bad aNSStrength passed to ConvertStrength.");
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
*aICUStrength = strength;
|
|
*aCaseLevelOut = caseLevel;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsCollation::EnsureCollator(const int32_t newStrength)
|
|
{
|
|
NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED);
|
|
if (mHasCollator && (mLastStrength == newStrength))
|
|
return NS_OK;
|
|
|
|
nsresult res;
|
|
res = CleanUpCollator();
|
|
NS_ENSURE_SUCCESS(res, res);
|
|
|
|
UErrorCode status;
|
|
status = U_ZERO_ERROR;
|
|
mCollatorICU = ucol_open(mLocale.get(), &status);
|
|
NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE);
|
|
|
|
UCollationStrength strength;
|
|
UColAttributeValue caseLevel;
|
|
res = ConvertStrength(newStrength, &strength, &caseLevel);
|
|
NS_ENSURE_SUCCESS(res, res);
|
|
|
|
status = U_ZERO_ERROR;
|
|
ucol_setAttribute(mCollatorICU, UCOL_STRENGTH, strength, &status);
|
|
NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE);
|
|
ucol_setAttribute(mCollatorICU, UCOL_CASE_LEVEL, caseLevel, &status);
|
|
NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE);
|
|
ucol_setAttribute(mCollatorICU, UCOL_ALTERNATE_HANDLING, UCOL_DEFAULT, &status);
|
|
NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE);
|
|
ucol_setAttribute(mCollatorICU, UCOL_NUMERIC_COLLATION, UCOL_OFF, &status);
|
|
NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE);
|
|
ucol_setAttribute(mCollatorICU, UCOL_NORMALIZATION_MODE, UCOL_ON, &status);
|
|
NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE);
|
|
ucol_setAttribute(mCollatorICU, UCOL_CASE_FIRST, UCOL_DEFAULT, &status);
|
|
NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE);
|
|
|
|
mHasCollator = true;
|
|
|
|
mLastStrength = newStrength;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsCollation::CleanUpCollator(void)
|
|
{
|
|
if (mHasCollator) {
|
|
ucol_close(mCollatorICU);
|
|
mHasCollator = false;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCollation::Initialize(const nsACString& locale)
|
|
{
|
|
NS_ENSURE_TRUE((!mInit), NS_ERROR_ALREADY_INITIALIZED);
|
|
|
|
// 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)
|
|
{
|
|
NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED);
|
|
NS_ENSURE_ARG_POINTER(key);
|
|
NS_ENSURE_ARG_POINTER(outLen);
|
|
|
|
nsresult res = EnsureCollator(strength);
|
|
NS_ENSURE_SUCCESS(res, res);
|
|
|
|
uint32_t stringInLen = stringIn.Length();
|
|
|
|
const UChar* str = (const UChar*)stringIn.BeginReading();
|
|
|
|
int32_t keyLength = ucol_getSortKey(mCollatorICU, str, stringInLen, nullptr, 0);
|
|
NS_ENSURE_TRUE((stringInLen == 0 || keyLength > 0), NS_ERROR_FAILURE);
|
|
|
|
// Since key is freed elsewhere with free, allocate with malloc.
|
|
uint8_t* newKey = (uint8_t*)malloc(keyLength + 1);
|
|
if (!newKey) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
keyLength = ucol_getSortKey(mCollatorICU, str, stringInLen, newKey, keyLength + 1);
|
|
NS_ENSURE_TRUE((stringInLen == 0 || keyLength > 0), NS_ERROR_FAILURE);
|
|
|
|
*key = newKey;
|
|
*outLen = keyLength;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCollation::CompareString(int32_t strength, const nsAString& string1,
|
|
const nsAString& string2, int32_t* result)
|
|
{
|
|
NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED);
|
|
NS_ENSURE_ARG_POINTER(result);
|
|
*result = 0;
|
|
|
|
nsresult rv = EnsureCollator(strength);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
UCollationResult uresult;
|
|
uresult = ucol_strcoll(mCollatorICU,
|
|
(const UChar*)string1.BeginReading(),
|
|
string1.Length(),
|
|
(const UChar*)string2.BeginReading(),
|
|
string2.Length());
|
|
int32_t res;
|
|
switch (uresult) {
|
|
case UCOL_LESS:
|
|
res = -1;
|
|
break;
|
|
case UCOL_EQUAL:
|
|
res = 0;
|
|
break;
|
|
case UCOL_GREATER:
|
|
res = 1;
|
|
break;
|
|
default:
|
|
MOZ_CRASH("ucol_strcoll returned bad UCollationResult");
|
|
}
|
|
*result = res;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
nsCollation::CompareRawSortKey(const uint8_t* key1, uint32_t len1,
|
|
const uint8_t* key2, uint32_t len2,
|
|
int32_t* result)
|
|
{
|
|
NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED);
|
|
NS_ENSURE_ARG_POINTER(key1);
|
|
NS_ENSURE_ARG_POINTER(key2);
|
|
NS_ENSURE_ARG_POINTER(result);
|
|
*result = 0;
|
|
|
|
int32_t tmpResult = strcmp((const char*)key1, (const char*)key2);
|
|
int32_t res;
|
|
if (tmpResult < 0) {
|
|
res = -1;
|
|
} else if (tmpResult > 0) {
|
|
res = 1;
|
|
} else {
|
|
res = 0;
|
|
}
|
|
*result = res;
|
|
return NS_OK;
|
|
}
|