Bug 1426907 - Update OSPreferences API to use UTF-8 rather than UTF-16; r=zbraniecki

We'll want to use UTF-8 when we switch to using ICU4x because Rust is all UTF-8. We
can switch the external facing APIs now, and update the internal implementations
later.

Differential Revision: https://phabricator.services.mozilla.com/D94850
This commit is contained in:
Dan Minor 2020-10-27 20:45:19 +00:00
parent 3790450033
commit 686b723d0d
9 changed files with 89 additions and 78 deletions

View File

@ -73,7 +73,7 @@ nsresult DateTimeFormat::FormatDateTime(
UErrorCode status = U_ZERO_ERROR;
nsAutoString skeleton;
nsAutoCString skeleton;
switch (aSkeleton) {
case Skeleton::yyyyMM:
skeleton.AssignASCII("yyyyMM");
@ -85,10 +85,11 @@ nsresult DateTimeFormat::FormatDateTime(
MOZ_ASSERT_UNREACHABLE("Unhandled skeleton enum");
}
nsAutoString pattern;
if (!OSPreferences::GetPatternForSkeleton(skeleton, *mLocale, pattern)) {
nsAutoCString str;
if (!OSPreferences::GetPatternForSkeleton(skeleton, *mLocale, str)) {
return NS_ERROR_FAILURE;
}
nsAutoString pattern = NS_ConvertUTF8toUTF16(str);
nsAutoString timeZoneID;
BuildTimeZoneString(aExplodedTime->tm_params, timeZoneID);
@ -253,7 +254,6 @@ nsresult DateTimeFormat::FormatUDateTime(
if (!dateTimeFormat) {
// We didn't have a cached formatter for this key, so create one.
nsAutoString pattern;
int32_t dateFormatStyle;
switch (aDateFormatSelector) {
case kDateFormatLong:
@ -286,10 +286,12 @@ nsresult DateTimeFormat::FormatUDateTime(
return NS_ERROR_ILLEGAL_VALUE;
}
nsAutoCString str;
rv = OSPreferences::GetInstance()->GetDateTimePattern(
dateFormatStyle, timeFormatStyle, nsDependentCString(mLocale->get()),
pattern);
str);
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString pattern = NS_ConvertUTF8toUTF16(str);
if (aTimeParameters) {
nsAutoString timeZoneID;

View File

@ -63,7 +63,7 @@ bool OSPreferences::CanonicalizeLanguageTag(nsCString& aLoc) {
bool OSPreferences::GetDateTimePatternForStyle(DateTimeFormatStyle aDateStyle,
DateTimeFormatStyle aTimeStyle,
const nsACString& aLocale,
nsAString& aRetVal) {
nsACString& aRetVal) {
UDateFormatStyle timeStyle = UDAT_NONE;
UDateFormatStyle dateStyle = UDAT_NONE;
@ -133,7 +133,7 @@ bool OSPreferences::GetDateTimePatternForStyle(DateTimeFormatStyle aDateStyle,
if (U_FAILURE(status)) {
return false;
}
aRetVal.Assign((const char16_t*)pattern, patsize);
aRetVal = NS_ConvertUTF16toUTF8(pattern, patsize);
return true;
}
@ -148,24 +148,26 @@ bool OSPreferences::GetDateTimePatternForStyle(DateTimeFormatStyle aDateStyle,
bool OSPreferences::GetDateTimeSkeletonForStyle(DateTimeFormatStyle aDateStyle,
DateTimeFormatStyle aTimeStyle,
const nsACString& aLocale,
nsAString& aRetVal) {
nsAutoString pattern;
nsACString& aRetVal) {
nsAutoCString pattern;
if (!GetDateTimePatternForStyle(aDateStyle, aTimeStyle, aLocale, pattern)) {
return false;
}
nsAutoString patternAsUtf16 = NS_ConvertUTF8toUTF16(pattern);
const int32_t kSkeletonMax = 160;
UChar skeleton[kSkeletonMax];
UErrorCode status = U_ZERO_ERROR;
int32_t skelsize =
udatpg_getSkeleton(nullptr, (const UChar*)pattern.BeginReading(),
pattern.Length(), skeleton, kSkeletonMax, &status);
int32_t skelsize = udatpg_getSkeleton(
nullptr, (const UChar*)patternAsUtf16.BeginReading(),
patternAsUtf16.Length(), skeleton, kSkeletonMax, &status);
if (U_FAILURE(status)) {
return false;
}
aRetVal.Assign((const char16_t*)skeleton, skelsize);
aRetVal = NS_ConvertUTF16toUTF8(skeleton, skelsize);
return true;
}
@ -178,9 +180,11 @@ bool OSPreferences::GetDateTimeSkeletonForStyle(DateTimeFormatStyle aDateStyle,
* For example:
* "Hm" skeleton for "en-US" will return "H:m"
*/
bool OSPreferences::GetPatternForSkeleton(const nsAString& aSkeleton,
bool OSPreferences::GetPatternForSkeleton(const nsACString& aSkeleton,
const nsACString& aLocale,
nsAString& aRetVal) {
nsACString& aRetVal) {
aRetVal.Truncate();
UErrorCode status = U_ZERO_ERROR;
UDateTimePatternGenerator* pg =
udatpg_open(PromiseFlatCString(aLocale).get(), &status);
@ -188,19 +192,26 @@ bool OSPreferences::GetPatternForSkeleton(const nsAString& aSkeleton,
return false;
}
nsAutoString skeletonAsUtf16 = NS_ConvertUTF8toUTF16(aSkeleton);
nsAutoString result;
int32_t len =
udatpg_getBestPattern(pg, (const UChar*)aSkeleton.BeginReading(),
aSkeleton.Length(), nullptr, 0, &status);
udatpg_getBestPattern(pg, (const UChar*)skeletonAsUtf16.BeginReading(),
skeletonAsUtf16.Length(), nullptr, 0, &status);
if (status == U_BUFFER_OVERFLOW_ERROR) { // expected
aRetVal.SetLength(len);
result.SetLength(len);
status = U_ZERO_ERROR;
udatpg_getBestPattern(pg, (const UChar*)aSkeleton.BeginReading(),
aSkeleton.Length(), (UChar*)aRetVal.BeginWriting(),
len, &status);
udatpg_getBestPattern(pg, (const UChar*)skeletonAsUtf16.BeginReading(),
skeletonAsUtf16.Length(),
(UChar*)result.BeginWriting(), len, &status);
}
udatpg_close(pg);
if (U_SUCCESS(status)) {
aRetVal = NS_ConvertUTF16toUTF8(result);
}
return U_SUCCESS(status);
}
@ -214,7 +225,7 @@ bool OSPreferences::GetPatternForSkeleton(const nsAString& aSkeleton,
* An example output is "{1}, {0}".
*/
bool OSPreferences::GetDateTimeConnectorPattern(const nsACString& aLocale,
nsAString& aRetVal) {
nsACString& aRetVal) {
bool result = false;
UErrorCode status = U_ZERO_ERROR;
UDateTimePatternGenerator* pg =
@ -224,7 +235,7 @@ bool OSPreferences::GetDateTimeConnectorPattern(const nsACString& aLocale,
const UChar* value = udatpg_getDateTimeFormat(pg, &resultSize);
MOZ_ASSERT(resultSize >= 0);
aRetVal.Assign((char16_t*)value, resultSize);
aRetVal = NS_ConvertUTF16toUTF8(value, resultSize);
result = true;
}
udatpg_close(pg);
@ -306,7 +317,7 @@ NS_IMETHODIMP
OSPreferences::GetDateTimePattern(int32_t aDateFormatStyle,
int32_t aTimeFormatStyle,
const nsACString& aLocale,
nsAString& aRetVal) {
nsACString& aRetVal) {
DateTimeFormatStyle dateStyle = ToDateTimeFormatStyle(aDateFormatStyle);
if (dateStyle == DateTimeFormatStyle::Invalid) {
return NS_ERROR_INVALID_ARG;
@ -330,7 +341,7 @@ OSPreferences::GetDateTimePattern(int32_t aDateFormatStyle,
key.Append(':');
key.AppendInt(aTimeFormatStyle);
nsString pattern;
nsCString pattern;
if (mPatternCache.Get(key, &pattern)) {
aRetVal = pattern;
return NS_OK;

View File

@ -77,12 +77,12 @@ class OSPreferences : public mozIOSPreferences {
return RefPtr<OSPreferences>(GetInstance()).forget();
}
static bool GetPatternForSkeleton(const nsAString& aSkeleton,
static bool GetPatternForSkeleton(const nsACString& aSkeleton,
const nsACString& aLocale,
nsAString& aRetVal);
nsACString& aRetVal);
static bool GetDateTimeConnectorPattern(const nsACString& aLocale,
nsAString& aRetVal);
nsACString& aRetVal);
/**
* Triggers a refresh of retrieving data from host environment.
@ -102,7 +102,7 @@ class OSPreferences : public mozIOSPreferences {
nsTArray<nsCString> mRegionalPrefsLocales;
const size_t kMaxCachedPatterns = 15;
nsDataHashtable<nsCStringHashKey, nsString> mPatternCache;
nsDataHashtable<nsCStringHashKey, nsCString> mPatternCache;
private:
virtual ~OSPreferences();
@ -118,12 +118,12 @@ class OSPreferences : public mozIOSPreferences {
bool GetDateTimePatternForStyle(DateTimeFormatStyle aDateStyle,
DateTimeFormatStyle aTimeStyle,
const nsACString& aLocale,
nsAString& aRetVal);
nsACString& aRetVal);
bool GetDateTimeSkeletonForStyle(DateTimeFormatStyle aDateStyle,
DateTimeFormatStyle aTimeStyle,
const nsACString& aLocale,
nsAString& aRetVal);
nsACString& aRetVal);
/**
* This is a host environment specific method that will be implemented
@ -153,7 +153,7 @@ class OSPreferences : public mozIOSPreferences {
*/
bool ReadDateTimePattern(DateTimeFormatStyle aDateFormatStyle,
DateTimeFormatStyle aTimeFormatStyle,
const nsACString& aLocale, nsAString& aRetVal);
const nsACString& aLocale, nsACString& aRetVal);
};
} // namespace intl

View File

@ -43,6 +43,6 @@ bool OSPreferences::ReadRegionalPrefsLocales(nsTArray<nsCString>& aLocaleList) {
bool OSPreferences::ReadDateTimePattern(DateTimeFormatStyle aDateStyle,
DateTimeFormatStyle aTimeStyle,
const nsACString& aLocale,
nsAString& aRetVal) {
nsACString& aRetVal) {
return false;
}

View File

@ -136,8 +136,8 @@ static int HourCycle() {
bool OSPreferences::ReadDateTimePattern(DateTimeFormatStyle aDateStyle,
DateTimeFormatStyle aTimeStyle,
const nsACString& aLocale,
nsAString& aRetVal) {
nsAutoString skeleton;
nsACString& aRetVal) {
nsAutoCString skeleton;
if (!GetDateTimeSkeletonForStyle(aDateStyle, aTimeStyle, aLocale, skeleton)) {
return false;
}

View File

@ -131,7 +131,7 @@ static CFLocaleRef CreateCFLocaleFor(const nsACString& aLocale) {
bool OSPreferences::ReadDateTimePattern(DateTimeFormatStyle aDateStyle,
DateTimeFormatStyle aTimeStyle,
const nsACString& aLocale,
nsAString& aRetVal) {
nsACString& aRetVal) {
CFLocaleRef locale = CreateCFLocaleFor(aLocale);
if (!locale) {
return false;
@ -147,10 +147,12 @@ bool OSPreferences::ReadDateTimePattern(DateTimeFormatStyle aDateStyle,
CFRelease(locale);
CFRange range = CFRangeMake(0, CFStringGetLength(format));
aRetVal.SetLength(range.length);
nsAutoString str;
str.SetLength(range.length);
CFStringGetCharacters(format, range,
reinterpret_cast<UniChar*>(aRetVal.BeginWriting()));
reinterpret_cast<UniChar*>(str.BeginWriting()));
CFRelease(formatter);
aRetVal = NS_ConvertUTF16toUTF8(str);
return true;
}

View File

@ -89,7 +89,7 @@ interface mozIOSPreferences : nsISupports
* handle all scenarios, including with cases where we fail to retrieve
* anything from the OS, here.
*/
AString getDateTimePattern(in long timeFormatStyle,
in long dateFormatStyle,
[optional] in ACString locale);
ACString getDateTimePattern(in long timeFormatStyle,
in long dateFormatStyle,
[optional] in ACString locale);
};

View File

@ -53,7 +53,7 @@ TEST(Intl_Locale_OSPreferences, GetRegionalPrefsLocales)
*/
TEST(Intl_Locale_OSPreferences, GetDateTimePattern)
{
nsAutoString pattern;
nsAutoCString pattern;
OSPreferences* osprefs = OSPreferences::GetInstance();
struct Test {
@ -70,7 +70,6 @@ TEST(Intl_Locale_OSPreferences, GetDateTimePattern)
for (unsigned i = 0; i < mozilla::ArrayLength(tests); i++) {
const Test& t = tests[i];
nsAutoString pattern;
if (NS_SUCCEEDED(osprefs->GetDateTimePattern(
t.dateStyle, t.timeStyle, nsDependentCString(t.locale), pattern))) {
ASSERT_TRUE((t.dateStyle == 0 && t.timeStyle == 0) || !pattern.IsEmpty());

View File

@ -204,7 +204,7 @@ static LCTYPE ToTimeLCType(OSPreferences::DateTimeFormatStyle aFormatStyle) {
bool OSPreferences::ReadDateTimePattern(DateTimeFormatStyle aDateStyle,
DateTimeFormatStyle aTimeStyle,
const nsACString& aLocale,
nsAString& aRetVal) {
nsACString& aRetVal) {
nsAutoString localeName;
CopyASCIItoUTF16(aLocale, localeName);
@ -215,20 +215,13 @@ bool OSPreferences::ReadDateTimePattern(DateTimeFormatStyle aDateStyle,
// If both date and time are wanted, we'll initially read them into a
// local string, and then insert them into the overall date+time pattern;
// but if only one is needed we'll work directly with the return value.
// Set 'str' to point to the string we will use to retrieve patterns
// from Windows.
nsAutoString tmpStr;
nsAString* str;
nsAutoString str;
if (isDate && isTime) {
if (!GetDateTimeConnectorPattern(aLocale, aRetVal)) {
NS_WARNING("failed to get date/time connector");
aRetVal.AssignLiteral(u"{1} {0}");
aRetVal.AssignLiteral("{1} {0}");
}
str = &tmpStr;
} else if (isDate || isTime) {
str = &aRetVal;
} else {
} else if (!isDate && !isTime) {
aRetVal.Truncate(0);
return true;
}
@ -244,10 +237,10 @@ bool OSPreferences::ReadDateTimePattern(DateTimeFormatStyle aDateStyle,
// We're doing it to ensure the terminator will fit when Windows writes the
// data to its output buffer. See bug 1358159 for details.
str->SetLength(len);
str.SetLength(len);
GetLocaleInfoEx(reinterpret_cast<const wchar_t*>(localeName.BeginReading()),
lcType, (WCHAR*)str->BeginWriting(), len);
str->SetLength(len - 1); // -1 because len counts the null terminator
lcType, (WCHAR*)str.BeginWriting(), len);
str.SetLength(len - 1); // -1 because len counts the null terminator
// Windows uses "ddd" and "dddd" for abbreviated and full day names
// respectively,
@ -256,38 +249,40 @@ bool OSPreferences::ReadDateTimePattern(DateTimeFormatStyle aDateStyle,
// http://userguide.icu-project.org/formatparse/datetime
// So we fix that up here.
nsAString::const_iterator start, pos, end;
start = str->BeginReading(pos);
str->EndReading(end);
start = str.BeginReading(pos);
str.EndReading(end);
if (FindInReadable(u"dddd"_ns, pos, end)) {
str->ReplaceLiteral(pos - start, 4, u"EEEE");
str.ReplaceLiteral(pos - start, 4, u"EEEE");
} else {
pos = start;
if (FindInReadable(u"ddd"_ns, pos, end)) {
str->ReplaceLiteral(pos - start, 3, u"EEE");
str.ReplaceLiteral(pos - start, 3, u"EEE");
}
}
// Also, Windows uses lowercase "g" or "gg" for era, but ICU wants uppercase
// "G" (it would interpret "g" as "modified Julian day"!). So fix that.
int32_t index = str->FindChar('g');
int32_t index = str.FindChar('g');
if (index >= 0) {
str->Replace(index, 1, 'G');
str.Replace(index, 1, 'G');
// If it was a double "gg", just drop the second one.
index++;
if (str->CharAt(index) == 'g') {
str->Cut(index, 1);
if (str.CharAt(index) == 'g') {
str.Cut(index, 1);
}
}
// If time was also requested, we need to substitute the date pattern from
// Windows into the date+time format that we have in aRetVal.
if (isTime) {
nsAString::const_iterator start, pos, end;
nsACString::const_iterator start, pos, end;
start = aRetVal.BeginReading(pos);
aRetVal.EndReading(end);
if (FindInReadable(u"{1}"_ns, pos, end)) {
aRetVal.Replace(pos - start, 3, tmpStr);
if (FindInReadable("{1}"_ns, pos, end)) {
aRetVal.Replace(pos - start, 3, NS_ConvertUTF16toUTF8(str));
}
} else {
aRetVal = NS_ConvertUTF16toUTF8(str);
}
}
@ -302,32 +297,34 @@ bool OSPreferences::ReadDateTimePattern(DateTimeFormatStyle aDateStyle,
// We're doing it to ensure the terminator will fit when Windows writes the
// data to its output buffer. See bug 1358159 for details.
str->SetLength(len);
str.SetLength(len);
GetLocaleInfoEx(reinterpret_cast<const wchar_t*>(localeName.BeginReading()),
lcType, (WCHAR*)str->BeginWriting(), len);
str->SetLength(len - 1);
lcType, (WCHAR*)str.BeginWriting(), len);
str.SetLength(len - 1);
// Windows uses "t" or "tt" for a "time marker" (am/pm indicator),
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd318148(v=vs.85).aspx
// but in a CLDR/ICU-style pattern that should be "a".
// http://userguide.icu-project.org/formatparse/datetime
// So we fix that up here.
int32_t index = str->FindChar('t');
int32_t index = str.FindChar('t');
if (index >= 0) {
str->Replace(index, 1, 'a');
str.Replace(index, 1, 'a');
index++;
if (str->CharAt(index) == 't') {
str->Cut(index, 1);
if (str.CharAt(index) == 't') {
str.Cut(index, 1);
}
}
if (isDate) {
nsAString::const_iterator start, pos, end;
nsACString::const_iterator start, pos, end;
start = aRetVal.BeginReading(pos);
aRetVal.EndReading(end);
if (FindInReadable(u"{0}"_ns, pos, end)) {
aRetVal.Replace(pos - start, 3, tmpStr);
if (FindInReadable("{0}"_ns, pos, end)) {
aRetVal.Replace(pos - start, 3, NS_ConvertUTF16toUTF8(str));
}
} else {
aRetVal = NS_ConvertUTF16toUTF8(str);
}
}