From 41f1699bd8981533acd548da649561f017d00c6b Mon Sep 17 00:00:00 2001 From: Gordon Su Date: Wed, 16 Dec 2015 17:27:44 +0900 Subject: [PATCH] Bug 1214169 - Always use ICU in nsCollationMacUC. r=emk. --- intl/locale/mac/nsCollationMacUC.cpp | 265 +++++------------- intl/locale/mac/nsCollationMacUC.h | 20 +- .../tests/unit/test_collation_mac_icu.js | 29 +- modules/libpref/init/all.js | 3 - 4 files changed, 72 insertions(+), 245 deletions(-) diff --git a/intl/locale/mac/nsCollationMacUC.cpp b/intl/locale/mac/nsCollationMacUC.cpp index 94a1e07614b..7eae8e4e48e 100644 --- a/intl/locale/mac/nsCollationMacUC.cpp +++ b/intl/locale/mac/nsCollationMacUC.cpp @@ -13,41 +13,24 @@ NS_IMPL_ISUPPORTS(nsCollationMacUC, nsICollation) -nsCollationMacUC::nsCollationMacUC() +nsCollationMacUC::nsCollationMacUC() : mInit(false) , mHasCollator(false) , mLocaleICU(nullptr) - , mLocale(nullptr) , mLastStrength(-1) , mCollatorICU(nullptr) - , mCollator(nullptr) - , mBuffer(nullptr) - , mBufferLen(1) - , mUseICU(true) -{ - nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); - if (prefs) { - prefs->GetBoolPref("intl.collation.mac.use_icu", &mUseICU); - } -} +{ } -nsCollationMacUC::~nsCollationMacUC() +nsCollationMacUC::~nsCollationMacUC() { #ifdef DEBUG nsresult res = #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,25 +90,7 @@ 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) +nsresult nsCollationMacUC::EnsureCollator(const int32_t newStrength) { NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED); if (mHasCollator && (mLastStrength == newStrength)) @@ -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,102 +175,55 @@ 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; } NS_IMETHODIMP nsCollationMacUC::CompareString(int32_t strength, const nsAString& string1, - const nsAString& string2, int32_t* result) + const nsAString& string2, int32_t* result) { NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED); 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; } diff --git a/intl/locale/mac/nsCollationMacUC.h b/intl/locale/mac/nsCollationMacUC.h index 447c1430845..46bb0145de7 100644 --- a/intl/locale/mac/nsCollationMacUC.h +++ b/intl/locale/mac/nsCollationMacUC.h @@ -11,18 +11,10 @@ #include "mozilla/Attributes.h" #include "unicode/ucol.h" -#include - -// 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 { -public: +public: nsCollationMacUC(); // nsISupports interface @@ -32,15 +24,12 @@ public: NS_DECL_NSICOLLATION protected: - ~nsCollationMacUC(); + ~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_ */ diff --git a/intl/locale/tests/unit/test_collation_mac_icu.js b/intl/locale/tests/unit/test_collation_mac_icu.js index d04d301c5d1..32ebc60ebcc 100644 --- a/intl/locale/tests/unit/test_collation_mac_icu.js +++ b/intl/locale/tests/unit/test_collation_mac_icu.js @@ -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"); -} diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index dd9c09022d4..80196fda6ab 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -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