Bug 1214169 - Always use ICU in nsCollationMacUC. r=emk.

This commit is contained in:
Gordon Su 2015-12-16 17:27:44 +09:00
parent 3c61437ab6
commit 41f1699bd8
4 changed files with 72 additions and 245 deletions

View File

@ -17,19 +17,9 @@ nsCollationMacUC::nsCollationMacUC()
: mInit(false)
, mHasCollator(false)
, mLocaleICU(nullptr)
, mLocale(nullptr)
, mLastStrength(-1)
, mCollatorICU(nullptr)
, mCollator(nullptr)
, mBuffer(nullptr)
, mBufferLen(1)
, mUseICU(true)
{
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
if (prefs) {
prefs->GetBoolPref("intl.collation.mac.use_icu", &mUseICU);
}
}
{ }
nsCollationMacUC::~nsCollationMacUC()
{
@ -38,16 +28,9 @@ nsCollationMacUC::~nsCollationMacUC()
#endif
CleanUpCollator();
NS_ASSERTION(NS_SUCCEEDED(res), "CleanUpCollator failed");
if (mUseICU) {
if (mLocaleICU) {
free(mLocaleICU);
mLocaleICU = nullptr;
}
} else {
if (mBuffer) {
free(mBuffer);
mBuffer = nullptr;
}
if (mLocaleICU) {
free(mLocaleICU);
mLocaleICU = nullptr;
}
}
@ -85,21 +68,6 @@ nsresult nsCollationMacUC::ConvertStrength(const int32_t aNSStrength,
return NS_OK;
}
nsresult nsCollationMacUC::StrengthToOptions(const int32_t aStrength,
UCCollateOptions* aOptions)
{
NS_ENSURE_ARG_POINTER(aOptions);
NS_ENSURE_TRUE((aStrength < 4), NS_ERROR_FAILURE);
// set our default collation options
UCCollateOptions options = kUCCollateStandardOptions | kUCCollatePunctuationSignificantMask;
if (aStrength & kCollationCaseInsensitiveAscii)
options |= kUCCollateCaseInsensitiveMask;
if (aStrength & kCollationAccentInsenstive)
options |= kUCCollateDiacritInsensitiveMask;
*aOptions = options;
return NS_OK;
}
nsresult nsCollationMacUC::ConvertLocaleICU(nsILocale* aNSLocale, char** aICULocale)
{
NS_ENSURE_ARG_POINTER(aNSLocale);
@ -122,24 +90,6 @@ nsresult nsCollationMacUC::ConvertLocaleICU(nsILocale* aNSLocale, char** aICULoc
return NS_OK;
}
nsresult nsCollationMacUC::ConvertLocale(nsILocale* aNSLocale, LocaleRef* aMacLocale)
{
NS_ENSURE_ARG_POINTER(aNSLocale);
NS_ENSURE_ARG_POINTER(aMacLocale);
nsAutoString localeString;
nsresult res = aNSLocale->GetCategory(NS_LITERAL_STRING("NSILOCALE_COLLATE"), localeString);
NS_ENSURE_TRUE(NS_SUCCEEDED(res) && !localeString.IsEmpty(),
NS_ERROR_FAILURE);
NS_LossyConvertUTF16toASCII tmp(localeString);
tmp.ReplaceChar('-', '_');
OSStatus err;
err = ::LocaleRefFromLocaleString(tmp.get(), aMacLocale);
NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE);
return NS_OK;
}
nsresult nsCollationMacUC::EnsureCollator(const int32_t newStrength)
{
NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED);
@ -150,42 +100,31 @@ nsresult nsCollationMacUC::EnsureCollator(const int32_t newStrength)
res = CleanUpCollator();
NS_ENSURE_SUCCESS(res, res);
if (mUseICU) {
NS_ENSURE_TRUE(mLocaleICU, NS_ERROR_NOT_INITIALIZED);
NS_ENSURE_TRUE(mLocaleICU, NS_ERROR_NOT_INITIALIZED);
UErrorCode status;
status = U_ZERO_ERROR;
mCollatorICU = ucol_open(mLocaleICU, &status);
NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE);
UErrorCode status;
status = U_ZERO_ERROR;
mCollatorICU = ucol_open(mLocaleICU, &status);
NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE);
UCollationStrength strength;
UColAttributeValue caseLevel;
res = ConvertStrength(newStrength, &strength, &caseLevel);
NS_ENSURE_SUCCESS(res, res);
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);
} else {
OSStatus err;
UCCollateOptions newOptions;
res = StrengthToOptions(newStrength, &newOptions);
NS_ENSURE_SUCCESS(res, res);
LocaleOperationVariant opVariant = 0; // default variant for now
err = ::UCCreateCollator(mLocale, opVariant, newOptions, &mCollator);
NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE);
}
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;
@ -196,14 +135,8 @@ nsresult nsCollationMacUC::EnsureCollator(const int32_t newStrength)
nsresult nsCollationMacUC::CleanUpCollator(void)
{
if (mHasCollator) {
if (mUseICU) {
ucol_close(mCollatorICU);
mHasCollator = false;
} else {
OSStatus err = ::UCDisposeCollator(&mCollator);
mHasCollator = false;
NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE);
}
ucol_close(mCollatorICU);
mHasCollator = false;
}
return NS_OK;
@ -223,11 +156,7 @@ NS_IMETHODIMP nsCollationMacUC::Initialize(nsILocale* locale)
locale = appLocale;
}
if (mUseICU) {
rv = ConvertLocaleICU(locale, &mLocaleICU);
} else {
rv = ConvertLocale(locale, &mLocale);
}
rv = ConvertLocaleICU(locale, &mLocaleICU);
NS_ENSURE_SUCCESS(rv, rv);
mInit = true;
@ -246,62 +175,21 @@ NS_IMETHODIMP nsCollationMacUC::AllocateRawSortKey(int32_t strength, const nsASt
uint32_t stringInLen = stringIn.Length();
if (mUseICU) {
const UChar* str = (const UChar*)PromiseFlatString(stringIn).get();
const UChar* str = (const UChar*)PromiseFlatString(stringIn).get();
int32_t keyLength = ucol_getSortKey(mCollatorICU, str, stringInLen, nullptr, 0);
NS_ENSURE_TRUE((stringInLen == 0 || keyLength > 0), NS_ERROR_FAILURE);
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 PR_Free, allocate with PR_Malloc.
uint8_t* newKey = (uint8_t*)PR_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;
}
uint32_t maxKeyLen = (1 + stringInLen) * kCollationValueSizeFactor * sizeof(UCCollationValue);
if (maxKeyLen > mBufferLen) {
uint32_t newBufferLen = mBufferLen;
do {
newBufferLen *= 2;
} while (newBufferLen < maxKeyLen);
void* newBuffer = malloc(newBufferLen);
if (!newBuffer) {
return NS_ERROR_OUT_OF_MEMORY;
}
if (mBuffer) {
free(mBuffer);
mBuffer = nullptr;
}
mBuffer = newBuffer;
mBufferLen = newBufferLen;
}
ItemCount actual;
OSStatus err = ::UCGetCollationKey(mCollator, (const UniChar*) PromiseFlatString(stringIn).get(),
(UniCharCount) stringInLen,
(ItemCount) (mBufferLen / sizeof(UCCollationValue)),
&actual, (UCCollationValue *)mBuffer);
NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE);
uint32_t keyLength = actual * sizeof(UCCollationValue);
// Since key is freed elsewhere with PR_Free, allocate with PR_Malloc.
void* newKey = PR_Malloc(keyLength);
uint8_t* newKey = (uint8_t*)PR_Malloc(keyLength + 1);
if (!newKey) {
return NS_ERROR_OUT_OF_MEMORY;
return NS_ERROR_OUT_OF_MEMORY;
}
memcpy(newKey, mBuffer, keyLength);
*key = (uint8_t *)newKey;
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;
@ -314,34 +202,28 @@ NS_IMETHODIMP nsCollationMacUC::CompareString(int32_t strength, const nsAString&
NS_ENSURE_ARG_POINTER(result);
*result = 0;
nsresult res = EnsureCollator(strength);
NS_ENSURE_SUCCESS(res, res);
nsresult rv = EnsureCollator(strength);
NS_ENSURE_SUCCESS(rv, rv);
if (mUseICU) {
UCollationResult uresult;
uresult = ucol_strcoll(mCollatorICU,
(const UChar*)PromiseFlatString(string1).get(), string1.Length(),
(const UChar*)PromiseFlatString(string2).get(), 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;
UCollationResult uresult;
uresult = ucol_strcoll(mCollatorICU,
(const UChar*)PromiseFlatString(string1).get(), string1.Length(),
(const UChar*)PromiseFlatString(string2).get(), 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 = 0;
OSStatus err;
err = ::UCCompareText(mCollator,
(const UniChar *) PromiseFlatString(string1).get(), (UniCharCount) string1.Length(),
(const UniChar *) PromiseFlatString(string2).get(), (UniCharCount) string2.Length(),
nullptr, (SInt32*) result);
NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE);
*result = res;
return NS_OK;
}
@ -355,26 +237,15 @@ NS_IMETHODIMP nsCollationMacUC::CompareRawSortKey(const uint8_t* key1, uint32_t
NS_ENSURE_ARG_POINTER(result);
*result = 0;
if (mUseICU) {
int32_t tmpResult = strcmp((const char*)key1, (const char*)key2);
int32_t res;
if (tmpResult < 0) {
int32_t tmpResult = strcmp((const char*)key1, (const char*)key2);
int32_t res;
if (tmpResult < 0) {
res = -1;
} else if (tmpResult > 0) {
} else if (tmpResult > 0) {
res = 1;
} else {
} else {
res = 0;
}
*result = res;
return NS_OK;
}
OSStatus err;
err = ::UCCompareCollationKeys((const UCCollationValue*) key1, (ItemCount) len1,
(const UCCollationValue*) key2, (ItemCount) len2,
nullptr, (SInt32*) result);
NS_ENSURE_TRUE((err == noErr), NS_ERROR_FAILURE);
*result = res;
return NS_OK;
}

View File

@ -11,14 +11,6 @@
#include "mozilla/Attributes.h"
#include "unicode/ucol.h"
#include <Carbon/Carbon.h>
// Maximum number of characters for a buffer to remember
// the generated collation key.
const uint32_t kCacheSize = 128;
// According to the documentation, the length of the key should typically be
// at least 5 * textLength, but 6* would be safer.
const uint32_t kCollationValueSizeFactor = 6;
class nsCollationMacUC final : public nsICollation {
@ -35,12 +27,9 @@ protected:
~nsCollationMacUC();
nsresult ConvertLocaleICU(nsILocale* aNSLocale, char** aICULocale);
nsresult ConvertLocale(nsILocale* aNSLocale, LocaleRef* aMacLocale);
nsresult ConvertStrength(const int32_t aStrength,
UCollationStrength* aStrengthOut,
UColAttributeValue* aCaseLevelOut);
nsresult StrengthToOptions(const int32_t aStrength,
UCCollateOptions* aOptions);
nsresult EnsureCollator(const int32_t newStrength);
nsresult CleanUpCollator(void);
@ -48,13 +37,8 @@ private:
bool mInit;
bool mHasCollator;
char* mLocaleICU;
LocaleRef mLocale;
int32_t mLastStrength;
UCollator* mCollatorICU;
CollatorRef mCollator;
void *mBuffer; // temporary buffer to generate collation keys
uint32_t mBufferLen; // byte length of buffer
bool mUseICU;
};
#endif /* nsCollationMacUC_h_ */

View File

@ -2,7 +2,8 @@ var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/Services.jsm");
function check_sort() {
function run_test()
{
var input = [
"Argentina",
"Oerlikon",
@ -80,29 +81,3 @@ function check_sort() {
"日本",
]);
}
function test_default() {
Services.prefs.clearUserPref("intl.collation.mac.use_icu");
check_sort();
}
function test_ICU() {
Services.prefs.setBoolPref("intl.collation.mac.use_icu", true);
check_sort();
}
function test_CoreServices() {
Services.prefs.setBoolPref("intl.collation.mac.use_icu", false);
check_sort();
}
function run_test()
{
test_default();
test_ICU();
if (Services.sysinfo.getProperty("arch") == "x86") {
test_CoreServices();
}
Services.prefs.clearUserPref("intl.collation.mac.use_icu");
}

View File

@ -4948,9 +4948,6 @@ pref("dom.presentation.discovery.timeout_ms", 10000);
pref("dom.presentation.discoverable", false);
#ifdef XP_MACOSX
// Use raw ICU instead of CoreServices API in Unicode collation
pref("intl.collation.mac.use_icu", true);
#if !defined(RELEASE_BUILD) || defined(DEBUG)
// In non-release builds we crash by default on insecure text input (when a
// password editor has focus but secure event input isn't enabled). The