@@ -48,48 +48,76 @@ using namespace PlatformAgnostic::ICUHelpers;
48
48
49
49
#endif // INTL_ICU
50
50
51
- // NOTE(jahorto): Keep these enums in sync with those by the same name in Intl.js
52
- // These enums are used by both WinGlob- and ICU-backed Intl
53
- enum class NumberFormatStyle
54
- {
55
- Decimal, // Intl.NumberFormat(locale, { style: "decimal" }); // aka in our code as "number"
56
- Percent, // Intl.NumberFormat(locale, { style: "percent" });
57
- Currency, // Intl.NumberFormat(locale, { style: "currency", ... });
58
-
59
- Max,
60
- Default = Decimal,
61
- };
62
-
63
- enum class NumberFormatCurrencyDisplay
64
- {
65
- Symbol, // Intl.NumberFormat(locale, { style: "currency", currencyDisplay: "symbol" }); // e.g. "$" or "US$" depeding on locale
66
- Code, // Intl.NumberFormat(locale, { style: "currency", currencyDisplay: "code" }); // e.g. "USD"
67
- Name, // Intl.NumberFormat(locale, { style: "currency", currencyDisplay: "name" }); // e.g. "US dollar"
68
-
69
- Max,
70
- Default = Symbol,
51
+ // The following macros allow the key-value pairs to be C++ enums as well as JS objects
52
+ // in Intl.js. When adding a new macro, follow the same format as the _VALUES macros below,
53
+ // and add your new _VALUES macro to PROJECTED_ENUMS along with the name of the enum.
54
+ // NOTE: make sure the last VALUE macro has the highest integer value, since the C++ enum's ::Max
55
+ // value is added to the end of the C++ enum definition as an increment of the previous value.
56
+ // The ::Max value is used in a defensive assert, and we want to make sure its always 1 greater
57
+ // than the highest valid value.
58
+
59
+ #define NUMBERFORMATSTYLE_VALUES (VALUE ) \
60
+ VALUE (Default, default_, 0 ) \
61
+ VALUE(Decimal, decimal, 0 ) \
62
+ VALUE(Percent, percent, 1 ) \
63
+ VALUE(Currency, currency, 2 )
64
+
65
+ #define NUMBERFORMATCURRENCYDISPLAY_VALUES (VALUE ) \
66
+ VALUE (Default, default_, 0 ) \
67
+ VALUE(Symbol, symbol, 0 ) \
68
+ VALUE(Code, code, 1 ) \
69
+ VALUE(Name, name, 2 )
70
+
71
+ #define COLLATORSENSITIVITY_VALUES (VALUE ) \
72
+ VALUE (Default, default_, 3 ) \
73
+ VALUE(Base, base, 0 ) \
74
+ VALUE(Accent, accent, 1 ) \
75
+ VALUE(Case, case_, 2 ) \
76
+ VALUE(Variant, variant, 3 )
77
+
78
+ #define COLLATORCASEFIRST_VALUES (VALUE ) \
79
+ VALUE (Default, default_, 2 ) \
80
+ VALUE(Upper, upper, 0 ) \
81
+ VALUE(Lower, lower, 1 ) \
82
+ VALUE(False, false_, 2 )
83
+
84
+ // LocaleDataKind intentionally has no Default value
85
+ #define LOCALEDATAKIND_VALUES (VALUE ) \
86
+ VALUE (Collation, co, 0 ) \
87
+ VALUE(CaseFirst, kf, 1 ) \
88
+ VALUE(Numeric, kn, 2 ) \
89
+ VALUE(Calendar, ca, 3 ) \
90
+ VALUE(NumberingSystem, nu, 4 ) \
91
+ VALUE(HourCycle, hc, 5 )
92
+
93
+ // BuiltInFunctionID intentionally has no Default value
94
+ #define BUILTINFUNCTIONID_VALUES (VALUE ) \
95
+ VALUE (DateToLocaleString, DateToLocaleString, 0 ) \
96
+ VALUE(DateToLocaleDateString, DateToLocaleDateString, 1 ) \
97
+ VALUE(DateToLocaleTimeString, DateToLocaleTimeString, 2 ) \
98
+ VALUE(NumberToLocaleString, NumberToLocaleString, 3 ) \
99
+ VALUE(StringLocaleCompare, StringLocaleCompare, 4 )
100
+
101
+ #define ENUM_VALUE (enumName, propId, value ) enumName = value,
102
+ #define PROJECTED_ENUM (ClassName, VALUES ) \
103
+ enum class ClassName \
104
+ { \
105
+ VALUES (ENUM_VALUE) \
106
+ Max \
71
107
};
72
108
73
- enum class CollatorSensitivity
74
- {
75
- Base,
76
- Accent,
77
- Case,
78
- Variant,
109
+ #define PROJECTED_ENUMS (PROJECT ) \
110
+ PROJECT (LocaleDataKind, LOCALEDATAKIND_VALUES) \
111
+ PROJECT(CollatorCaseFirst, COLLATORCASEFIRST_VALUES) \
112
+ PROJECT(CollatorSensitivity, COLLATORSENSITIVITY_VALUES) \
113
+ PROJECT(NumberFormatCurrencyDisplay, NUMBERFORMATCURRENCYDISPLAY_VALUES) \
114
+ PROJECT(NumberFormatStyle, NUMBERFORMATSTYLE_VALUES) \
115
+ PROJECT(BuiltInFunctionID, BUILTINFUNCTIONID_VALUES)
79
116
80
- Max,
81
- Default = Variant,
82
- };
117
+ PROJECTED_ENUMS(PROJECTED_ENUM)
83
118
84
- enum class CollatorCaseFirst
85
- {
86
- Upper,
87
- Lower,
88
- False,
89
-
90
- Max,
91
- Default = False,
92
- };
119
+ #undef PROJECTED_ENUM
120
+ #undef ENUM_VALUE
93
121
94
122
#pragma warning(push)
95
123
#pragma warning(disable:4309) // truncation of constant value
@@ -431,7 +459,7 @@ namespace Js
431
459
template <size_t N>
432
460
static void LangtagToLocaleID (_In_ JavascriptString *langtag, _Out_ char (&localeID)[N])
433
461
{
434
- LangtagToLocaleID (langtag->GetSz (), langtag->GetLength (), localeID);
462
+ LangtagToLocaleID (langtag->GetString (), langtag->GetLength (), localeID);
435
463
}
436
464
437
465
template <typename Callback>
@@ -533,22 +561,46 @@ namespace Js
533
561
534
562
bool IntlEngineInterfaceExtensionObject::InitializeIntlNativeInterfaces (DynamicObject* intlNativeInterfaces, DeferredTypeHandlerBase * typeHandler, DeferredInitializeMode mode)
535
563
{
536
- typeHandler->Convert (intlNativeInterfaces, mode, 16 );
564
+ int initSlotCapacity = 0 ;
565
+
566
+ // automatically get the initSlotCapacity from everything we are about to add to intlNativeInterfaces
567
+ #define INTL_ENTRY (id, func ) initSlotCapacity++;
568
+ #include " IntlExtensionObjectBuiltIns.h"
569
+ #undef INTL_ENTRY
570
+
571
+ #define PROJECTED_ENUM (ClassName, VALUES ) initSlotCapacity++;
572
+ PROJECTED_ENUMS (PROJECTED_ENUM)
573
+ #undef PROJECTED_ENUM
574
+
575
+ // add capacity for platform.winglob and platform.FallbackSymbol
576
+ initSlotCapacity += 2 ;
577
+
578
+ typeHandler->Convert (intlNativeInterfaces, mode, initSlotCapacity);
537
579
538
580
ScriptContext* scriptContext = intlNativeInterfaces->GetScriptContext ();
539
581
JavascriptLibrary* library = scriptContext->GetLibrary ();
540
582
541
583
// gives each entrypoint a property ID on the intlNativeInterfaces library object
542
- #ifdef INTL_ENTRY
543
- #undef INTL_ENTRY
544
- #endif
545
- #define INTL_ENTRY (id, func ) \
546
- library->AddFunctionToLibraryObject (intlNativeInterfaces, Js::PropertyIds::##id, &IntlEngineInterfaceExtensionObject::EntryInfo::Intl_##func, 1 );
584
+ #define INTL_ENTRY (id, func ) library->AddFunctionToLibraryObject (intlNativeInterfaces, Js::PropertyIds::##id, &IntlEngineInterfaceExtensionObject::EntryInfo::Intl_##func, 1 );
547
585
#include " IntlExtensionObjectBuiltIns.h"
548
586
#undef INTL_ENTRY
549
587
550
588
library->AddMember (intlNativeInterfaces, PropertyIds::FallbackSymbol, library->CreateSymbol (BuiltInPropertyRecords::_intlFallbackSymbol));
551
589
590
+ DynamicObject * enumObj = nullptr ;
591
+
592
+ // Projects the exact layout of our C++ enums into Intl.js so that we dont have to remember to keep them in sync
593
+ #define ENUM_VALUE (enumName, propId, value ) library->AddMember (enumObj, PropertyIds::##propId, JavascriptNumber::ToVar(value, scriptContext));
594
+ #define PROJECTED_ENUM (ClassName, VALUES ) \
595
+ enumObj = library->CreateObject (); \
596
+ VALUES (ENUM_VALUE) \
597
+ library->AddMember (intlNativeInterfaces, PropertyIds::##ClassName, enumObj); \
598
+
599
+ PROJECTED_ENUMS (PROJECTED_ENUM)
600
+
601
+ #undef PROJECTED_ENUM
602
+ #undef ENUM_VALUE
603
+
552
604
#if INTL_WINGLOB
553
605
library->AddMember (intlNativeInterfaces, Js::PropertyIds::winglob, library->GetTrue ());
554
606
#else
@@ -1049,15 +1101,8 @@ DEFINE_ISXLOCALEAVAILABLE(DTF, udat)
1049
1101
DEFINE_ISXLOCALEAVAILABLE(PR, uloc)
1050
1102
1051
1103
#ifdef INTL_ICU
1052
- enum class LocaleDataKind
1053
- {
1054
- Collation,
1055
- CaseFirst,
1056
- Numeric,
1057
- Calendar,
1058
- NumberingSystem,
1059
- HourCycle
1060
- };
1104
+
1105
+
1061
1106
#endif
1062
1107
1063
1108
Var IntlEngineInterfaceExtensionObject::EntryIntl_GetLocaleData (RecyclableObject* function, CallInfo callInfo, ...)
@@ -1087,11 +1132,13 @@ DEFINE_ISXLOCALEAVAILABLE(PR, uloc)
1087
1132
if (kind == LocaleDataKind::Collation)
1088
1133
{
1089
1134
ScopedUEnumeration collations (ucol_getKeywordValuesForLocale (" collation" , localeID, false , &status));
1090
- ICU_ASSERT (status, true );
1135
+ int collationsCount = uenum_count (collations, &status);
1136
+
1137
+ // we expect collationsCount to have at least "standard" and "search" in it
1138
+ ICU_ASSERT (status, collationsCount > 2 );
1091
1139
1092
1140
// the return array can't include "standard" and "search", but must have its first element be null (count - 2 + 1) [#sec-intl-collator-internal-slots]
1093
- ret = library->CreateArray (uenum_count (collations, &status) - 1 );
1094
- ICU_ASSERT (status, true );
1141
+ ret = library->CreateArray (collationsCount - 1 );
1095
1142
ret->SetItem (0 , library->GetNull (), flag);
1096
1143
1097
1144
int collationLen = 0 ;
@@ -1111,7 +1158,7 @@ DEFINE_ISXLOCALEAVAILABLE(PR, uloc)
1111
1158
const size_t unicodeCollationLen = strlen (unicodeCollation);
1112
1159
1113
1160
// we only need strlen(unicodeCollation) + 1 char16s because unicodeCollation will always be ASCII (funnily enough)
1114
- char16 *unicodeCollation16 = RecyclerNewArrayLeaf (scriptContext->GetRecycler (), char16, strlen (unicodeCollation) + 1 );
1161
+ char16 *unicodeCollation16 = RecyclerNewArrayLeaf (scriptContext->GetRecycler (), char16, unicodeCollationLen + 1 );
1115
1162
charcount_t unicodeCollation16Len = 0 ;
1116
1163
HRESULT hr = utf8::NarrowStringToWideNoAlloc (
1117
1164
unicodeCollation,
@@ -1836,10 +1883,18 @@ DEFINE_ISXLOCALEAVAILABLE(PR, uloc)
1836
1883
bool ignorePunctuation = AssertBooleanProperty (state, PropertyIds::ignorePunctuation);
1837
1884
bool numeric = AssertBooleanProperty (state, PropertyIds::numeric);
1838
1885
CollatorCaseFirst caseFirst = AssertEnumProperty<CollatorCaseFirst>(state, PropertyIds::caseFirstEnum);
1886
+ JavascriptString *usage = AssertStringProperty (state, PropertyIds::usage);
1839
1887
1840
1888
char localeID[ULOC_FULLNAME_CAPACITY] = { 0 };
1841
1889
LangtagToLocaleID (langtag, localeID);
1842
1890
1891
+ const char16 searchString[] = _u (" search" );
1892
+ if (usage->BufferEquals (searchString, _countof (searchString) - 1 )) // minus the null terminator
1893
+ {
1894
+ uloc_setKeywordValue (" collation" , " search" , localeID, _countof (localeID), &status);
1895
+ ICU_ASSERT (status, true );
1896
+ }
1897
+
1843
1898
coll = FinalizableUCollator::New (scriptContext->GetRecycler (), ucol_open (localeID, &status));
1844
1899
ICU_ASSERT (status, true );
1845
1900
@@ -3114,45 +3169,34 @@ DEFINE_ISXLOCALEAVAILABLE(PR, uloc)
3114
3169
*/
3115
3170
Var IntlEngineInterfaceExtensionObject::EntryIntl_RegisterBuiltInFunction (RecyclableObject* function, CallInfo callInfo, ...)
3116
3171
{
3117
- // Don't put this in a header or add it to the namespace even in this file. Keep it to the minimum scope needed.
3118
- enum class IntlBuiltInFunctionID : int32 {
3119
- Min = 0 ,
3120
- DateToLocaleString = Min,
3121
- DateToLocaleDateString,
3122
- DateToLocaleTimeString,
3123
- NumberToLocaleString,
3124
- StringLocaleCompare,
3125
- Max
3126
- };
3127
-
3128
3172
EngineInterfaceObject_CommonFunctionProlog (function, callInfo);
3129
3173
3130
3174
// This function will only be used during the construction of the Intl object, hence Asserts are in place.
3131
3175
Assert (args.Info .Count >= 3 && JavascriptFunction::Is (args.Values [1 ]) && TaggedInt::Is (args.Values [2 ]));
3132
3176
3133
3177
JavascriptFunction *func = JavascriptFunction::FromVar (args.Values [1 ]);
3134
3178
int32 id = TaggedInt::ToInt32 (args.Values [2 ]);
3135
- Assert (id >= (int32)IntlBuiltInFunctionID::Min && id < (int32)IntlBuiltInFunctionID ::Max);
3179
+ Assert (id >= 0 && id < (int32)BuiltInFunctionID ::Max);
3136
3180
3137
3181
EngineInterfaceObject* nativeEngineInterfaceObj = scriptContext->GetLibrary ()->GetEngineInterfaceObject ();
3138
3182
IntlEngineInterfaceExtensionObject* extensionObject = static_cast <IntlEngineInterfaceExtensionObject*>(nativeEngineInterfaceObj->GetEngineExtension (EngineInterfaceExtensionKind_Intl));
3139
3183
3140
- IntlBuiltInFunctionID functionID = static_cast <IntlBuiltInFunctionID >(id);
3184
+ BuiltInFunctionID functionID = static_cast <BuiltInFunctionID >(id);
3141
3185
switch (functionID)
3142
3186
{
3143
- case IntlBuiltInFunctionID ::DateToLocaleString:
3187
+ case BuiltInFunctionID ::DateToLocaleString:
3144
3188
extensionObject->dateToLocaleString = func;
3145
3189
break ;
3146
- case IntlBuiltInFunctionID ::DateToLocaleDateString:
3190
+ case BuiltInFunctionID ::DateToLocaleDateString:
3147
3191
extensionObject->dateToLocaleDateString = func;
3148
3192
break ;
3149
- case IntlBuiltInFunctionID ::DateToLocaleTimeString:
3193
+ case BuiltInFunctionID ::DateToLocaleTimeString:
3150
3194
extensionObject->dateToLocaleTimeString = func;
3151
3195
break ;
3152
- case IntlBuiltInFunctionID ::NumberToLocaleString:
3196
+ case BuiltInFunctionID ::NumberToLocaleString:
3153
3197
extensionObject->numberToLocaleString = func;
3154
3198
break ;
3155
- case IntlBuiltInFunctionID ::StringLocaleCompare:
3199
+ case BuiltInFunctionID ::StringLocaleCompare:
3156
3200
extensionObject->stringLocaleCompare = func;
3157
3201
break ;
3158
3202
default :
0 commit comments