WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
WIP
bug-209774-20200624194941.patch (text/plain), 38.00 KB, created by
Yusuke Suzuki
on 2020-06-24 19:49:42 PDT
(
hide
)
Description:
WIP
Filename:
MIME Type:
Creator:
Yusuke Suzuki
Created:
2020-06-24 19:49:42 PDT
Size:
38.00 KB
patch
obsolete
>Subversion Revision: 263493 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index 41bdeabc03ce7ea6ab792ea58baaf9881a43fd07..ed4382c98c8648daaa5cfcac1a14ce7d883c2825 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,26 @@ >+2020-06-24 Yusuke Suzuki <ysuzuki@apple.com> >+ >+ [ECMA-402] Unified Intl.NumberFormat missing in WebKit >+ https://bugs.webkit.org/show_bug.cgi?id=209774 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * JavaScriptCore.xcodeproj/project.pbxproj: >+ * runtime/IntlNumberFormat.cpp: >+ (JSC::computeCurrencyDigits): >+ (JSC::isSanctionedSimpleUnitIdentifier): >+ (JSC::isWellFormedUnitIdentifier): >+ (JSC::IntlNumberFormat::initializeNumberFormat): >+ (JSC::IntlNumberFormat::styleString): >+ (JSC::IntlNumberFormat::currencyDisplayString): >+ * runtime/IntlNumberFormat.h: >+ * runtime/IntlNumberFormatInlines.h: Added. >+ (JSC::setNumberFormatDigitOptions): >+ * runtime/IntlPluralRules.cpp: >+ (JSC::IntlPluralRules::initializePluralRules): >+ (JSC::IntlPluralRules::resolvedOptions const): >+ * runtime/IntlPluralRules.h: >+ > 2020-06-24 Caitlin Potter <caitp@igalia.com> > > [JSC] handle Put/DefinePrivateField in resetPutByID >diff --git a/Source/WTF/ChangeLog b/Source/WTF/ChangeLog >index dd5f3cea737f06d53515c983bdc15cdc2deaf83c..355013fad80e2d009ec2ab9e01d29b57e2106b9d 100644 >--- a/Source/WTF/ChangeLog >+++ b/Source/WTF/ChangeLog >@@ -1,3 +1,14 @@ >+2020-06-24 Yusuke Suzuki <ysuzuki@apple.com> >+ >+ [ECMA-402] Unified Intl.NumberFormat missing in WebKit >+ https://bugs.webkit.org/show_bug.cgi?id=209774 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * wtf/text/ASCIILiteral.h: >+ * wtf/text/StringView.h: >+ (WTF::StringView::StringView): >+ > 2020-06-24 Umar Iqbal <uiqbal@apple.com> > > We should resurrect the older patch that collects some statistics of web API calls >diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >index 9f851c1172c6e04eab8388c2280da50843a63bdd..0b5db5c299dbf3f158375280aa3e0accf1a397a7 100644 >--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj >@@ -1789,6 +1789,7 @@ > E3201C1E1F8E824C0076A032 /* ScriptFetchParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = E38D060C1F8E814100649CF2 /* ScriptFetchParameters.h */; settings = {ATTRIBUTES = (Private, ); }; }; > E322E5A31DA64439006E7709 /* DFGSnippetParams.h in Headers */ = {isa = PBXBuildFile; fileRef = E322E5A11DA64435006E7709 /* DFGSnippetParams.h */; }; > E322E5A71DA644A8006E7709 /* FTLSnippetParams.h in Headers */ = {isa = PBXBuildFile; fileRef = E322E5A51DA644A4006E7709 /* FTLSnippetParams.h */; }; >+ E323116924A1DC3500693DA5 /* IntlNumberFormatInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E323116824A1DC2F00693DA5 /* IntlNumberFormatInlines.h */; }; > E325956421FDA2C9008EDC9C /* RegExpGlobalDataInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E325956321FDA2C8008EDC9C /* RegExpGlobalDataInlines.h */; }; > E325A36022211590007349A1 /* StringPrototypeInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E325A35F2221158A007349A1 /* StringPrototypeInlines.h */; }; > E3282BBB1FE930AF00EDAF71 /* YarrErrorCode.h in Headers */ = {isa = PBXBuildFile; fileRef = E3282BBA1FE930A400EDAF71 /* YarrErrorCode.h */; settings = {ATTRIBUTES = (Private, ); }; }; >@@ -4944,6 +4945,7 @@ > E322E5A11DA64435006E7709 /* DFGSnippetParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGSnippetParams.h; path = dfg/DFGSnippetParams.h; sourceTree = "<group>"; }; > E322E5A41DA644A4006E7709 /* FTLSnippetParams.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLSnippetParams.cpp; path = ftl/FTLSnippetParams.cpp; sourceTree = "<group>"; }; > E322E5A51DA644A4006E7709 /* FTLSnippetParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLSnippetParams.h; path = ftl/FTLSnippetParams.h; sourceTree = "<group>"; }; >+ E323116824A1DC2F00693DA5 /* IntlNumberFormatInlines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IntlNumberFormatInlines.h; sourceTree = "<group>"; }; > E325956321FDA2C8008EDC9C /* RegExpGlobalDataInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegExpGlobalDataInlines.h; sourceTree = "<group>"; }; > E325A35F2221158A007349A1 /* StringPrototypeInlines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StringPrototypeInlines.h; sourceTree = "<group>"; }; > E326C4961ECBEF5700A9A905 /* ClassInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClassInfo.cpp; sourceTree = "<group>"; }; >@@ -7272,6 +7274,7 @@ > A1D792F71B43864B004516F5 /* IntlNumberFormat.h */, > A1D792F81B43864B004516F5 /* IntlNumberFormatConstructor.cpp */, > A1D792F91B43864B004516F5 /* IntlNumberFormatConstructor.h */, >+ E323116824A1DC2F00693DA5 /* IntlNumberFormatInlines.h */, > A1D792FA1B43864B004516F5 /* IntlNumberFormatPrototype.cpp */, > A1D792FB1B43864B004516F5 /* IntlNumberFormatPrototype.h */, > A12BBFF31B044A9800664B69 /* IntlObject.cpp */, >@@ -9755,6 +9758,7 @@ > A1D792FD1B43864B004516F5 /* IntlNumberFormat.h in Headers */, > A1D792FF1B43864B004516F5 /* IntlNumberFormatConstructor.h in Headers */, > A125846E1B45A36000CC7F6C /* IntlNumberFormatConstructor.lut.h in Headers */, >+ E323116924A1DC3500693DA5 /* IntlNumberFormatInlines.h in Headers */, > A1D793011B43864B004516F5 /* IntlNumberFormatPrototype.h in Headers */, > A125846F1B45A36000CC7F6C /* IntlNumberFormatPrototype.lut.h in Headers */, > A12BBFF21B044A8B00664B69 /* IntlObject.h in Headers */, >diff --git a/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp b/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp >index c38fe99e2f4f0a3db2f3ab179922eba838aa2938..1a1a48f094dc7bb6b82c7c1ddd43239428847720 100644 >--- a/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp >+++ b/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp >@@ -30,6 +30,7 @@ > #include "IntlNumberFormat.h" > > #include "Error.h" >+#include "IntlNumberFormatInlines.h" > #include "IntlObject.h" > #include "JSBoundFunction.h" > #include "JSCInlines.h" >@@ -119,7 +120,7 @@ static unsigned computeCurrencyDigits(const String& currency) > // 11.1.1 The abstract operation CurrencyDigits (currency) > // "If the ISO 4217 currency and funds code list contains currency as an alphabetic code, > // then return the minor unit value corresponding to the currency from the list; else return 2. >- std::pair<const char*, unsigned> currencyMinorUnits[] = { >+ static constexpr std::pair<const char*, unsigned> currencyMinorUnits[] = { > { "BHD", 3 }, > { "BIF", 0 }, > { "BYR", 0 }, >@@ -153,6 +154,89 @@ static unsigned computeCurrencyDigits(const String& currency) > return 2; > } > >+static bool isSanctionedSimpleUnitIdentifier(StringView unitIdentifier) >+{ >+ static constexpr ASCIILiteral simpleUnits[] = { >+ "acre"_s, >+ "bit"_s, >+ "byte"_s, >+ "celsius"_s, >+ "centimeter"_s, >+ "day"_s, >+ "degree"_s, >+ "fahrenheit"_s, >+ "fluid-ounce"_s, >+ "foot"_s, >+ "gallon"_s, >+ "gigabit"_s, >+ "gigabyte"_s, >+ "gram"_s, >+ "hectare"_s, >+ "hour"_s, >+ "inch"_s, >+ "kilobit"_s, >+ "kilobyte"_s, >+ "kilogram"_s, >+ "kilometer"_s, >+ "liter"_s, >+ "megabit"_s, >+ "megabyte"_s, >+ "meter"_s, >+ "mile"_s, >+ "mile-scandinavian"_s, >+ "milliliter"_s, >+ "millimeter"_s, >+ "millisecond"_s, >+ "minute"_s, >+ "month"_s, >+ "ounce"_s, >+ "percent"_s, >+ "petabyte"_s, >+ "pound"_s, >+ "second"_s, >+ "stone"_s, >+ "terabit"_s, >+ "terabyte"_s, >+ "week"_s, >+ "yard"_s, >+ "year"_s, >+ }; >+ // FIXME: Do binary-search. >+ for (const ASCIILiteral& unit : simpleUnits) { >+ if (unitIdentifier == StringView(unit)) >+ return true; >+ } >+ return false; >+} >+ >+static bool isWellFormedUnitIdentifier(StringView unitIdentifier) >+{ >+ // https://tc39.es/ecma402/#sec-iswellformedunitidentifier >+ if (isSanctionedSimpleUnitIdentifier(unitIdentifier)) >+ return true; >+ >+ // If the substring "-per-" does not occur exactly once in unitIdentifier, then return false. >+ auto per = StringView("-per-"_s); >+ auto pos = unitIdentifier.find(per); >+ if (pos == WTF::notFound) >+ return false; >+ auto pos2 = unitIdentifier.find(per, pos + per.length()); >+ if (pos2 != WTF::notFound) >+ return false; >+ >+ // If the result of IsSanctionedSimpleUnitIdentifier(numerator) is false, then return false. >+ auto numerator = unitIdentifier.substring(0, pos); >+ if (!isSanctionedSimpleUnitIdentifier(numerator)) >+ return false; >+ >+ // If the result of IsSanctionedSimpleUnitIdentifier(denominator) is false, then return false. >+ auto denominator = unitIdentifier.substring(pos + per.length()); >+ if (!isSanctionedSimpleUnitIdentifier(denominator)) >+ return false; >+ >+ return true; >+} >+ > // https://tc39.github.io/ecma402/#sec-initializenumberformat > void IntlNumberFormat::initializeNumberFormat(JSGlobalObject* globalObject, JSValue locales, JSValue optionsValue) > { >@@ -197,14 +281,19 @@ void IntlNumberFormat::initializeNumberFormat(JSGlobalObject* globalObject, JSVa > > m_numberingSystem = result.get("nu"_s); > >- String styleString = intlStringOption(globalObject, options, vm.propertyNames->style, { "decimal", "percent", "currency" }, "style must be either \"decimal\", \"percent\", or \"currency\"", "decimal"); >+ // SetNumberFormatUnitOptions(intlObject, options) >+ // https://tc39.es/ecma402/#sec-setnumberformatunitoptions >+ >+ String styleString = intlStringOption(globalObject, options, vm.propertyNames->style, { "decimal", "percent", "currency", "unit" }, "style must be either \"decimal\", \"percent\", \"currency\", or \"unit\"", "decimal"); > RETURN_IF_EXCEPTION(scope, void()); >- if (styleString == "decimal") >+ if (styleString == "decimal"_s) > m_style = Style::Decimal; >- else if (styleString == "percent") >+ else if (styleString == "percent"_s) > m_style = Style::Percent; >- else if (styleString == "currency") >+ else if (styleString == "currency"_s) > m_style = Style::Currency; >+ else if (styleString == "unit"_s) >+ m_style = Style::Unit; > else > ASSERT_NOT_REACHED(); > >@@ -229,60 +318,108 @@ void IntlNumberFormat::initializeNumberFormat(JSGlobalObject* globalObject, JSVa > currencyDigits = computeCurrencyDigits(currency); > } > >- String currencyDisplayString = intlStringOption(globalObject, options, Identifier::fromString(vm, "currencyDisplay"), { "code", "symbol", "name" }, "currencyDisplay must be either \"code\", \"symbol\", or \"name\"", "symbol"); >+ String currencyDisplayString = intlStringOption(globalObject, options, Identifier::fromString(vm, "currencyDisplay"), { "code", "symbol", "narrowSymbol", "name" }, "currencyDisplay must be either \"code\", \"symbol\", \"narrowSymbol\", or \"name\"", "symbol"); > RETURN_IF_EXCEPTION(scope, void()); > if (m_style == Style::Currency) { >- if (currencyDisplayString == "code") >+ if (currencyDisplayString == "code"_s) > m_currencyDisplay = CurrencyDisplay::Code; >- else if (currencyDisplayString == "symbol") >+ else if (currencyDisplayString == "symbol"_s) > m_currencyDisplay = CurrencyDisplay::Symbol; >- else if (currencyDisplayString == "name") >+ else if (currencyDisplayString == "narrowSymbol"_s) >+ m_currencyDisplay = CurrencyDisplay::NarrowSymbol; >+ else if (currencyDisplayString == "name"_s) > m_currencyDisplay = CurrencyDisplay::Name; > else > ASSERT_NOT_REACHED(); > } > >- unsigned minimumIntegerDigits = intlNumberOption(globalObject, options, Identifier::fromString(vm, "minimumIntegerDigits"), 1, 21, 1); >+ String currencySignString = intlStringOption(globalObject, options, Identifier::fromString(vm, "currencySign"), { "standard", "accounting" }, "currencySign must be either \"standard\" or \"accounting\"", "standard"); > RETURN_IF_EXCEPTION(scope, void()); >- m_minimumIntegerDigits = minimumIntegerDigits; >+ if (m_style == Style::Currency) { >+ if (currencySignString == "standard"_s) >+ m_currencySign = CurrencySign::Standard; >+ else if (currencySignString == "accounting"_s) >+ m_currencySign = CurrencySign::Accounting; >+ else >+ ASSERT_NOT_REACHED(); >+ } > >- unsigned minimumFractionDigitsDefault = (m_style == Style::Currency) ? currencyDigits : 0; >+ String unit = intlStringOption(globalObject, options, Identifier::fromString(vm, "unit"), { }, nullptr, nullptr); >+ RETURN_IF_EXCEPTION(scope, void()); >+ if (!unit.isNull()) { >+ if (!isWellFormedUnitIdentifier(unit)) { >+ throwException(globalObject, scope, createRangeError(globalObject, "unit is not a well-formed unit identifier"_s)); >+ return; >+ } >+ m_unit = unit; >+ } else { >+ if (m_style == Style::Unit) { >+ throwTypeError(globalObject, scope, "unit must be a string"_s); >+ return; >+ } >+ } > >- unsigned minimumFractionDigits = intlNumberOption(globalObject, options, Identifier::fromString(vm, "minimumFractionDigits"), 0, 20, minimumFractionDigitsDefault); >+ String unitDisplayString = intlStringOption(globalObject, options, Identifier::fromString(vm, "unitDisplay"), { "short", "narrow", "long" }, "unitDisplay must be either \"short\", \"narrow\", or \"long\"", "short"); > RETURN_IF_EXCEPTION(scope, void()); >- m_minimumFractionDigits = minimumFractionDigits; >+ if (m_style == Style::Unit) { >+ if (unitDisplayString == "short"_s) >+ m_unitDisplay = UnitDisplay::Short; >+ else if (unitDisplayString == "narrow"_s) >+ m_unitDisplay = UnitDisplay::Narrow; >+ else if (unitDisplayString == "long"_s) >+ m_unitDisplay = UnitDisplay::Long; >+ else >+ ASSERT_NOT_REACHED(); >+ } > >- unsigned maximumFractionDigitsDefault; >- if (m_style == Style::Currency) >- maximumFractionDigitsDefault = std::max(minimumFractionDigits, currencyDigits); >- else if (m_style == Style::Percent) >- maximumFractionDigitsDefault = minimumFractionDigits; >- else >- maximumFractionDigitsDefault = std::max(minimumFractionDigits, 3u); >+ unsigned minimumFractionDigitsDefault = (m_style == Style::Currency) ? currencyDigits : 0; >+ unsigned maximumFractionDigitsDefault = (m_style == Style::Currency) ? currencyDigits : (m_style == Style::Percent) ? 0 : 3; > >- unsigned maximumFractionDigits = intlNumberOption(globalObject, options, Identifier::fromString(vm, "maximumFractionDigits"), minimumFractionDigits, 20, maximumFractionDigitsDefault); >+ IntlNotation notation = IntlNotation::Standard; >+ String notationString = intlStringOption(globalObject, options, Identifier::fromString(vm, "notation"), { "standard", "scientific", "engineering", "compact" }, "notation must be either \"standard\", \"scientific\", \"engineering\", or \"compact\"", "standard"); > RETURN_IF_EXCEPTION(scope, void()); >- m_maximumFractionDigits = maximumFractionDigits; >+ if (notationString == "standard"_s) >+ notation = IntlNotation::Standard; >+ else if (notationString == "scientific"_s) >+ notation = IntlNotation::Scientific; >+ else if (notationString == "engineering"_s) >+ notation = IntlNotation::Engineering; >+ else if (notationString == "compact"_s) >+ notation = IntlNotation::Compact; >+ else >+ ASSERT_NOT_REACHED(); > >- JSValue minimumSignificantDigitsValue = options->get(globalObject, Identifier::fromString(vm, "minimumSignificantDigits")); >+ setNumberFormatDigitOptions(globalObject, this, options, minimumFractionDigitsDefault, maximumFractionDigitsDefault, notation); > RETURN_IF_EXCEPTION(scope, void()); > >- JSValue maximumSignificantDigitsValue = options->get(globalObject, Identifier::fromString(vm, "maximumSignificantDigits")); >+ String compactDisplay = intlStringOption(globalObject, options, Identifier::fromString(vm, "compactDisplay"), { "short", "long" }, "compactDisplay must be either \"short\" or \"long\"", "short"); > RETURN_IF_EXCEPTION(scope, void()); >- >- if (!minimumSignificantDigitsValue.isUndefined() || !maximumSignificantDigitsValue.isUndefined()) { >- unsigned minimumSignificantDigits = intlDefaultNumberOption(globalObject, minimumSignificantDigitsValue, Identifier::fromString(vm, "minimumSignificantDigits"), 1, 21, 1); >- RETURN_IF_EXCEPTION(scope, void()); >- unsigned maximumSignificantDigits = intlDefaultNumberOption(globalObject, maximumSignificantDigitsValue, Identifier::fromString(vm, "maximumSignificantDigits"), minimumSignificantDigits, 21, 21); >- RETURN_IF_EXCEPTION(scope, void()); >- m_minimumSignificantDigits = minimumSignificantDigits; >- m_maximumSignificantDigits = maximumSignificantDigits; >+ if (notation == IntlNotation::Compact) { >+ if (compactDisplay == "short"_s) >+ m_compactDisplay = CompactDisplay::Short; >+ else if (compactDisplay == "long"_s) >+ m_compactDisplay = CompactDisplay::Long; >+ else >+ ASSERT_NOT_REACHED(); > } > > TriState useGrouping = intlBooleanOption(globalObject, options, Identifier::fromString(vm, "useGrouping")); > RETURN_IF_EXCEPTION(scope, void()); > m_useGrouping = useGrouping != TriState::False; > >+ String signDisplay = intlStringOption(globalObject, options, Identifier::fromString(vm, "signDisplay"), { "short", "long" }, "signDisplay must be either \"auto\", \"never\", \"always\", or \"exceptZero\"", "auto"); >+ RETURN_IF_EXCEPTION(scope, void()); >+ if (signDisplay == "auto"_s) >+ m_signDisplay = SignDisplay::Auto; >+ else if (signDisplay == "never"_s) >+ m_signDisplay = SignDisplay::Never; >+ else if (signDisplay == "always"_s) >+ m_signDisplay = SignDisplay::Always; >+ else if (signDisplay == "exceptZero"_s) >+ m_signDisplay = SignDisplay::ExceptZero; >+ else >+ ASSERT_NOT_REACHED(); >+ > UNumberFormatStyle style = UNUM_DEFAULT; > switch (m_style) { > case Style::Decimal: >@@ -299,15 +436,16 @@ void IntlNumberFormat::initializeNumberFormat(JSGlobalObject* globalObject, JSVa > case CurrencyDisplay::Symbol: > style = UNUM_CURRENCY; > break; >+ case CurrencyDisplay::NarrowSymbol: >+ style = UNUM_CURRENCY; >+ break; > case CurrencyDisplay::Name: > style = UNUM_CURRENCY_PLURAL; > break; >- default: >- ASSERT_NOT_REACHED(); > } > break; >- default: >- ASSERT_NOT_REACHED(); >+ case Style::Unit: >+ break; > } > > UErrorCode status = U_ZERO_ERROR; >@@ -324,14 +462,20 @@ void IntlNumberFormat::initializeNumberFormat(JSGlobalObject* globalObject, JSVa > return; > } > } >- if (!m_minimumSignificantDigits) { >+ >+ switch (m_roundingType) { >+ case IntlRoundingType::FractionDigits: > unum_setAttribute(m_numberFormat.get(), UNUM_MIN_INTEGER_DIGITS, m_minimumIntegerDigits); > unum_setAttribute(m_numberFormat.get(), UNUM_MIN_FRACTION_DIGITS, m_minimumFractionDigits); > unum_setAttribute(m_numberFormat.get(), UNUM_MAX_FRACTION_DIGITS, m_maximumFractionDigits); >- } else { >+ break; >+ case IntlRoundingType::SignificantDigits: > unum_setAttribute(m_numberFormat.get(), UNUM_SIGNIFICANT_DIGITS_USED, true); > unum_setAttribute(m_numberFormat.get(), UNUM_MIN_SIGNIFICANT_DIGITS, m_minimumSignificantDigits); > unum_setAttribute(m_numberFormat.get(), UNUM_MAX_SIGNIFICANT_DIGITS, m_maximumSignificantDigits); >+ break; >+ case IntlRoundingType::CompactRounding: >+ break; > } > unum_setAttribute(m_numberFormat.get(), UNUM_GROUPING_USED, m_useGrouping); > unum_setAttribute(m_numberFormat.get(), UNUM_ROUNDING_MODE, UNUM_ROUND_HALFUP); >@@ -384,6 +528,8 @@ ASCIILiteral IntlNumberFormat::styleString(Style style) > return "percent"_s; > case Style::Currency: > return "currency"_s; >+ case Style::Unit: >+ return "unit"_s; > } > ASSERT_NOT_REACHED(); > return ASCIILiteral::null(); >@@ -396,6 +542,8 @@ ASCIILiteral IntlNumberFormat::currencyDisplayString(CurrencyDisplay currencyDis > return "code"_s; > case CurrencyDisplay::Symbol: > return "symbol"_s; >+ case CurrencyDisplay::NarrowSymbol: >+ return "narrowSymbol"_s; > case CurrencyDisplay::Name: > return "name"_s; > } >diff --git a/Source/JavaScriptCore/runtime/IntlNumberFormat.h b/Source/JavaScriptCore/runtime/IntlNumberFormat.h >index 4304b22a8c6a511f74e2bdcb05388d5b65b73476..25c36e2a0db71e7a4c5d9909772728c646a19d4a 100644 >--- a/Source/JavaScriptCore/runtime/IntlNumberFormat.h >+++ b/Source/JavaScriptCore/runtime/IntlNumberFormat.h >@@ -33,6 +33,10 @@ namespace JSC { > > class JSBoundFunction; > >+enum class IntlRoundingType : uint8_t { FractionDigits, SignificantDigits, CompactRounding }; >+enum class IntlNotation { Standard, Scientific, Engineering, Compact }; >+template<typename IntlType> void setNumberFormatDigitOptions(JSGlobalObject*, IntlType*, JSObject*, unsigned, unsigned, IntlNotation); >+ > class IntlNumberFormat final : public JSNonFinalObject { > public: > using Base = JSNonFinalObject; >@@ -66,6 +70,9 @@ class IntlNumberFormat final : public JSNonFinalObject { > > static void formatToPartsInternal(JSGlobalObject*, double, const String& formatted, UFieldPositionIterator*, JSArray*, JSString* unit = nullptr); > >+ template<typename IntlType> >+ friend void setNumberFormatDigitOptions(JSGlobalObject*, IntlType*, JSObject*, unsigned, unsigned, IntlNotation); >+ > private: > IntlNumberFormat(VM&, Structure*); > void finishCreation(VM&); >@@ -73,8 +80,12 @@ class IntlNumberFormat final : public JSNonFinalObject { > > static Vector<String> localeData(const String&, size_t); > >- enum class Style : uint8_t { Decimal, Percent, Currency }; >- enum class CurrencyDisplay : uint8_t { Code, Symbol, Name }; >+ enum class Style : uint8_t { Decimal, Percent, Currency, Unit }; >+ enum class CurrencyDisplay : uint8_t { Code, Symbol, NarrowSymbol, Name }; >+ enum class CurrencySign : uint8_t { Standard, Accounting }; >+ enum class UnitDisplay : uint8_t { Short, Narrow, Long }; >+ enum class CompactDisplay : uint8_t { Short, Long }; >+ enum class SignDisplay : uint8_t { Auto, Never, Always, ExceptZero }; > > struct UNumberFormatDeleter { > void operator()(UNumberFormat*) const; >@@ -89,6 +100,7 @@ class IntlNumberFormat final : public JSNonFinalObject { > String m_locale; > String m_numberingSystem; > String m_currency; >+ String m_unit; > unsigned m_minimumIntegerDigits { 1 }; > unsigned m_minimumFractionDigits { 0 }; > unsigned m_maximumFractionDigits { 3 }; >@@ -96,7 +108,12 @@ class IntlNumberFormat final : public JSNonFinalObject { > unsigned m_maximumSignificantDigits { 0 }; > Style m_style { Style::Decimal }; > CurrencyDisplay m_currencyDisplay; >+ CurrencySign m_currencySign; >+ UnitDisplay m_unitDisplay; >+ CompactDisplay m_compactDisplay; >+ SignDisplay m_signDisplay; > bool m_useGrouping { true }; >+ IntlRoundingType m_roundingType { IntlRoundingType::FractionDigits }; > }; > > } // namespace JSC >diff --git a/Source/JavaScriptCore/runtime/IntlNumberFormatInlines.h b/Source/JavaScriptCore/runtime/IntlNumberFormatInlines.h >new file mode 100644 >index 0000000000000000000000000000000000000000..b358e49db58ff9c6c9ef5cdfec6bc17444b3cc61 >--- /dev/null >+++ b/Source/JavaScriptCore/runtime/IntlNumberFormatInlines.h >@@ -0,0 +1,90 @@ >+/* >+ * Copyright (C) 2020 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#pragma once >+ >+#include "IntlNumberFormat.h" >+#include "IntlObject.h" >+#include "JSGlobalObject.h" >+ >+namespace JSC { >+ >+template<typename IntlType> >+void setNumberFormatDigitOptions(JSGlobalObject* globalObject, IntlType* intlObject, JSObject* options, unsigned minimumFractionDigitsDefault, unsigned maximumFractionDigitsDefault, IntlNotation notation) >+{ >+ VM& vm = globalObject->vm(); >+ auto scope = DECLARE_THROW_SCOPE(vm); >+ >+ unsigned minimumIntegerDigits = intlNumberOption(globalObject, options, Identifier::fromString(vm, "minimumIntegerDigits"), 1, 21, 1); >+ RETURN_IF_EXCEPTION(scope, void()); >+ >+ JSValue minimumFractionDigitsValue = options->get(globalObject, Identifier::fromString(vm, "minimumFractionDigits")); >+ RETURN_IF_EXCEPTION(scope, void()); >+ >+ JSValue maximumFractionDigitsValue = options->get(globalObject, Identifier::fromString(vm, "maximumFractionDigits")); >+ RETURN_IF_EXCEPTION(scope, void()); >+ >+ JSValue minimumSignificantDigitsValue = options->get(globalObject, Identifier::fromString(vm, "minimumSignificantDigits")); >+ RETURN_IF_EXCEPTION(scope, void()); >+ >+ JSValue maximumSignificantDigitsValue = options->get(globalObject, Identifier::fromString(vm, "maximumSignificantDigits")); >+ RETURN_IF_EXCEPTION(scope, void()); >+ >+ intlObject->m_minimumIntegerDigits = minimumIntegerDigits; >+ >+ if (!minimumSignificantDigitsValue.isUndefined() || !maximumSignificantDigitsValue.isUndefined()) { >+ intlObject->m_roundingType = IntlRoundingType::SignificantDigits; >+ unsigned minimumSignificantDigits = intlDefaultNumberOption(globalObject, minimumSignificantDigitsValue, Identifier::fromString(vm, "minimumSignificantDigits"), 1, 21, 1); >+ RETURN_IF_EXCEPTION(scope, void()); >+ unsigned maximumSignificantDigits = intlDefaultNumberOption(globalObject, maximumSignificantDigitsValue, Identifier::fromString(vm, "maximumSignificantDigits"), minimumSignificantDigits, 21, 21); >+ RETURN_IF_EXCEPTION(scope, void()); >+ intlObject->m_minimumSignificantDigits = minimumSignificantDigits; >+ intlObject->m_maximumSignificantDigits = maximumSignificantDigits; >+ return; >+ } >+ >+ if (!minimumFractionDigitsValue.isUndefined() || !maximumFractionDigitsValue.isUndefined()) { >+ intlObject->m_roundingType = IntlRoundingType::FractionDigits; >+ unsigned minimumFractionDigits = intlDefaultNumberOption(globalObject, minimumFractionDigitsValue, Identifier::fromString(vm, "minimumFractionDigits"), 0, 20, minimumFractionDigitsDefault); >+ RETURN_IF_EXCEPTION(scope, void()); >+ unsigned maximumFractionDigitsActualDefault = std::max(minimumFractionDigits, maximumFractionDigitsDefault); >+ unsigned maximumFractionDigits = intlDefaultNumberOption(globalObject, maximumFractionDigitsValue, Identifier::fromString(vm, "maximumFractionDigits"), minimumFractionDigits, 20, maximumFractionDigitsActualDefault); >+ RETURN_IF_EXCEPTION(scope, void()); >+ intlObject->m_minimumFractionDigits = minimumFractionDigits; >+ intlObject->m_maximumFractionDigits = maximumFractionDigits; >+ return; >+ } >+ >+ if (notation == IntlNotation::Compact) { >+ intlObject->m_roundingType = IntlRoundingType::CompactRounding; >+ return; >+ } >+ >+ intlObject->m_roundingType = IntlRoundingType::FractionDigits; >+ intlObject->m_minimumFractionDigits = minimumFractionDigitsDefault; >+ intlObject->m_maximumFractionDigits = maximumFractionDigitsDefault; >+} >+ >+} // namespace JSC >diff --git a/Source/JavaScriptCore/runtime/IntlPluralRules.cpp b/Source/JavaScriptCore/runtime/IntlPluralRules.cpp >index 616e52ed8e5f92916d4f683137fcfbc72000c5f7..818b6a23d230650cc17d8bde23db18bedf69ecbc 100644 >--- a/Source/JavaScriptCore/runtime/IntlPluralRules.cpp >+++ b/Source/JavaScriptCore/runtime/IntlPluralRules.cpp >@@ -27,6 +27,7 @@ > #include "config.h" > #include "IntlPluralRules.h" > >+#include "IntlNumberFormatInlines.h" > #include "IntlObject.h" > #include "JSCInlines.h" > #include "ObjectConstructor.h" >@@ -125,34 +126,8 @@ void IntlPluralRules::initializePluralRules(JSGlobalObject* globalObject, JSValu > RETURN_IF_EXCEPTION(scope, void()); > m_type = typeString == "ordinal" ? UPLURAL_TYPE_ORDINAL : UPLURAL_TYPE_CARDINAL; > >- unsigned minimumIntegerDigits = intlNumberOption(globalObject, options, Identifier::fromString(vm, "minimumIntegerDigits"), 1, 21, 1); >+ setNumberFormatDigitOptions(globalObject, this, options, 0, 3, IntlNotation::Standard); > RETURN_IF_EXCEPTION(scope, void()); >- m_minimumIntegerDigits = minimumIntegerDigits; >- >- unsigned minimumFractionDigitsDefault = 0; >- unsigned minimumFractionDigits = intlNumberOption(globalObject, options, Identifier::fromString(vm, "minimumFractionDigits"), 0, 20, minimumFractionDigitsDefault); >- RETURN_IF_EXCEPTION(scope, void()); >- m_minimumFractionDigits = minimumFractionDigits; >- >- unsigned maximumFractionDigitsDefault = std::max(minimumFractionDigits, 3u); >- unsigned maximumFractionDigits = intlNumberOption(globalObject, options, Identifier::fromString(vm, "maximumFractionDigits"), minimumFractionDigits, 20, maximumFractionDigitsDefault); >- RETURN_IF_EXCEPTION(scope, void()); >- m_maximumFractionDigits = maximumFractionDigits; >- >- JSValue minimumSignificantDigitsValue = options->get(globalObject, Identifier::fromString(vm, "minimumSignificantDigits")); >- RETURN_IF_EXCEPTION(scope, void()); >- >- JSValue maximumSignificantDigitsValue = options->get(globalObject, Identifier::fromString(vm, "maximumSignificantDigits")); >- RETURN_IF_EXCEPTION(scope, void()); >- >- if (!minimumSignificantDigitsValue.isUndefined() || !maximumSignificantDigitsValue.isUndefined()) { >- unsigned minimumSignificantDigits = intlNumberOption(globalObject, options, Identifier::fromString(vm, "minimumSignificantDigits"), 1, 21, 1); >- RETURN_IF_EXCEPTION(scope, void()); >- unsigned maximumSignificantDigits = intlNumberOption(globalObject, options, Identifier::fromString(vm, "maximumSignificantDigits"), minimumSignificantDigits, 21, 21); >- RETURN_IF_EXCEPTION(scope, void()); >- m_minimumSignificantDigits = minimumSignificantDigits; >- m_maximumSignificantDigits = maximumSignificantDigits; >- } > > UErrorCode status = U_ZERO_ERROR; > m_numberFormat = std::unique_ptr<UNumberFormat, UNumberFormatDeleter>(unum_open(UNUM_DECIMAL, nullptr, 0, m_locale.utf8().data(), nullptr, &status)); >@@ -161,14 +136,20 @@ void IntlPluralRules::initializePluralRules(JSGlobalObject* globalObject, JSValu > return; > } > >- if (m_minimumSignificantDigits) { >- unum_setAttribute(m_numberFormat.get(), UNUM_SIGNIFICANT_DIGITS_USED, true); >- unum_setAttribute(m_numberFormat.get(), UNUM_MIN_SIGNIFICANT_DIGITS, m_minimumSignificantDigits.value()); >- unum_setAttribute(m_numberFormat.get(), UNUM_MAX_SIGNIFICANT_DIGITS, m_maximumSignificantDigits.value()); >- } else { >+ switch (m_roundingType) { >+ case IntlRoundingType::FractionDigits: > unum_setAttribute(m_numberFormat.get(), UNUM_MIN_INTEGER_DIGITS, m_minimumIntegerDigits); > unum_setAttribute(m_numberFormat.get(), UNUM_MIN_FRACTION_DIGITS, m_minimumFractionDigits); > unum_setAttribute(m_numberFormat.get(), UNUM_MAX_FRACTION_DIGITS, m_maximumFractionDigits); >+ break; >+ case IntlRoundingType::SignificantDigits: >+ unum_setAttribute(m_numberFormat.get(), UNUM_SIGNIFICANT_DIGITS_USED, true); >+ unum_setAttribute(m_numberFormat.get(), UNUM_MIN_SIGNIFICANT_DIGITS, m_minimumSignificantDigits); >+ unum_setAttribute(m_numberFormat.get(), UNUM_MAX_SIGNIFICANT_DIGITS, m_maximumSignificantDigits); >+ break; >+ default: >+ RELEASE_ASSERT_NOT_REACHED(); >+ break; > } > > status = U_ZERO_ERROR; >@@ -191,11 +172,18 @@ JSObject* IntlPluralRules::resolvedOptions(JSGlobalObject* globalObject) const > options->putDirect(vm, vm.propertyNames->locale, jsNontrivialString(vm, m_locale)); > options->putDirect(vm, vm.propertyNames->type, jsNontrivialString(vm, m_type == UPLURAL_TYPE_ORDINAL ? "ordinal"_s : "cardinal"_s)); > options->putDirect(vm, Identifier::fromString(vm, "minimumIntegerDigits"), jsNumber(m_minimumIntegerDigits)); >- options->putDirect(vm, Identifier::fromString(vm, "minimumFractionDigits"), jsNumber(m_minimumFractionDigits)); >- options->putDirect(vm, Identifier::fromString(vm, "maximumFractionDigits"), jsNumber(m_maximumFractionDigits)); >- if (m_minimumSignificantDigits) { >- options->putDirect(vm, Identifier::fromString(vm, "minimumSignificantDigits"), jsNumber(m_minimumSignificantDigits.value())); >- options->putDirect(vm, Identifier::fromString(vm, "maximumSignificantDigits"), jsNumber(m_maximumSignificantDigits.value())); >+ switch (m_roundingType) { >+ case IntlRoundingType::FractionDigits: >+ options->putDirect(vm, Identifier::fromString(vm, "minimumFractionDigits"), jsNumber(m_minimumFractionDigits)); >+ options->putDirect(vm, Identifier::fromString(vm, "maximumFractionDigits"), jsNumber(m_maximumFractionDigits)); >+ break; >+ case IntlRoundingType::SignificantDigits: >+ options->putDirect(vm, Identifier::fromString(vm, "minimumSignificantDigits"), jsNumber(m_minimumSignificantDigits)); >+ options->putDirect(vm, Identifier::fromString(vm, "maximumSignificantDigits"), jsNumber(m_maximumSignificantDigits)); >+ break; >+ default: >+ RELEASE_ASSERT_NOT_REACHED(); >+ break; > } > > JSArray* categories = JSArray::tryCreate(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous), 0); >diff --git a/Source/JavaScriptCore/runtime/IntlPluralRules.h b/Source/JavaScriptCore/runtime/IntlPluralRules.h >index d3712736fafb2a21a2a67cabe4fa185bd7e05e1d..ee2bafc3c7132dcc6ba2c38473c51ccbf722ad6d 100644 >--- a/Source/JavaScriptCore/runtime/IntlPluralRules.h >+++ b/Source/JavaScriptCore/runtime/IntlPluralRules.h >@@ -25,7 +25,7 @@ > > #pragma once > >-#include "JSObject.h" >+#include "IntlNumberFormat.h" > #include <unicode/unum.h> > #include <unicode/upluralrules.h> > >@@ -53,6 +53,9 @@ class IntlPluralRules final : public JSNonFinalObject { > > DECLARE_INFO; > >+ template<typename IntlType> >+ friend void setNumberFormatDigitOptions(JSGlobalObject*, IntlType*, JSObject*, unsigned, unsigned, IntlNotation); >+ > void initializePluralRules(JSGlobalObject*, JSValue locales, JSValue options); > JSValue select(JSGlobalObject*, double value) const; > JSObject* resolvedOptions(JSGlobalObject*) const; >@@ -79,8 +82,9 @@ class IntlPluralRules final : public JSNonFinalObject { > unsigned m_minimumIntegerDigits { 1 }; > unsigned m_minimumFractionDigits { 0 }; > unsigned m_maximumFractionDigits { 3 }; >- Optional<unsigned> m_minimumSignificantDigits; >- Optional<unsigned> m_maximumSignificantDigits; >+ unsigned m_minimumSignificantDigits { 0 }; >+ unsigned m_maximumSignificantDigits { 0 }; >+ IntlRoundingType m_roundingType { IntlRoundingType::FractionDigits }; > }; > > } // namespace JSC >diff --git a/Source/WTF/wtf/text/ASCIILiteral.h b/Source/WTF/wtf/text/ASCIILiteral.h >index a908df3bea61ffc23ebddb344c756fc2c8e88277..f7a479a0ba071ef0689a0e1232fbeb44a5d0b6e4 100644 >--- a/Source/WTF/wtf/text/ASCIILiteral.h >+++ b/Source/WTF/wtf/text/ASCIILiteral.h >@@ -26,6 +26,7 @@ > #pragma once > > #include <wtf/ASCIICType.h> >+#include <wtf/StdLibExtras.h> > > namespace WTF { > >@@ -47,7 +48,9 @@ class ASCIILiteral final { > return ASCIILiteral { nullptr }; > } > >- const char* characters() const { return m_characters; } >+ constexpr const char* characters() const { return m_characters; } >+ const LChar* characters8() const { return bitwise_cast<const LChar*>(m_characters); } >+ size_t length() const { return strlen(m_characters); } > > private: > constexpr explicit ASCIILiteral(const char* characters) : m_characters(characters) { } >diff --git a/Source/WTF/wtf/text/StringView.h b/Source/WTF/wtf/text/StringView.h >index 8bdc8b0ee19b32cd5f06ffdc2ca77ae35a61f38d..c22a8ae34461c3b3cc802bfcb5301a6672bc9ef6 100644 >--- a/Source/WTF/wtf/text/StringView.h >+++ b/Source/WTF/wtf/text/StringView.h >@@ -31,6 +31,7 @@ > #include <wtf/Optional.h> > #include <wtf/RetainPtr.h> > #include <wtf/Vector.h> >+#include <wtf/text/ASCIILiteral.h> > #include <wtf/text/CString.h> > #include <wtf/text/ConversionMode.h> > #include <wtf/text/LChar.h> >@@ -68,6 +69,7 @@ class StringView final { > StringView(const UChar*, unsigned length); > StringView(const char*); > StringView(const char*, unsigned length); >+ StringView(ASCIILiteral); > > static StringView empty(); > >@@ -356,6 +358,11 @@ inline StringView::StringView(const char* characters, unsigned length) > initialize(reinterpret_cast<const LChar*>(characters), length); > } > >+inline StringView::StringView(ASCIILiteral string) >+{ >+ initialize(string.characters8(), string.length()); >+} >+ > inline StringView::StringView(const StringImpl& string) > { > setUnderlyingString(&string);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 209774
:
402712
|
402749
|
402843
|
402853
|
402854
|
402895
|
402944
|
402945
|
402946
|
402947
|
402948
|
402950
|
402953
|
403033
|
403035
|
403079
|
406493