From 7d2bd41148a80dcf801cc617cea661f49880a9d7 Mon Sep 17 00:00:00 2001 From: Jack Horton Date: Sat, 8 Sep 2018 01:31:28 -0700 Subject: [PATCH] Implement Intl.Locale.prototype.{minimize|maximize} --- lib/Runtime/Base/JnDirectFields.h | 1 + .../Library/EngineInterfaceObjectBuiltIns.h | 1 + lib/Runtime/Library/InJavascript/Intl.js | 21 +++--- .../IntlEngineInterfaceExtensionObject.cpp | 70 +++++++++++++++++++ .../Library/IntlExtensionObjectBuiltIns.h | 2 + test/Intl/Locale.js | 16 ++++- 6 files changed, 97 insertions(+), 14 deletions(-) diff --git a/lib/Runtime/Base/JnDirectFields.h b/lib/Runtime/Base/JnDirectFields.h index b716598e120..b1f679c4203 100644 --- a/lib/Runtime/Base/JnDirectFields.h +++ b/lib/Runtime/Base/JnDirectFields.h @@ -658,6 +658,7 @@ ENTRY(builtInJavascriptArrayEntryMap) ENTRY(builtInJavascriptArrayEntryPush) ENTRY(builtInJavascriptArrayEntryReduce) ENTRY(builtInJavascriptArrayEntrySlice) +ENTRY(builtInJavascriptArrayEntrySort) ENTRY(builtInJavascriptDateEntryGetDate) ENTRY(builtInJavascriptDateEntryNow) ENTRY(builtInJavascriptFunctionEntryApply) diff --git a/lib/Runtime/Library/EngineInterfaceObjectBuiltIns.h b/lib/Runtime/Library/EngineInterfaceObjectBuiltIns.h index 71793a98ea7..e029d093b61 100644 --- a/lib/Runtime/Library/EngineInterfaceObjectBuiltIns.h +++ b/lib/Runtime/Library/EngineInterfaceObjectBuiltIns.h @@ -30,6 +30,7 @@ GlobalBuiltIn(JavascriptArray, EntryMap) GlobalBuiltIn(JavascriptArray, EntryReduce) GlobalBuiltIn(JavascriptArray, EntrySlice) GlobalBuiltIn(JavascriptArray, EntryConcat) +GlobalBuiltIn(JavascriptArray, EntrySort) GlobalBuiltIn(JavascriptFunction, EntryBind) GlobalBuiltIn(JavascriptFunction, EntryApply) diff --git a/lib/Runtime/Library/InJavascript/Intl.js b/lib/Runtime/Library/InJavascript/Intl.js index 6cc33f6f16e..8e003142eb7 100644 --- a/lib/Runtime/Library/InJavascript/Intl.js +++ b/lib/Runtime/Library/InJavascript/Intl.js @@ -131,18 +131,7 @@ return false; }, - sort(array, sortCallback) { - for (let i = 0; i < array.length; i++) { - for (let j = i; j < array.length; j++) { - const cond = sortCallback ? sortCallback(array[i], array[j]) : array[i] < array[j]; - if (cond > 0) { - const temp = array[i]; - array[i] = array[j]; - array[j] = temp; - } - } - } - }, + sort(array, sortCallback) { return callInstanceFunc(platform.builtInJavascriptArrayEntrySort, array, sortCallback); }, keys: platform.builtInJavascriptObjectEntryKeys, hasOwnProperty(o, prop) { return callInstanceFunc(platform.builtInJavascriptObjectEntryHasOwnProperty, o, prop); }, @@ -2251,7 +2240,7 @@ const minMaxImpl = function (loc, methodName) { const locInternals = getLocaleInternalsObject(loc, methodName); - const minimaximal = platform[`${methodName}Locale`](locInternals); + const minimaximal = platform[`${methodName}Locale`](locInternals.locale); return new Locale(minimaximal); }; @@ -2331,8 +2320,10 @@ } } else { const parts = langtagToParts(tag); + const savedLanguage = parts.language; parts.language = language; tag = partsToLangtag(parts); + parts.language = savedLanguage; } } @@ -2355,6 +2346,8 @@ } } else { const langtagParts = langtagToParts(tag); + const savedScript = langtagParts.script; + const savedRegion = langtagParts.region; if (script !== undefined) { langtagParts.script = script; } @@ -2364,6 +2357,8 @@ } tag = partsToLangtag(langtagParts); + langtagParts.script = savedScript; + langtagParts.region = savedRegion; } // 13. Return CanonicalizeLanguageTag(tag). diff --git a/lib/Runtime/Library/IntlEngineInterfaceExtensionObject.cpp b/lib/Runtime/Library/IntlEngineInterfaceExtensionObject.cpp index 9801de6cbeb..bce808845b2 100644 --- a/lib/Runtime/Library/IntlEngineInterfaceExtensionObject.cpp +++ b/lib/Runtime/Library/IntlEngineInterfaceExtensionObject.cpp @@ -3156,6 +3156,76 @@ DEFINE_ISXLOCALEAVAILABLE(PR, uloc) #endif } +#ifdef INTL_ICU + template + static JavascriptString *MinMaxImpl(JavascriptString *langtag, ScriptContext *scriptContext) + { + UErrorCode status = U_ZERO_ERROR; + char localeID[ULOC_FULLNAME_CAPACITY] = { 0 }; + LangtagToLocaleID(langtag, localeID); + + char minmaxLocaleID[ULOC_FULLNAME_CAPACITY] = { 0 }; + int32_t minmaxLocaleIDLength = 0; + if (minimize) + { + minmaxLocaleIDLength = uloc_minimizeSubtags(localeID, minmaxLocaleID, ULOC_FULLNAME_CAPACITY, &status); + INTL_TRACE("Minimizing localeID %S to %S", localeID, minmaxLocaleID); + } + else + { + minmaxLocaleIDLength = uloc_addLikelySubtags(localeID, minmaxLocaleID, ULOC_FULLNAME_CAPACITY, &status); + INTL_TRACE("Maximizing localeID %S to %S", localeID, minmaxLocaleID); + } + ICU_ASSERT(status, minmaxLocaleIDLength < ULOC_FULLNAME_CAPACITY); + + char minmaxLangtag[ULOC_FULLNAME_CAPACITY] = { 0 }; + int minmaxLangtagLength = uloc_toLanguageTag(minmaxLocaleID, minmaxLangtag, ULOC_FULLNAME_CAPACITY, true, &status); + ICU_ASSERT(status, minmaxLangtagLength > 0); + + // allocate maximizedLangtagLength + 1 to leave room for null terminator + char16 *minmaxLangtag16 = RecyclerNewArrayLeaf(scriptContext->GetRecycler(), char16, minmaxLangtagLength + 1); + charcount_t minmaxLangtag16Length = 0; + HRESULT hr = utf8::NarrowStringToWideNoAlloc( + minmaxLangtag, + minmaxLangtagLength, + minmaxLangtag16, + minmaxLangtagLength + 1, + &minmaxLangtag16Length + ); + AssertOrFailFast(hr == S_OK && ((int)minmaxLangtag16Length) == minmaxLangtagLength); + + return JavascriptString::NewWithBuffer(minmaxLangtag16, minmaxLangtagLength, scriptContext); + } +#endif + + Var IntlEngineInterfaceExtensionObject::EntryIntl_MinimizeLocale(RecyclableObject *function, CallInfo callInfo, ...) + { +#ifdef INTL_ICU + EngineInterfaceObject_CommonFunctionProlog(function, callInfo); + + INTL_CHECK_ARGS(args.Info.Count == 2 && JavascriptString::Is(args.Values[1])); + + return MinMaxImpl(JavascriptString::UnsafeFromVar(args.Values[1]), scriptContext); +#else + AssertOrFailFastMsg(false, "Intl-WinGlob should not be using MinimizeLocale"); + return nullptr; +#endif + } + + Var IntlEngineInterfaceExtensionObject::EntryIntl_MaximizeLocale(RecyclableObject *function, CallInfo callInfo, ...) + { +#ifdef INTL_ICU + EngineInterfaceObject_CommonFunctionProlog(function, callInfo); + + INTL_CHECK_ARGS(args.Info.Count == 2 && JavascriptString::Is(args.Values[1])); + + return MinMaxImpl(JavascriptString::UnsafeFromVar(args.Values[1]), scriptContext); +#else + AssertOrFailFastMsg(false, "Intl-WinGlob should not be using MaximizeLocale"); + return nullptr; +#endif + } + /* * This function registers built in functions when Intl initializes. * Call with (Function : toRegister, integer : id) diff --git a/lib/Runtime/Library/IntlExtensionObjectBuiltIns.h b/lib/Runtime/Library/IntlExtensionObjectBuiltIns.h index 90415b710f2..0908244d1e9 100644 --- a/lib/Runtime/Library/IntlExtensionObjectBuiltIns.h +++ b/lib/Runtime/Library/IntlExtensionObjectBuiltIns.h @@ -37,6 +37,8 @@ INTL_ENTRY(getLocaleData, GetLocaleData) INTL_ENTRY(localeCompare, LocaleCompare) INTL_ENTRY(pluralRulesSelect, PluralRulesSelect) INTL_ENTRY(pluralRulesKeywords, PluralRulesKeywords) +INTL_ENTRY(minimizeLocale, MinimizeLocale) +INTL_ENTRY(maximizeLocale, MaximizeLocale) INTL_ENTRY(registerBuiltInFunction, RegisterBuiltInFunction) INTL_ENTRY(getHiddenObject, GetHiddenObject) diff --git a/test/Intl/Locale.js b/test/Intl/Locale.js index 6d8e0cd6ed0..3bc93875705 100644 --- a/test/Intl/Locale.js +++ b/test/Intl/Locale.js @@ -58,10 +58,24 @@ testRunner.runTests([ assert.areEqual("de", deUnihan.language); assert.areEqual("unihan", deUnihan.collation); - esUnihanH24 = new Intl.Locale(deUnihan, { language: "es", hourCycle: "h24" }); + const esUnihanH24 = new Intl.Locale(deUnihan, { language: "es", hourCycle: "h24" }); assert.areEqual("es", esUnihanH24.language); assert.areEqual("unihan", esUnihanH24.collation); assert.areEqual("h24", esUnihanH24.hourCycle); } }, + { + name: "Maximizing and minimizing", + body() { + function test(input, expected, minimal, maximal) { + const locale = new Intl.Locale(input); + assert.areEqual(expected, locale.toString(), `Incorrect canonicalization of ${input}`); + assert.areEqual(minimal, locale.minimize().toString(), `Incorrect minimization of ${input}`); + assert.areEqual(maximal, locale.maximize().toString(), `Incorrect maximization of ${input}`); + } + + test("en", "en", "en", "en-Latn-US"); + test("DE-de", "de-DE", "de", "de-Latn-DE"); + } + }, ], { verbose: false })