1573 lines
67 KiB
Diff
1573 lines
67 KiB
Diff
From ebc0c4a088acbc523bda3b935b8c59a6568ae318 Mon Sep 17 00:00:00 2001
|
|
From: Michael Catanzaro <mcatanzaro@redhat.com>
|
|
Date: Thu, 27 Mar 2025 15:56:41 -0500
|
|
Subject: [PATCH 1/4] Revert "[CMake] Update minimum ICU version to 70.1"
|
|
|
|
This reverts commit 95d71be25d5b838b1171e6b9b2cd526190118fba.
|
|
---
|
|
Source/cmake/OptionsGTK.cmake | 6 +++---
|
|
Source/cmake/OptionsJSCOnly.cmake | 2 +-
|
|
Source/cmake/OptionsMac.cmake | 2 +-
|
|
Source/cmake/OptionsPlayStation.cmake | 2 +-
|
|
Source/cmake/OptionsWPE.cmake | 6 +++---
|
|
Source/cmake/OptionsWin.cmake | 2 +-
|
|
6 files changed, 10 insertions(+), 10 deletions(-)
|
|
|
|
diff --git a/Source/cmake/OptionsGTK.cmake b/Source/cmake/OptionsGTK.cmake
|
|
index 677ab4e49155..57dd75e4d9a8 100644
|
|
--- a/Source/cmake/OptionsGTK.cmake
|
|
+++ b/Source/cmake/OptionsGTK.cmake
|
|
@@ -10,11 +10,11 @@ set(USER_AGENT_BRANDING "" CACHE STRING "Branding to add to user agent string")
|
|
find_package(Cairo 1.16.0 REQUIRED)
|
|
find_package(LibGcrypt 1.7.0 REQUIRED)
|
|
find_package(Libtasn1 REQUIRED)
|
|
-find_package(HarfBuzz 2.7.4 REQUIRED COMPONENTS ICU)
|
|
-find_package(ICU 70.1 REQUIRED COMPONENTS data i18n uc)
|
|
+find_package(HarfBuzz 1.4.2 REQUIRED COMPONENTS ICU)
|
|
+find_package(ICU 61.2 REQUIRED COMPONENTS data i18n uc)
|
|
find_package(JPEG REQUIRED)
|
|
find_package(Epoxy 1.5.4 REQUIRED)
|
|
-find_package(LibXml2 2.9.13 REQUIRED)
|
|
+find_package(LibXml2 2.8.0 REQUIRED)
|
|
find_package(PNG REQUIRED)
|
|
find_package(SQLite3 REQUIRED)
|
|
find_package(Threads REQUIRED)
|
|
--
|
|
2.49.0
|
|
|
|
|
|
From e2a9042fb85253f297f136424460526ebf441d4d Mon Sep 17 00:00:00 2001
|
|
From: Michael Catanzaro <mcatanzaro@redhat.com>
|
|
Date: Fri, 28 Mar 2025 14:45:03 -0500
|
|
Subject: [PATCH 2/4] Revert "[JSC] Remove unnecessary ICU version checks"
|
|
|
|
This reverts commit af62f09a1fad0b72293a7f0d082704d92116cb9a.
|
|
---
|
|
.../runtime/IntlDurationFormat.cpp | 2 +-
|
|
.../runtime/IntlNumberFormat.cpp | 12 ++--
|
|
.../runtime/IntlNumberFormatInlines.h | 57 ++++++++++++-------
|
|
3 files changed, 47 insertions(+), 24 deletions(-)
|
|
|
|
diff --git a/Source/JavaScriptCore/runtime/IntlDurationFormat.cpp b/Source/JavaScriptCore/runtime/IntlDurationFormat.cpp
|
|
index 61264bfe23d9..a1c628082dd5 100644
|
|
--- a/Source/JavaScriptCore/runtime/IntlDurationFormat.cpp
|
|
+++ b/Source/JavaScriptCore/runtime/IntlDurationFormat.cpp
|
|
@@ -457,7 +457,7 @@ static Vector<Element> collectElements(JSGlobalObject* globalObject, const IntlD
|
|
|
|
// 3.k. If style is "2-digit", then
|
|
// i. Perform ! CreateDataPropertyOrThrow(nfOpts, "minimumIntegerDigits", 2F).
|
|
- skeletonBuilder.append(" integer-width/*"_s);
|
|
+ skeletonBuilder.append(" integer-width/"_s, WTF::ICU::majorVersion() >= 67 ? '*' : '+'); // Prior to ICU 67, use the symbol + instead of *.
|
|
if (style == IntlDurationFormat::UnitStyle::TwoDigit)
|
|
skeletonBuilder.append("00"_s);
|
|
else
|
|
diff --git a/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp b/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp
|
|
index 67708f1d8d33..0938d2d5b4a5 100644
|
|
--- a/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp
|
|
+++ b/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp
|
|
@@ -517,10 +517,14 @@ void IntlNumberFormat::initializeNumberFormat(JSGlobalObject* globalObject, JSVa
|
|
skeletonBuilder.append(" sign-except-zero"_s);
|
|
break;
|
|
case SignDisplay::Negative:
|
|
- if (useAccounting)
|
|
- skeletonBuilder.append(" sign-accounting-negative"_s);
|
|
- else
|
|
- skeletonBuilder.append(" sign-negative"_s);
|
|
+ // Only ICU69~ supports negative sign display. Ignore this option if linked ICU does not support it.
|
|
+ // https://github.com/unicode-org/icu/commit/1aa0dad8e06ecc99bff442dd37f6daa2d39d9a5a
|
|
+ if (WTF::ICU::majorVersion() >= 69) {
|
|
+ if (useAccounting)
|
|
+ skeletonBuilder.append(" sign-accounting-negative"_s);
|
|
+ else
|
|
+ skeletonBuilder.append(" sign-negative"_s);
|
|
+ }
|
|
break;
|
|
}
|
|
|
|
diff --git a/Source/JavaScriptCore/runtime/IntlNumberFormatInlines.h b/Source/JavaScriptCore/runtime/IntlNumberFormatInlines.h
|
|
index ddccce2fd112..980da4e3c74a 100644
|
|
--- a/Source/JavaScriptCore/runtime/IntlNumberFormatInlines.h
|
|
+++ b/Source/JavaScriptCore/runtime/IntlNumberFormatInlines.h
|
|
@@ -199,12 +199,24 @@ void appendNumberFormatDigitOptionsToSkeleton(IntlType* intlInstance, StringBuil
|
|
case RoundingMode::Trunc:
|
|
skeletonBuilder.append(" rounding-mode-down"_s);
|
|
break;
|
|
- case RoundingMode::HalfCeil:
|
|
- skeletonBuilder.append(" rounding-mode-half-ceiling"_s);
|
|
+ case RoundingMode::HalfCeil: {
|
|
+ // Only ICU69~ supports half-ceiling. Ignore this option if linked ICU does not support it.
|
|
+ // https://github.com/unicode-org/icu/commit/e8dfea9bb6bb27596731173b352759e44ad06b21
|
|
+ if (WTF::ICU::majorVersion() >= 69)
|
|
+ skeletonBuilder.append(" rounding-mode-half-ceiling"_s);
|
|
+ else
|
|
+ skeletonBuilder.append(" rounding-mode-half-up"_s); // Default option.
|
|
break;
|
|
- case RoundingMode::HalfFloor:
|
|
- skeletonBuilder.append(" rounding-mode-half-floor"_s);
|
|
+ }
|
|
+ case RoundingMode::HalfFloor: {
|
|
+ // Only ICU69~ supports half-flooring. Ignore this option if linked ICU does not support it.
|
|
+ // https://github.com/unicode-org/icu/commit/e8dfea9bb6bb27596731173b352759e44ad06b21
|
|
+ if (WTF::ICU::majorVersion() >= 69)
|
|
+ skeletonBuilder.append(" rounding-mode-half-floor"_s);
|
|
+ else
|
|
+ skeletonBuilder.append(" rounding-mode-half-up"_s); // Default option.
|
|
break;
|
|
+ }
|
|
case RoundingMode::HalfExpand:
|
|
skeletonBuilder.append(" rounding-mode-half-up"_s);
|
|
break;
|
|
@@ -217,7 +229,7 @@ void appendNumberFormatDigitOptionsToSkeleton(IntlType* intlInstance, StringBuil
|
|
}
|
|
|
|
// https://github.com/unicode-org/icu/blob/master/docs/userguide/format_parse/numbers/skeletons.md#integer-width
|
|
- skeletonBuilder.append(" integer-width/*"_s);
|
|
+ skeletonBuilder.append(" integer-width/"_s, WTF::ICU::majorVersion() >= 67 ? '*' : '+'); // Prior to ICU 67, use the symbol + instead of *.
|
|
for (unsigned i = 0; i < intlInstance->m_minimumIntegerDigits; ++i)
|
|
skeletonBuilder.append('0');
|
|
|
|
@@ -255,19 +267,23 @@ void appendNumberFormatDigitOptionsToSkeleton(IntlType* intlInstance, StringBuil
|
|
}
|
|
case IntlRoundingType::MorePrecision:
|
|
case IntlRoundingType::LessPrecision:
|
|
- // https://github.com/unicode-org/icu/commit/d7db6c1f8655bb53153695b09a50029fd04a8364
|
|
- // https://github.com/unicode-org/icu/blob/main/docs/userguide/format_parse/numbers/skeletons.md#precision
|
|
- skeletonBuilder.append(" ."_s);
|
|
- for (unsigned i = 0; i < intlInstance->m_minimumFractionDigits; ++i)
|
|
- skeletonBuilder.append('0');
|
|
- for (unsigned i = 0; i < intlInstance->m_maximumFractionDigits - intlInstance->m_minimumFractionDigits; ++i)
|
|
- skeletonBuilder.append('#');
|
|
- skeletonBuilder.append('/');
|
|
- for (unsigned i = 0; i < intlInstance->m_minimumSignificantDigits; ++i)
|
|
- skeletonBuilder.append('@');
|
|
- for (unsigned i = 0; i < intlInstance->m_maximumSignificantDigits - intlInstance->m_minimumSignificantDigits; ++i)
|
|
- skeletonBuilder.append('#');
|
|
- skeletonBuilder.append(intlInstance->m_roundingType == IntlRoundingType::MorePrecision ? 'r' : 's');
|
|
+ // Before Intl.NumberFormat v3, it was CompactRounding mode, where we do not configure anything.
|
|
+ // So, if linked ICU is ~68, we do nothing.
|
|
+ if (WTF::ICU::majorVersion() >= 69) {
|
|
+ // https://github.com/unicode-org/icu/commit/d7db6c1f8655bb53153695b09a50029fd04a8364
|
|
+ // https://github.com/unicode-org/icu/blob/main/docs/userguide/format_parse/numbers/skeletons.md#precision
|
|
+ skeletonBuilder.append(" ."_s);
|
|
+ for (unsigned i = 0; i < intlInstance->m_minimumFractionDigits; ++i)
|
|
+ skeletonBuilder.append('0');
|
|
+ for (unsigned i = 0; i < intlInstance->m_maximumFractionDigits - intlInstance->m_minimumFractionDigits; ++i)
|
|
+ skeletonBuilder.append('#');
|
|
+ skeletonBuilder.append('/');
|
|
+ for (unsigned i = 0; i < intlInstance->m_minimumSignificantDigits; ++i)
|
|
+ skeletonBuilder.append('@');
|
|
+ for (unsigned i = 0; i < intlInstance->m_maximumSignificantDigits - intlInstance->m_minimumSignificantDigits; ++i)
|
|
+ skeletonBuilder.append('#');
|
|
+ skeletonBuilder.append(intlInstance->m_roundingType == IntlRoundingType::MorePrecision ? 'r' : 's');
|
|
+ }
|
|
break;
|
|
}
|
|
}
|
|
@@ -278,7 +294,10 @@ void appendNumberFormatDigitOptionsToSkeleton(IntlType* intlInstance, StringBuil
|
|
case IntlTrailingZeroDisplay::Auto:
|
|
break;
|
|
case IntlTrailingZeroDisplay::StripIfInteger:
|
|
- skeletonBuilder.append("/w"_s);
|
|
+ // Only ICU69~ supports trailing zero display. Ignore this option if linked ICU does not support it.
|
|
+ // https://github.com/unicode-org/icu/commit/b79c299f90d4023ac237db3d0335d568bf21cd36
|
|
+ if (WTF::ICU::majorVersion() >= 69)
|
|
+ skeletonBuilder.append("/w"_s);
|
|
break;
|
|
}
|
|
}
|
|
--
|
|
2.49.0
|
|
|
|
|
|
From 459dffe47b82147919f9ea8e8d4f374389e11ccd Mon Sep 17 00:00:00 2001
|
|
From: Michael Catanzaro <mcatanzaro@redhat.com>
|
|
Date: Fri, 28 Mar 2025 15:01:00 -0500
|
|
Subject: [PATCH 3/4] Revert "[JSC] TimeZone Cache should be per-process level"
|
|
|
|
This reverts commit c779aa30eced87609c7c808d672a8f23c5c4821d.
|
|
---
|
|
Source/JavaScriptCore/runtime/JSDateMath.cpp | 59 +++++++-------------
|
|
1 file changed, 20 insertions(+), 39 deletions(-)
|
|
|
|
diff --git a/Source/JavaScriptCore/runtime/JSDateMath.cpp b/Source/JavaScriptCore/runtime/JSDateMath.cpp
|
|
index c6a194568dab..756cbccb1668 100644
|
|
--- a/Source/JavaScriptCore/runtime/JSDateMath.cpp
|
|
+++ b/Source/JavaScriptCore/runtime/JSDateMath.cpp
|
|
@@ -453,12 +453,9 @@ String DateCache::timeZoneDisplayName(bool isDST)
|
|
return m_timeZoneStandardDisplayNameCache;
|
|
}
|
|
|
|
-static Lock timeZoneCacheLock;
|
|
-
|
|
#if PLATFORM(COCOA)
|
|
static void timeZoneChangeNotification(CFNotificationCenterRef, void*, CFStringRef, const void*, CFDictionaryRef)
|
|
{
|
|
- Locker locker { timeZoneCacheLock };
|
|
ASSERT(isMainThread());
|
|
++lastTimeZoneID;
|
|
}
|
|
@@ -475,40 +472,6 @@ DateCache::DateCache()
|
|
#endif
|
|
}
|
|
|
|
-static std::tuple<String, Vector<UChar, 32>> retrieveTimeZoneInformation()
|
|
-{
|
|
- Locker locker { timeZoneCacheLock };
|
|
- static NeverDestroyed<std::tuple<String, Vector<UChar, 32>, uint64_t>> globalCache;
|
|
-
|
|
- bool isCacheStale = true;
|
|
- uint64_t currentID = 0;
|
|
-#if PLATFORM(COCOA)
|
|
- currentID = lastTimeZoneID.load();
|
|
- isCacheStale = std::get<2>(globalCache.get()) != currentID;
|
|
-#endif
|
|
- if (isCacheStale) {
|
|
- Vector<UChar, 32> timeZoneID;
|
|
- getTimeZoneOverride(timeZoneID);
|
|
- String canonical;
|
|
- UErrorCode status = U_ZERO_ERROR;
|
|
- if (timeZoneID.isEmpty()) {
|
|
- status = callBufferProducingFunction(ucal_getHostTimeZone, timeZoneID);
|
|
- ASSERT_UNUSED(status, U_SUCCESS(status));
|
|
- }
|
|
- if (U_SUCCESS(status)) {
|
|
- Vector<UChar, 32> canonicalBuffer;
|
|
- auto status = callBufferProducingFunction(ucal_getCanonicalTimeZoneID, timeZoneID.data(), timeZoneID.size(), canonicalBuffer, nullptr);
|
|
- if (U_SUCCESS(status))
|
|
- canonical = String(canonicalBuffer);
|
|
- }
|
|
- if (canonical.isNull() || isUTCEquivalent(canonical))
|
|
- canonical = "UTC"_s;
|
|
-
|
|
- globalCache.get() = std::tuple { canonical.isolatedCopy(), WTFMove(timeZoneID), currentID };
|
|
- }
|
|
- return std::tuple { std::get<0>(globalCache.get()).isolatedCopy(), std::get<1>(globalCache.get()) };
|
|
-}
|
|
-
|
|
DateCache::~DateCache() = default;
|
|
|
|
Ref<DateInstanceData> DateCache::cachedDateInstanceData(double millisecondsFromEpoch)
|
|
@@ -519,10 +482,28 @@ Ref<DateInstanceData> DateCache::cachedDateInstanceData(double millisecondsFromE
|
|
void DateCache::timeZoneCacheSlow()
|
|
{
|
|
ASSERT(!m_timeZoneCache);
|
|
- auto [canonical, timeZoneID] = retrieveTimeZoneInformation();
|
|
+
|
|
+ Vector<UChar, 32> timeZoneID;
|
|
+ getTimeZoneOverride(timeZoneID);
|
|
auto* cache = new OpaqueICUTimeZone;
|
|
- cache->m_canonicalTimeZoneID = WTFMove(canonical);
|
|
+
|
|
+ String canonical;
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
+ if (timeZoneID.isEmpty()) {
|
|
+ status = callBufferProducingFunction(ucal_getHostTimeZone, timeZoneID);
|
|
+ ASSERT_UNUSED(status, U_SUCCESS(status));
|
|
+ }
|
|
+ if (U_SUCCESS(status)) {
|
|
+ Vector<UChar, 32> canonicalBuffer;
|
|
+ auto status = callBufferProducingFunction(ucal_getCanonicalTimeZoneID, timeZoneID.data(), timeZoneID.size(), canonicalBuffer, nullptr);
|
|
+ if (U_SUCCESS(status))
|
|
+ canonical = String(canonicalBuffer);
|
|
+ }
|
|
+ if (canonical.isNull() || isUTCEquivalent(canonical))
|
|
+ canonical = "UTC"_s;
|
|
+ cache->m_canonicalTimeZoneID = WTFMove(canonical);
|
|
+
|
|
+ status = U_ZERO_ERROR;
|
|
cache->m_calendar = std::unique_ptr<UCalendar, ICUDeleter<ucal_close>>(ucal_open(timeZoneID.data(), timeZoneID.size(), "", UCAL_DEFAULT, &status));
|
|
ASSERT_UNUSED(status, U_SUCCESS(status));
|
|
ucal_setGregorianChange(cache->m_calendar.get(), minECMAScriptTime, &status); // Ignore "unsupported" error.
|
|
--
|
|
2.49.0
|
|
|
|
|
|
From af2f8c534482ad7e540ee5da473baff97f05d355 Mon Sep 17 00:00:00 2001
|
|
From: Michael Catanzaro <mcatanzaro@redhat.com>
|
|
Date: Fri, 28 Mar 2025 15:01:11 -0500
|
|
Subject: [PATCH 4/4] Revert "[JSC] Rebaseline Intl implementation based on
|
|
lowest dependency ICU 70"
|
|
|
|
This reverts commit 31a358087be7e5e70c7a03bdfcf89de35628a2a2.
|
|
---
|
|
.../runtime/IntlDateTimeFormat.cpp | 27 ++++
|
|
.../runtime/IntlDateTimeFormat.h | 6 +
|
|
.../runtime/IntlDateTimeFormatPrototype.cpp | 6 +-
|
|
.../runtime/IntlDurationFormat.cpp | 27 ++++
|
|
.../runtime/IntlDurationFormat.h | 2 +
|
|
.../JavaScriptCore/runtime/IntlListFormat.cpp | 24 +++
|
|
.../JavaScriptCore/runtime/IntlListFormat.h | 6 +
|
|
.../runtime/IntlNumberFormat.cpp | 150 ++++++++++++++++++
|
|
.../JavaScriptCore/runtime/IntlNumberFormat.h | 35 ++++
|
|
.../runtime/IntlNumberFormatPrototype.cpp | 35 +++-
|
|
Source/JavaScriptCore/runtime/IntlObject.cpp | 9 +-
|
|
.../runtime/IntlPluralRules.cpp | 41 +++++
|
|
.../JavaScriptCore/runtime/IntlPluralRules.h | 12 +-
|
|
.../runtime/IntlPluralRulesPrototype.cpp | 8 +-
|
|
.../JavaScriptCore/runtime/IntlWorkaround.cpp | 12 +-
|
|
Source/JavaScriptCore/runtime/JSDateMath.cpp | 94 ++++++++++-
|
|
16 files changed, 478 insertions(+), 16 deletions(-)
|
|
|
|
diff --git a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp b/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp
|
|
index e3e7671fcf45..2f2371649667 100644
|
|
--- a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp
|
|
+++ b/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp
|
|
@@ -42,12 +42,16 @@
|
|
#include <wtf/unicode/CharacterNames.h>
|
|
#include <wtf/unicode/icu/ICUHelpers.h>
|
|
|
|
+#if HAVE(ICU_U_DATE_INTERVAL_FORMAT_FORMAT_RANGE_TO_PARTS)
|
|
#include <unicode/uformattedvalue.h>
|
|
#ifdef U_HIDE_DRAFT_API
|
|
#undef U_HIDE_DRAFT_API
|
|
#endif
|
|
+#endif // HAVE(ICU_U_DATE_INTERVAL_FORMAT_FORMAT_RANGE_TO_PARTS)
|
|
#include <unicode/udateintervalformat.h>
|
|
+#if HAVE(ICU_U_DATE_INTERVAL_FORMAT_FORMAT_RANGE_TO_PARTS)
|
|
#define U_HIDE_DRAFT_API 1
|
|
+#endif // HAVE(ICU_U_DATE_INTERVAL_FORMAT_FORMAT_RANGE_TO_PARTS)
|
|
|
|
WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN
|
|
|
|
@@ -1446,6 +1450,8 @@ UDateIntervalFormat* IntlDateTimeFormat::createDateIntervalFormatIfNecessary(JSG
|
|
return m_dateIntervalFormat.get();
|
|
}
|
|
|
|
+#if HAVE(ICU_U_DATE_INTERVAL_FORMAT_FORMAT_RANGE_TO_PARTS)
|
|
+
|
|
static std::unique_ptr<UFormattedDateInterval, ICUDeleter<udtitvfmt_closeResult>> formattedValueFromDateRange(UDateIntervalFormat& dateIntervalFormat, UDateFormat& dateFormat, double startDate, double endDate, UErrorCode& status)
|
|
{
|
|
auto result = std::unique_ptr<UFormattedDateInterval, ICUDeleter<udtitvfmt_closeResult>>(udtitvfmt_openResult(&status));
|
|
@@ -1524,6 +1530,8 @@ static bool dateFieldsPracticallyEqual(const UFormattedValue* formattedValue, UE
|
|
return !hasSpan;
|
|
}
|
|
|
|
+#endif // HAVE(ICU_U_DATE_INTERVAL_FORMAT_FORMAT_RANGE_TO_PARTS)
|
|
+
|
|
JSValue IntlDateTimeFormat::formatRange(JSGlobalObject* globalObject, double startDate, double endDate)
|
|
{
|
|
ASSERT(m_dateFormat);
|
|
@@ -1542,6 +1550,7 @@ JSValue IntlDateTimeFormat::formatRange(JSGlobalObject* globalObject, double sta
|
|
auto* dateIntervalFormat = createDateIntervalFormatIfNecessary(globalObject);
|
|
RETURN_IF_EXCEPTION(scope, { });
|
|
|
|
+#if HAVE(ICU_U_DATE_INTERVAL_FORMAT_FORMAT_RANGE_TO_PARTS)
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
auto result = formattedValueFromDateRange(*dateIntervalFormat, *m_dateFormat, startDate, endDate, status);
|
|
if (U_FAILURE(status)) {
|
|
@@ -1579,6 +1588,17 @@ JSValue IntlDateTimeFormat::formatRange(JSGlobalObject* globalObject, double sta
|
|
replaceNarrowNoBreakSpaceOrThinSpaceWithNormalSpace(buffer);
|
|
|
|
return jsString(vm, String(WTFMove(buffer)));
|
|
+#else
|
|
+ Vector<UChar, 32> buffer;
|
|
+ auto status = callBufferProducingFunction(udtitvfmt_format, dateIntervalFormat, startDate, endDate, buffer, nullptr);
|
|
+ if (U_FAILURE(status)) {
|
|
+ throwTypeError(globalObject, scope, "Failed to format date interval"_s);
|
|
+ return { };
|
|
+ }
|
|
+ replaceNarrowNoBreakSpaceOrThinSpaceWithNormalSpace(buffer);
|
|
+
|
|
+ return jsString(vm, String(WTFMove(buffer)));
|
|
+#endif
|
|
}
|
|
|
|
JSValue IntlDateTimeFormat::formatRangeToParts(JSGlobalObject* globalObject, double startDate, double endDate)
|
|
@@ -1588,6 +1608,7 @@ JSValue IntlDateTimeFormat::formatRangeToParts(JSGlobalObject* globalObject, dou
|
|
VM& vm = globalObject->vm();
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
|
|
+#if HAVE(ICU_U_DATE_INTERVAL_FORMAT_FORMAT_RANGE_TO_PARTS)
|
|
// http://tc39.es/proposal-intl-DateTimeFormat-formatRange/#sec-partitiondatetimerangepattern
|
|
startDate = timeClip(startDate);
|
|
endDate = timeClip(endDate);
|
|
@@ -1791,6 +1812,12 @@ JSValue IntlDateTimeFormat::formatRangeToParts(JSGlobalObject* globalObject, dou
|
|
}
|
|
|
|
return parts;
|
|
+#else
|
|
+ UNUSED_PARAM(startDate);
|
|
+ UNUSED_PARAM(endDate);
|
|
+ throwTypeError(globalObject, scope, "Failed to format date interval"_s);
|
|
+ return { };
|
|
+#endif
|
|
}
|
|
|
|
|
|
diff --git a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.h b/Source/JavaScriptCore/runtime/IntlDateTimeFormat.h
|
|
index 121417aab9e1..14c476c72f69 100644
|
|
--- a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.h
|
|
+++ b/Source/JavaScriptCore/runtime/IntlDateTimeFormat.h
|
|
@@ -32,6 +32,12 @@
|
|
|
|
struct UDateIntervalFormat;
|
|
|
|
+#if !defined(HAVE_ICU_U_DATE_INTERVAL_FORMAT_FORMAT_RANGE_TO_PARTS)
|
|
+#if U_ICU_VERSION_MAJOR_NUM >= 64
|
|
+#define HAVE_ICU_U_DATE_INTERVAL_FORMAT_FORMAT_RANGE_TO_PARTS 1
|
|
+#endif
|
|
+#endif
|
|
+
|
|
namespace JSC {
|
|
|
|
enum class RelevantExtensionKey : uint8_t;
|
|
diff --git a/Source/JavaScriptCore/runtime/IntlDateTimeFormatPrototype.cpp b/Source/JavaScriptCore/runtime/IntlDateTimeFormatPrototype.cpp
|
|
index b7ef4bab865f..694ab7afea0c 100644
|
|
--- a/Source/JavaScriptCore/runtime/IntlDateTimeFormatPrototype.cpp
|
|
+++ b/Source/JavaScriptCore/runtime/IntlDateTimeFormatPrototype.cpp
|
|
@@ -56,7 +56,6 @@ const ClassInfo IntlDateTimeFormatPrototype::s_info = { "Intl.DateTimeFormat"_s,
|
|
@begin dateTimeFormatPrototypeTable
|
|
format intlDateTimeFormatPrototypeGetterFormat DontEnum|ReadOnly|CustomAccessor
|
|
formatRange intlDateTimeFormatPrototypeFuncFormatRange DontEnum|Function 2
|
|
- formatRangeToParts intlDateTimeFormatPrototypeFuncFormatRangeToParts DontEnum|Function 2
|
|
formatToParts intlDateTimeFormatPrototypeFuncFormatToParts DontEnum|Function 1
|
|
resolvedOptions intlDateTimeFormatPrototypeFuncResolvedOptions DontEnum|Function 0
|
|
@end
|
|
@@ -83,7 +82,12 @@ void IntlDateTimeFormatPrototype::finishCreation(VM& vm, JSGlobalObject* globalO
|
|
{
|
|
Base::finishCreation(vm);
|
|
ASSERT(inherits(info()));
|
|
+#if HAVE(ICU_U_DATE_INTERVAL_FORMAT_FORMAT_RANGE_TO_PARTS)
|
|
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("formatRangeToParts"_s, intlDateTimeFormatPrototypeFuncFormatRangeToParts, static_cast<unsigned>(PropertyAttribute::DontEnum), 2, ImplementationVisibility::Public);
|
|
+#else
|
|
UNUSED_PARAM(globalObject);
|
|
+ UNUSED_PARAM(&intlDateTimeFormatPrototypeFuncFormatRangeToParts);
|
|
+#endif
|
|
JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
|
|
}
|
|
|
|
diff --git a/Source/JavaScriptCore/runtime/IntlDurationFormat.cpp b/Source/JavaScriptCore/runtime/IntlDurationFormat.cpp
|
|
index a1c628082dd5..78e9106ee0a4 100644
|
|
--- a/Source/JavaScriptCore/runtime/IntlDurationFormat.cpp
|
|
+++ b/Source/JavaScriptCore/runtime/IntlDurationFormat.cpp
|
|
@@ -36,14 +36,21 @@
|
|
// While UListFormatter APIs are draft in ICU 67, they are stable in ICU 68 with the same function signatures.
|
|
// So we can assume that these signatures of draft APIs are stable.
|
|
// If UListFormatter is available, UNumberFormatter is also available.
|
|
+#if HAVE(ICU_U_LIST_FORMATTER)
|
|
#ifdef U_HIDE_DRAFT_API
|
|
#undef U_HIDE_DRAFT_API
|
|
#endif
|
|
+#endif
|
|
#include <unicode/ulistformatter.h>
|
|
#include <unicode/unumberformatter.h>
|
|
#include <unicode/ures.h>
|
|
+#if HAVE(ICU_U_LIST_FORMATTER)
|
|
#define U_HIDE_DRAFT_API 1
|
|
+#endif
|
|
+
|
|
+#if HAVE(ICU_U_LIST_FORMATTER)
|
|
#include <unicode/uformattedvalue.h>
|
|
+#endif
|
|
|
|
WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN
|
|
|
|
@@ -240,6 +247,7 @@ void IntlDurationFormat::initializeDurationFormat(JSGlobalObject* globalObject,
|
|
m_fractionalDigits = intlNumberOption(globalObject, options, vm.propertyNames->fractionalDigits, 0, 9, fractionalDigitsUndefinedValue);
|
|
RETURN_IF_EXCEPTION(scope, void());
|
|
|
|
+#if HAVE(ICU_U_LIST_FORMATTER)
|
|
{
|
|
auto toUListFormatterWidth = [](Style style) {
|
|
// 6. Let listStyle be durationFormat.[[Style]].
|
|
@@ -266,8 +274,15 @@ void IntlDurationFormat::initializeDurationFormat(JSGlobalObject* globalObject,
|
|
return;
|
|
}
|
|
}
|
|
+#else
|
|
+ UNUSED_PARAM(IntlDurationFormatInternal::verbose);
|
|
+ throwTypeError(globalObject, scope, "Failed to initialize Intl.DurationFormat since this feature is not supported in the linked ICU version"_s);
|
|
+ return;
|
|
+#endif
|
|
}
|
|
|
|
+#if HAVE(ICU_U_LIST_FORMATTER)
|
|
+
|
|
static String retrieveSeparator(const CString& locale, const String& numberingSystem)
|
|
{
|
|
ASCIILiteral fallbackTimeSeparator = ":"_s;
|
|
@@ -635,12 +650,15 @@ static Vector<Element> collectElements(JSGlobalObject* globalObject, const IntlD
|
|
return elements;
|
|
}
|
|
|
|
+#endif
|
|
+
|
|
// https://tc39.es/proposal-intl-duration-format/#sec-Intl.DurationFormat.prototype.format
|
|
JSValue IntlDurationFormat::format(JSGlobalObject* globalObject, ISO8601::Duration duration) const
|
|
{
|
|
VM& vm = globalObject->vm();
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
|
|
+#if HAVE(ICU_U_LIST_FORMATTER)
|
|
auto elements = collectElements(globalObject, this, WTFMove(duration));
|
|
RETURN_IF_EXCEPTION(scope, { });
|
|
|
|
@@ -676,6 +694,10 @@ JSValue IntlDurationFormat::format(JSGlobalObject* globalObject, ISO8601::Durati
|
|
return throwTypeError(globalObject, scope, "failed to format list of strings"_s);
|
|
|
|
return jsString(vm, String(WTFMove(result)));
|
|
+#else
|
|
+ UNUSED_PARAM(duration);
|
|
+ return throwTypeError(globalObject, scope, "failed to format list of strings"_s);
|
|
+#endif
|
|
}
|
|
|
|
// https://tc39.es/proposal-intl-duration-format/#sec-Intl.DurationFormat.prototype.formatToParts
|
|
@@ -684,6 +706,7 @@ JSValue IntlDurationFormat::formatToParts(JSGlobalObject* globalObject, ISO8601:
|
|
VM& vm = globalObject->vm();
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
|
|
+#if HAVE(ICU_U_LIST_FORMATTER)
|
|
auto elements = collectElements(globalObject, this, WTFMove(duration));
|
|
RETURN_IF_EXCEPTION(scope, { });
|
|
|
|
@@ -836,6 +859,10 @@ JSValue IntlDurationFormat::formatToParts(JSGlobalObject* globalObject, ISO8601:
|
|
}
|
|
|
|
return parts;
|
|
+#else
|
|
+ UNUSED_PARAM(duration);
|
|
+ return throwTypeError(globalObject, scope, "failed to format list of strings"_s);
|
|
+#endif
|
|
}
|
|
|
|
// https://tc39.es/proposal-intl-duration-format/#sec-Intl.DurationFormat.prototype.resolvedOptions
|
|
diff --git a/Source/JavaScriptCore/runtime/IntlDurationFormat.h b/Source/JavaScriptCore/runtime/IntlDurationFormat.h
|
|
index 69e64f9c8332..b3f781a54ad4 100644
|
|
--- a/Source/JavaScriptCore/runtime/IntlDurationFormat.h
|
|
+++ b/Source/JavaScriptCore/runtime/IntlDurationFormat.h
|
|
@@ -101,7 +101,9 @@ private:
|
|
static ASCIILiteral unitStyleString(UnitStyle);
|
|
static ASCIILiteral displayString(Display);
|
|
|
|
+#if HAVE(ICU_U_LIST_FORMATTER)
|
|
std::unique_ptr<UListFormatter, UListFormatterDeleter> m_listFormat;
|
|
+#endif
|
|
String m_locale;
|
|
String m_numberingSystem;
|
|
CString m_dataLocaleWithExtensions;
|
|
diff --git a/Source/JavaScriptCore/runtime/IntlListFormat.cpp b/Source/JavaScriptCore/runtime/IntlListFormat.cpp
|
|
index 8fb342027af5..c25cc5f9e90f 100644
|
|
--- a/Source/JavaScriptCore/runtime/IntlListFormat.cpp
|
|
+++ b/Source/JavaScriptCore/runtime/IntlListFormat.cpp
|
|
@@ -33,12 +33,19 @@
|
|
|
|
// While UListFormatter APIs are draft in ICU 67, they are stable in ICU 68 with the same function signatures.
|
|
// So we can assume that these signatures of draft APIs are stable.
|
|
+#if HAVE(ICU_U_LIST_FORMATTER)
|
|
#ifdef U_HIDE_DRAFT_API
|
|
#undef U_HIDE_DRAFT_API
|
|
#endif
|
|
+#endif
|
|
#include <unicode/ulistformatter.h>
|
|
+#if HAVE(ICU_U_LIST_FORMATTER)
|
|
#define U_HIDE_DRAFT_API 1
|
|
+#endif
|
|
+
|
|
+#if HAVE(ICU_U_LIST_FORMATTER)
|
|
#include <unicode/uformattedvalue.h>
|
|
+#endif
|
|
|
|
WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN
|
|
|
|
@@ -107,6 +114,7 @@ void IntlListFormat::initializeListFormat(JSGlobalObject* globalObject, JSValue
|
|
m_style = intlOption<Style>(globalObject, options, vm.propertyNames->style, { { "long"_s, Style::Long }, { "short"_s, Style::Short }, { "narrow"_s, Style::Narrow } }, "style must be either \"long\", \"short\", or \"narrow\""_s, Style::Long);
|
|
RETURN_IF_EXCEPTION(scope, void());
|
|
|
|
+#if HAVE(ICU_U_LIST_FORMATTER)
|
|
auto toUListFormatterType = [](Type type) {
|
|
switch (type) {
|
|
case Type::Conjunction:
|
|
@@ -137,8 +145,13 @@ void IntlListFormat::initializeListFormat(JSGlobalObject* globalObject, JSValue
|
|
throwTypeError(globalObject, scope, "failed to initialize ListFormat"_s);
|
|
return;
|
|
}
|
|
+#else
|
|
+ throwTypeError(globalObject, scope, "Failed to initialize Intl.ListFormat since this feature is not supported in the linked ICU version"_s);
|
|
+ return;
|
|
+#endif
|
|
}
|
|
|
|
+#if HAVE(ICU_U_LIST_FORMATTER)
|
|
static Vector<String, 4> stringListFromIterable(JSGlobalObject* globalObject, JSValue iterable)
|
|
{
|
|
Vector<String, 4> result;
|
|
@@ -158,6 +171,7 @@ static Vector<String, 4> stringListFromIterable(JSGlobalObject* globalObject, JS
|
|
});
|
|
return result;
|
|
}
|
|
+#endif
|
|
|
|
// https://tc39.es/proposal-intl-list-format/#sec-Intl.ListFormat.prototype.format
|
|
JSValue IntlListFormat::format(JSGlobalObject* globalObject, JSValue list) const
|
|
@@ -165,6 +179,7 @@ JSValue IntlListFormat::format(JSGlobalObject* globalObject, JSValue list) const
|
|
VM& vm = globalObject->vm();
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
|
|
+#if HAVE(ICU_U_LIST_FORMATTER)
|
|
auto stringList = stringListFromIterable(globalObject, list);
|
|
RETURN_IF_EXCEPTION(scope, { });
|
|
|
|
@@ -176,6 +191,10 @@ JSValue IntlListFormat::format(JSGlobalObject* globalObject, JSValue list) const
|
|
return throwTypeError(globalObject, scope, "failed to format list of strings"_s);
|
|
|
|
return jsString(vm, String(WTFMove(result)));
|
|
+#else
|
|
+ UNUSED_PARAM(list);
|
|
+ return throwTypeError(globalObject, scope, "failed to format list of strings"_s);
|
|
+#endif
|
|
}
|
|
|
|
// https://tc39.es/proposal-intl-list-format/#sec-Intl.ListFormat.prototype.formatToParts
|
|
@@ -184,6 +203,7 @@ JSValue IntlListFormat::formatToParts(JSGlobalObject* globalObject, JSValue list
|
|
VM& vm = globalObject->vm();
|
|
auto scope = DECLARE_THROW_SCOPE(vm);
|
|
|
|
+#if HAVE(ICU_U_LIST_FORMATTER)
|
|
auto stringList = stringListFromIterable(globalObject, list);
|
|
RETURN_IF_EXCEPTION(scope, { });
|
|
|
|
@@ -269,6 +289,10 @@ JSValue IntlListFormat::formatToParts(JSGlobalObject* globalObject, JSValue list
|
|
}
|
|
|
|
return parts;
|
|
+#else
|
|
+ UNUSED_PARAM(list);
|
|
+ return throwTypeError(globalObject, scope, "failed to format list of strings"_s);
|
|
+#endif
|
|
}
|
|
|
|
// https://tc39.es/proposal-intl-list-format/#sec-Intl.ListFormat.prototype.resolvedOptions
|
|
diff --git a/Source/JavaScriptCore/runtime/IntlListFormat.h b/Source/JavaScriptCore/runtime/IntlListFormat.h
|
|
index 2d071949e06f..af6f2c2e7b0a 100644
|
|
--- a/Source/JavaScriptCore/runtime/IntlListFormat.h
|
|
+++ b/Source/JavaScriptCore/runtime/IntlListFormat.h
|
|
@@ -28,6 +28,12 @@
|
|
#include "JSObject.h"
|
|
#include <wtf/unicode/icu/ICUHelpers.h>
|
|
|
|
+#if !defined(HAVE_ICU_U_LIST_FORMATTER)
|
|
+#if U_ICU_VERSION_MAJOR_NUM >= 67 || (U_ICU_VERSION_MAJOR_NUM >= 66 && USE(APPLE_INTERNAL_SDK))
|
|
+#define HAVE_ICU_U_LIST_FORMATTER 1
|
|
+#endif
|
|
+#endif
|
|
+
|
|
struct UListFormatter;
|
|
|
|
namespace JSC {
|
|
diff --git a/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp b/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp
|
|
index 0938d2d5b4a5..1f0aa041c201 100644
|
|
--- a/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp
|
|
+++ b/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp
|
|
@@ -43,8 +43,12 @@
|
|
#ifdef U_HIDE_DRAFT_API
|
|
#undef U_HIDE_DRAFT_API
|
|
#endif
|
|
+#if HAVE(ICU_U_NUMBER_FORMATTER)
|
|
#include <unicode/unumberformatter.h>
|
|
+#endif
|
|
+#if HAVE(ICU_U_NUMBER_RANGE_FORMATTER)
|
|
#include <unicode/unumberrangeformatter.h>
|
|
+#endif
|
|
#define U_HIDE_DRAFT_API 1
|
|
|
|
WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN
|
|
@@ -57,17 +61,21 @@ namespace IntlNumberFormatInternal {
|
|
static constexpr bool verbose = false;
|
|
}
|
|
|
|
+#if HAVE(ICU_U_NUMBER_FORMATTER)
|
|
void UNumberFormatterDeleter::operator()(UNumberFormatter* formatter)
|
|
{
|
|
if (formatter)
|
|
unumf_close(formatter);
|
|
}
|
|
+#endif
|
|
|
|
+#if HAVE(ICU_U_NUMBER_RANGE_FORMATTER)
|
|
void UNumberRangeFormatterDeleter::operator()(UNumberRangeFormatter* formatter)
|
|
{
|
|
if (formatter)
|
|
unumrf_close(formatter);
|
|
}
|
|
+#endif
|
|
|
|
IntlNumberFormat* IntlNumberFormat::create(VM& vm, Structure* structure)
|
|
{
|
|
@@ -226,10 +234,12 @@ static std::optional<WellFormedUnit> wellFormedUnitIdentifier(StringView unitIde
|
|
return WellFormedUnit(numeratorUnit.value(), denominatorUnit.value());
|
|
}
|
|
|
|
+#if HAVE(ICU_U_NUMBER_FORMATTER)
|
|
// We intentionally avoid using ICU's UNUM_APPROXIMATELY_SIGN_FIELD and define the same value here.
|
|
// UNUM_APPROXIMATELY_SIGN_FIELD can be defined in the header after ICU 71. But dylib ICU can be newer while ICU header version is old.
|
|
// We can define UNUM_APPROXIMATELY_SIGN_FIELD here so that we can support old ICU header + newer ICU library combination.
|
|
static constexpr UNumberFormatFields UNUM_APPROXIMATELY_SIGN_FIELD = static_cast<UNumberFormatFields>(UNUM_COMPACT_FIELD + 1);
|
|
+#endif
|
|
|
|
static ASCIILiteral partTypeString(UNumberFormatFields field, IntlNumberFormat::Style style, bool sign, IntlMathematicalValue::NumberType type)
|
|
{
|
|
@@ -265,6 +275,7 @@ static ASCIILiteral partTypeString(UNumberFormatFields field, IntlNumberFormat::
|
|
return (style == IntlNumberFormat::Style::Unit) ? "unit"_s : "percentSign"_s;
|
|
case UNUM_SIGN_FIELD:
|
|
return sign ? "minusSign"_s : "plusSign"_s;
|
|
+#if HAVE(ICU_U_NUMBER_FORMATTER)
|
|
case UNUM_MEASURE_UNIT_FIELD:
|
|
return "unit"_s;
|
|
case UNUM_COMPACT_FIELD:
|
|
@@ -273,6 +284,7 @@ IGNORE_GCC_WARNINGS_BEGIN("switch")
|
|
case UNUM_APPROXIMATELY_SIGN_FIELD:
|
|
return "approximatelySign"_s;
|
|
IGNORE_GCC_WARNINGS_END
|
|
+#endif
|
|
// These should not show up because there is no way to specify them in NumberFormat options.
|
|
// If they do, they don't fit well into any of known part types, so consider it an "unknown".
|
|
case UNUM_PERMILL_FIELD:
|
|
@@ -399,6 +411,7 @@ void IntlNumberFormat::initializeNumberFormat(JSGlobalObject* globalObject, JSVa
|
|
|
|
// Options are obtained. Configure formatter here.
|
|
|
|
+#if HAVE(ICU_U_NUMBER_FORMATTER)
|
|
// Constructing ICU Number Skeletons to configure UNumberFormatter.
|
|
// https://github.com/unicode-org/icu/blob/master/docs/userguide/format_parse/numbers/skeletons.md
|
|
|
|
@@ -557,11 +570,120 @@ void IntlNumberFormat::initializeNumberFormat(JSGlobalObject* globalObject, JSVa
|
|
return;
|
|
}
|
|
|
|
+#if HAVE(ICU_U_NUMBER_RANGE_FORMATTER)
|
|
m_numberRangeFormatter = std::unique_ptr<UNumberRangeFormatter, UNumberRangeFormatterDeleter>(unumrf_openForSkeletonWithCollapseAndIdentityFallback(upconverted.get(), skeletonView.length(), UNUM_RANGE_COLLAPSE_AUTO, UNUM_IDENTITY_FALLBACK_APPROXIMATELY, dataLocaleWithExtensions.data(), nullptr, &status));
|
|
if (U_FAILURE(status)) {
|
|
throwTypeError(globalObject, scope, "failed to initialize NumberFormat"_s);
|
|
return;
|
|
}
|
|
+#endif
|
|
+#else
|
|
+ UNumberFormatStyle style = UNUM_DEFAULT;
|
|
+ switch (m_style) {
|
|
+ case Style::Decimal:
|
|
+ style = UNUM_DECIMAL;
|
|
+ break;
|
|
+ case Style::Percent:
|
|
+ style = UNUM_PERCENT;
|
|
+ break;
|
|
+ case Style::Currency:
|
|
+ switch (m_currencyDisplay) {
|
|
+ case CurrencyDisplay::Code:
|
|
+ style = UNUM_CURRENCY_ISO;
|
|
+ break;
|
|
+ case CurrencyDisplay::Symbol:
|
|
+ style = UNUM_CURRENCY;
|
|
+ break;
|
|
+ case CurrencyDisplay::NarrowSymbol:
|
|
+ style = UNUM_CURRENCY; // Use the same option to "symbol" since linked-ICU does not support it.
|
|
+ break;
|
|
+ case CurrencyDisplay::Name:
|
|
+ style = UNUM_CURRENCY_PLURAL;
|
|
+ break;
|
|
+ }
|
|
+ switch (m_currencySign) {
|
|
+ case CurrencySign::Standard:
|
|
+ break;
|
|
+ case CurrencySign::Accounting:
|
|
+ // Ignore this case since linked ICU does not support it.
|
|
+ break;
|
|
+ }
|
|
+ break;
|
|
+ case Style::Unit:
|
|
+ // Ignore this case since linked ICU does not support it.
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ switch (m_notation) {
|
|
+ case IntlNotation::Standard:
|
|
+ break;
|
|
+ case IntlNotation::Scientific:
|
|
+ case IntlNotation::Engineering:
|
|
+ case IntlNotation::Compact:
|
|
+ // Ignore this case since linked ICU does not support it.
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ switch (m_signDisplay) {
|
|
+ case SignDisplay::Auto:
|
|
+ break;
|
|
+ case SignDisplay::Never:
|
|
+ case SignDisplay::Always:
|
|
+ case SignDisplay::ExceptZero:
|
|
+ case SignDisplay::Negative:
|
|
+ // Ignore this case since linked ICU does not support it.
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ UErrorCode status = U_ZERO_ERROR;
|
|
+ m_numberFormat = std::unique_ptr<UNumberFormat, ICUDeleter<unum_close>>(unum_open(style, nullptr, 0, dataLocaleWithExtensions.data(), nullptr, &status));
|
|
+ if (U_FAILURE(status)) {
|
|
+ throwTypeError(globalObject, scope, "failed to initialize NumberFormat"_s);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (m_style == Style::Currency) {
|
|
+ unum_setTextAttribute(m_numberFormat.get(), UNUM_CURRENCY_CODE, StringView(m_currency).upconvertedCharacters(), m_currency.length(), &status);
|
|
+ if (U_FAILURE(status)) {
|
|
+ throwTypeError(globalObject, scope, "failed to initialize NumberFormat"_s);
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ 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;
|
|
+ case IntlRoundingType::MorePrecision:
|
|
+ // Ignore this case since linked ICU does not support it.
|
|
+ break;
|
|
+ case IntlRoundingType::LessPrecision:
|
|
+ // Ignore this case since linked ICU does not support it.
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ switch (m_useGrouping) {
|
|
+ case UseGrouping::False:
|
|
+ unum_setAttribute(m_numberFormat.get(), UNUM_GROUPING_USED, false);
|
|
+ break;
|
|
+ case UseGrouping::Min2:
|
|
+ // Ignore this case since linked ICU does not support it.
|
|
+ break;
|
|
+ case UseGrouping::Auto:
|
|
+ break;
|
|
+ case UseGrouping::Always:
|
|
+ unum_setAttribute(m_numberFormat.get(), UNUM_GROUPING_USED, true);
|
|
+ break;
|
|
+ }
|
|
+ unum_setAttribute(m_numberFormat.get(), UNUM_ROUNDING_MODE, UNUM_ROUND_HALFUP);
|
|
+#endif
|
|
}
|
|
|
|
// https://tc39.es/ecma402/#sec-formatnumber
|
|
@@ -573,6 +695,7 @@ JSValue IntlNumberFormat::format(JSGlobalObject* globalObject, double value) con
|
|
value = purifyNaN(value);
|
|
|
|
Vector<UChar, 32> buffer;
|
|
+#if HAVE(ICU_U_NUMBER_FORMATTER)
|
|
ASSERT(m_numberFormatter);
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
auto formattedNumber = std::unique_ptr<UFormattedNumber, ICUDeleter<unumf_closeResult>>(unumf_openResult(&status));
|
|
@@ -584,6 +707,12 @@ JSValue IntlNumberFormat::format(JSGlobalObject* globalObject, double value) con
|
|
status = callBufferProducingFunction(unumf_resultToString, formattedNumber.get(), buffer);
|
|
if (U_FAILURE(status))
|
|
return throwTypeError(globalObject, scope, "Failed to format a number."_s);
|
|
+#else
|
|
+ ASSERT(m_numberFormat);
|
|
+ auto status = callBufferProducingFunction(unum_formatDouble, m_numberFormat.get(), value, buffer, nullptr);
|
|
+ if (U_FAILURE(status))
|
|
+ return throwTypeError(globalObject, scope, "Failed to format a number."_s);
|
|
+#endif
|
|
return jsString(vm, String(WTFMove(buffer)));
|
|
}
|
|
|
|
@@ -597,6 +726,7 @@ JSValue IntlNumberFormat::format(JSGlobalObject* globalObject, IntlMathematicalV
|
|
const auto& string = value.getString();
|
|
|
|
Vector<UChar, 32> buffer;
|
|
+#if HAVE(ICU_U_NUMBER_FORMATTER)
|
|
ASSERT(m_numberFormatter);
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
auto formattedNumber = std::unique_ptr<UFormattedNumber, ICUDeleter<unumf_closeResult>>(unumf_openResult(&status));
|
|
@@ -608,9 +738,16 @@ JSValue IntlNumberFormat::format(JSGlobalObject* globalObject, IntlMathematicalV
|
|
status = callBufferProducingFunction(unumf_resultToString, formattedNumber.get(), buffer);
|
|
if (U_FAILURE(status))
|
|
return throwTypeError(globalObject, scope, "Failed to format a BigInt."_s);
|
|
+#else
|
|
+ ASSERT(m_numberFormat);
|
|
+ auto status = callBufferProducingFunction(unum_formatDecimal, m_numberFormat.get(), string.data(), string.length(), buffer, nullptr);
|
|
+ if (U_FAILURE(status))
|
|
+ return throwTypeError(globalObject, scope, "Failed to format a BigInt."_s);
|
|
+#endif
|
|
return jsString(vm, String(WTFMove(buffer)));
|
|
}
|
|
|
|
+#if HAVE(ICU_U_NUMBER_RANGE_FORMATTER)
|
|
JSValue IntlNumberFormat::formatRange(JSGlobalObject* globalObject, double start, double end) const
|
|
{
|
|
VM& vm = globalObject->vm();
|
|
@@ -678,6 +815,7 @@ JSValue IntlNumberFormat::formatRange(JSGlobalObject* globalObject, IntlMathemat
|
|
|
|
return jsString(vm, String({ string, static_cast<size_t>(length) }));
|
|
}
|
|
+#endif
|
|
|
|
static constexpr int32_t literalField = -1;
|
|
struct IntlNumberFormatField {
|
|
@@ -790,6 +928,7 @@ static Vector<IntlNumberFormatField> flattenFields(Vector<IntlNumberFormatField>
|
|
return flatten;
|
|
}
|
|
|
|
+#if HAVE(ICU_U_NUMBER_RANGE_FORMATTER_FORMAT_RANGE_TO_PARTS)
|
|
static bool numberFieldsPracticallyEqual(const UFormattedValue* formattedValue, UErrorCode& status)
|
|
{
|
|
auto iterator = std::unique_ptr<UConstrainedFieldPosition, ICUDeleter<ucfpos_close>>(ucfpos_open(&status));
|
|
@@ -1031,6 +1170,7 @@ JSValue IntlNumberFormat::formatRangeToParts(JSGlobalObject* globalObject, IntlM
|
|
|
|
return parts;
|
|
}
|
|
+#endif
|
|
|
|
ASCIILiteral IntlNumberFormat::styleString(Style style)
|
|
{
|
|
@@ -1328,6 +1468,7 @@ JSValue IntlNumberFormat::formatToParts(JSGlobalObject* globalObject, double val
|
|
return throwTypeError(globalObject, scope, "failed to open field position iterator"_s);
|
|
|
|
Vector<UChar, 32> result;
|
|
+#if HAVE(ICU_U_NUMBER_FORMATTER)
|
|
ASSERT(m_numberFormatter);
|
|
auto formattedNumber = std::unique_ptr<UFormattedNumber, ICUDeleter<unumf_closeResult>>(unumf_openResult(&status));
|
|
if (U_FAILURE(status))
|
|
@@ -1342,6 +1483,13 @@ JSValue IntlNumberFormat::formatToParts(JSGlobalObject* globalObject, double val
|
|
if (U_FAILURE(status))
|
|
return throwTypeError(globalObject, scope, "Failed to format a number."_s);
|
|
IntlFieldIterator iterator(*fieldItr.get());
|
|
+#else
|
|
+ ASSERT(m_numberFormat);
|
|
+ status = callBufferProducingFunction(unum_formatDoubleForFields, m_numberFormat.get(), value, result, fieldItr.get());
|
|
+ if (U_FAILURE(status))
|
|
+ return throwTypeError(globalObject, scope, "failed to format a number."_s);
|
|
+ IntlFieldIterator iterator(*fieldItr.get());
|
|
+#endif
|
|
|
|
auto resultString = String(WTFMove(result));
|
|
|
|
@@ -1355,6 +1503,7 @@ JSValue IntlNumberFormat::formatToParts(JSGlobalObject* globalObject, double val
|
|
return parts;
|
|
}
|
|
|
|
+#if HAVE(ICU_U_NUMBER_FORMATTER)
|
|
JSValue IntlNumberFormat::formatToParts(JSGlobalObject* globalObject, IntlMathematicalValue&& value, JSString* sourceType) const
|
|
{
|
|
VM& vm = globalObject->vm();
|
|
@@ -1399,6 +1548,7 @@ JSValue IntlNumberFormat::formatToParts(JSGlobalObject* globalObject, IntlMathem
|
|
|
|
return parts;
|
|
}
|
|
+#endif
|
|
|
|
IntlMathematicalValue IntlMathematicalValue::parseString(JSGlobalObject* globalObject, StringView view)
|
|
{
|
|
diff --git a/Source/JavaScriptCore/runtime/IntlNumberFormat.h b/Source/JavaScriptCore/runtime/IntlNumberFormat.h
|
|
index 1bd75559a1d6..4928e5cc4d02 100644
|
|
--- a/Source/JavaScriptCore/runtime/IntlNumberFormat.h
|
|
+++ b/Source/JavaScriptCore/runtime/IntlNumberFormat.h
|
|
@@ -34,6 +34,25 @@
|
|
#include <wtf/TZoneMalloc.h>
|
|
#include <wtf/unicode/icu/ICUHelpers.h>
|
|
|
|
+#if !defined(HAVE_ICU_U_NUMBER_FORMATTER)
|
|
+// UNUM_COMPACT_FIELD and UNUM_MEASURE_UNIT_FIELD are available after ICU 64.
|
|
+#if U_ICU_VERSION_MAJOR_NUM >= 64
|
|
+#define HAVE_ICU_U_NUMBER_FORMATTER 1
|
|
+#endif
|
|
+#endif
|
|
+
|
|
+#if !defined(HAVE_ICU_U_NUMBER_RANGE_FORMATTER)
|
|
+#if U_ICU_VERSION_MAJOR_NUM >= 68
|
|
+#define HAVE_ICU_U_NUMBER_RANGE_FORMATTER 1
|
|
+#endif
|
|
+#endif
|
|
+
|
|
+#if !defined(HAVE_ICU_U_NUMBER_RANGE_FORMATTER_FORMAT_RANGE_TO_PARTS)
|
|
+#if U_ICU_VERSION_MAJOR_NUM >= 69
|
|
+#define HAVE_ICU_U_NUMBER_RANGE_FORMATTER_FORMAT_RANGE_TO_PARTS 1
|
|
+#endif
|
|
+#endif
|
|
+
|
|
struct UFormattedValue;
|
|
struct UNumberFormatter;
|
|
struct UNumberRangeFormatter;
|
|
@@ -51,13 +70,17 @@ enum class IntlNotation : uint8_t { Standard, Scientific, Engineering, Compact }
|
|
template<typename IntlType> void setNumberFormatDigitOptions(JSGlobalObject*, IntlType*, JSObject*, unsigned minimumFractionDigitsDefault, unsigned maximumFractionDigitsDefault, IntlNotation);
|
|
template<typename IntlType> void appendNumberFormatDigitOptionsToSkeleton(IntlType*, StringBuilder&);
|
|
|
|
+#if HAVE(ICU_U_NUMBER_FORMATTER)
|
|
struct UNumberFormatterDeleter {
|
|
JS_EXPORT_PRIVATE void operator()(UNumberFormatter*);
|
|
};
|
|
+#endif
|
|
|
|
+#if HAVE(ICU_U_NUMBER_RANGE_FORMATTER)
|
|
struct UNumberRangeFormatterDeleter {
|
|
JS_EXPORT_PRIVATE void operator()(UNumberRangeFormatter*);
|
|
};
|
|
+#endif
|
|
|
|
class IntlMathematicalValue {
|
|
WTF_MAKE_TZONE_ALLOCATED(IntlMathematicalValue);
|
|
@@ -159,14 +182,20 @@ public:
|
|
JSValue format(JSGlobalObject*, double) const;
|
|
JSValue format(JSGlobalObject*, IntlMathematicalValue&&) const;
|
|
JSValue formatToParts(JSGlobalObject*, double, JSString* sourceType = nullptr) const;
|
|
+#if HAVE(ICU_U_NUMBER_FORMATTER)
|
|
JSValue formatToParts(JSGlobalObject*, IntlMathematicalValue&&, JSString* sourceType = nullptr) const;
|
|
+#endif
|
|
JSObject* resolvedOptions(JSGlobalObject*) const;
|
|
|
|
+#if HAVE(ICU_U_NUMBER_RANGE_FORMATTER)
|
|
JSValue formatRange(JSGlobalObject*, double, double) const;
|
|
JSValue formatRange(JSGlobalObject*, IntlMathematicalValue&&, IntlMathematicalValue&&) const;
|
|
+#endif
|
|
|
|
+#if HAVE(ICU_U_NUMBER_RANGE_FORMATTER_FORMAT_RANGE_TO_PARTS)
|
|
JSValue formatRangeToParts(JSGlobalObject*, double, double) const;
|
|
JSValue formatRangeToParts(JSGlobalObject*, IntlMathematicalValue&&, IntlMathematicalValue&&) const;
|
|
+#endif
|
|
|
|
JSBoundFunction* boundFormat() const { return m_boundFormat.get(); }
|
|
void setBoundFormat(VM&, JSBoundFunction*);
|
|
@@ -212,8 +241,14 @@ private:
|
|
static JSValue useGroupingValue(VM&, UseGrouping);
|
|
|
|
WriteBarrier<JSBoundFunction> m_boundFormat;
|
|
+#if HAVE(ICU_U_NUMBER_FORMATTER)
|
|
std::unique_ptr<UNumberFormatter, UNumberFormatterDeleter> m_numberFormatter;
|
|
+#if HAVE(ICU_U_NUMBER_RANGE_FORMATTER)
|
|
std::unique_ptr<UNumberRangeFormatter, UNumberRangeFormatterDeleter> m_numberRangeFormatter;
|
|
+#endif
|
|
+#else
|
|
+ std::unique_ptr<UNumberFormat, ICUDeleter<unum_close>> m_numberFormat;
|
|
+#endif
|
|
|
|
String m_locale;
|
|
String m_numberingSystem;
|
|
diff --git a/Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.cpp b/Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.cpp
|
|
index 6459273641c6..026b4269652e 100644
|
|
--- a/Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.cpp
|
|
+++ b/Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.cpp
|
|
@@ -35,12 +35,18 @@
|
|
namespace JSC {
|
|
|
|
static JSC_DECLARE_CUSTOM_GETTER(intlNumberFormatPrototypeGetterFormat);
|
|
-static JSC_DECLARE_HOST_FUNCTION(intlNumberFormatPrototypeFuncFormatRange);
|
|
-static JSC_DECLARE_HOST_FUNCTION(intlNumberFormatPrototypeFuncFormatRangeToParts);
|
|
static JSC_DECLARE_HOST_FUNCTION(intlNumberFormatPrototypeFuncFormatToParts);
|
|
static JSC_DECLARE_HOST_FUNCTION(intlNumberFormatPrototypeFuncResolvedOptions);
|
|
static JSC_DECLARE_HOST_FUNCTION(intlNumberFormatFuncFormat);
|
|
|
|
+#if HAVE(ICU_U_NUMBER_RANGE_FORMATTER)
|
|
+static JSC_DECLARE_HOST_FUNCTION(intlNumberFormatPrototypeFuncFormatRange);
|
|
+#endif
|
|
+
|
|
+#if HAVE(ICU_U_NUMBER_RANGE_FORMATTER_FORMAT_RANGE_TO_PARTS)
|
|
+static JSC_DECLARE_HOST_FUNCTION(intlNumberFormatPrototypeFuncFormatRangeToParts);
|
|
+#endif
|
|
+
|
|
}
|
|
|
|
#include "IntlNumberFormatPrototype.lut.h"
|
|
@@ -51,11 +57,9 @@ const ClassInfo IntlNumberFormatPrototype::s_info = { "Intl.NumberFormat"_s, &Ba
|
|
|
|
/* Source for IntlNumberFormatPrototype.lut.h
|
|
@begin numberFormatPrototypeTable
|
|
- format intlNumberFormatPrototypeGetterFormat DontEnum|ReadOnly|CustomAccessor
|
|
- formatRange intlNumberFormatPrototypeFuncFormatRange DontEnum|Function 2
|
|
- formatRangeToParts intlNumberFormatPrototypeFuncFormatRangeToParts DontEnum|Function 2
|
|
- formatToParts intlNumberFormatPrototypeFuncFormatToParts DontEnum|Function 1
|
|
- resolvedOptions intlNumberFormatPrototypeFuncResolvedOptions DontEnum|Function 0
|
|
+ format intlNumberFormatPrototypeGetterFormat DontEnum|ReadOnly|CustomAccessor
|
|
+ formatToParts intlNumberFormatPrototypeFuncFormatToParts DontEnum|Function 1
|
|
+ resolvedOptions intlNumberFormatPrototypeFuncResolvedOptions DontEnum|Function 0
|
|
@end
|
|
*/
|
|
|
|
@@ -82,6 +86,12 @@ void IntlNumberFormatPrototype::finishCreation(VM& vm, JSGlobalObject* globalObj
|
|
ASSERT(inherits(info()));
|
|
JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
|
|
UNUSED_PARAM(globalObject);
|
|
+#if HAVE(ICU_U_NUMBER_RANGE_FORMATTER)
|
|
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("formatRange"_s, intlNumberFormatPrototypeFuncFormatRange, static_cast<unsigned>(PropertyAttribute::DontEnum), 2, ImplementationVisibility::Public);
|
|
+#endif
|
|
+#if HAVE(ICU_U_NUMBER_RANGE_FORMATTER_FORMAT_RANGE_TO_PARTS)
|
|
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("formatRangeToParts"_s, intlNumberFormatPrototypeFuncFormatRangeToParts, static_cast<unsigned>(PropertyAttribute::DontEnum), 2, ImplementationVisibility::Public);
|
|
+#endif
|
|
}
|
|
|
|
// https://tc39.es/ecma402/#sec-number-format-functions
|
|
@@ -134,6 +144,7 @@ JSC_DEFINE_CUSTOM_GETTER(intlNumberFormatPrototypeGetterFormat, (JSGlobalObject*
|
|
return JSValue::encode(boundFormat);
|
|
}
|
|
|
|
+#if HAVE(ICU_U_NUMBER_RANGE_FORMATTER)
|
|
JSC_DEFINE_HOST_FUNCTION(intlNumberFormatPrototypeFuncFormatRange, (JSGlobalObject* globalObject, CallFrame* callFrame))
|
|
{
|
|
VM& vm = globalObject->vm();
|
|
@@ -163,6 +174,7 @@ JSC_DEFINE_HOST_FUNCTION(intlNumberFormatPrototypeFuncFormatRange, (JSGlobalObje
|
|
|
|
RELEASE_AND_RETURN(scope, JSValue::encode(numberFormat->formatRange(globalObject, WTFMove(start), WTFMove(end))));
|
|
}
|
|
+#endif
|
|
|
|
JSC_DEFINE_HOST_FUNCTION(intlNumberFormatPrototypeFuncFormatToParts, (JSGlobalObject* globalObject, CallFrame* callFrame))
|
|
{
|
|
@@ -177,6 +189,7 @@ JSC_DEFINE_HOST_FUNCTION(intlNumberFormatPrototypeFuncFormatToParts, (JSGlobalOb
|
|
if (UNLIKELY(!numberFormat))
|
|
return JSValue::encode(throwTypeError(globalObject, scope, "Intl.NumberFormat.prototype.formatToParts called on value that's not a NumberFormat"_s));
|
|
|
|
+#if HAVE(ICU_U_NUMBER_FORMATTER)
|
|
auto value = toIntlMathematicalValue(globalObject, callFrame->argument(0));
|
|
RETURN_IF_EXCEPTION(scope, { });
|
|
|
|
@@ -184,8 +197,15 @@ JSC_DEFINE_HOST_FUNCTION(intlNumberFormatPrototypeFuncFormatToParts, (JSGlobalOb
|
|
RELEASE_AND_RETURN(scope, JSValue::encode(numberFormat->formatToParts(globalObject, number.value())));
|
|
|
|
RELEASE_AND_RETURN(scope, JSValue::encode(numberFormat->formatToParts(globalObject, WTFMove(value))));
|
|
+#else
|
|
+ double value = callFrame->argument(0).toNumber(globalObject);
|
|
+ RETURN_IF_EXCEPTION(scope, { });
|
|
+
|
|
+ RELEASE_AND_RETURN(scope, JSValue::encode(numberFormat->formatToParts(globalObject, value)));
|
|
+#endif
|
|
}
|
|
|
|
+#if HAVE(ICU_U_NUMBER_RANGE_FORMATTER_FORMAT_RANGE_TO_PARTS)
|
|
JSC_DEFINE_HOST_FUNCTION(intlNumberFormatPrototypeFuncFormatRangeToParts, (JSGlobalObject* globalObject, CallFrame* callFrame))
|
|
{
|
|
VM& vm = globalObject->vm();
|
|
@@ -215,6 +235,7 @@ JSC_DEFINE_HOST_FUNCTION(intlNumberFormatPrototypeFuncFormatRangeToParts, (JSGlo
|
|
|
|
RELEASE_AND_RETURN(scope, JSValue::encode(numberFormat->formatRangeToParts(globalObject, WTFMove(start), WTFMove(end))));
|
|
}
|
|
+#endif
|
|
|
|
JSC_DEFINE_HOST_FUNCTION(intlNumberFormatPrototypeFuncResolvedOptions, (JSGlobalObject* globalObject, CallFrame* callFrame))
|
|
{
|
|
diff --git a/Source/JavaScriptCore/runtime/IntlObject.cpp b/Source/JavaScriptCore/runtime/IntlObject.cpp
|
|
index dab995d4c294..51dbe4447db3 100644
|
|
--- a/Source/JavaScriptCore/runtime/IntlObject.cpp
|
|
+++ b/Source/JavaScriptCore/runtime/IntlObject.cpp
|
|
@@ -169,8 +169,6 @@ namespace JSC {
|
|
Collator createCollatorConstructor DontEnum|PropertyCallback
|
|
DateTimeFormat createDateTimeFormatConstructor DontEnum|PropertyCallback
|
|
DisplayNames createDisplayNamesConstructor DontEnum|PropertyCallback
|
|
- DurationFormat createDurationFormatConstructor DontEnum|PropertyCallback
|
|
- ListFormat createListFormatConstructor DontEnum|PropertyCallback
|
|
Locale createLocaleConstructor DontEnum|PropertyCallback
|
|
NumberFormat createNumberFormatConstructor DontEnum|PropertyCallback
|
|
PluralRules createPluralRulesConstructor DontEnum|PropertyCallback
|
|
@@ -258,6 +256,13 @@ void IntlObject::finishCreation(VM& vm, JSGlobalObject*)
|
|
Base::finishCreation(vm);
|
|
ASSERT(inherits(info()));
|
|
JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
|
|
+#if HAVE(ICU_U_LIST_FORMATTER)
|
|
+ putDirectWithoutTransition(vm, vm.propertyNames->DurationFormat, createDurationFormatConstructor(vm, this), static_cast<unsigned>(PropertyAttribute::DontEnum));
|
|
+ putDirectWithoutTransition(vm, vm.propertyNames->ListFormat, createListFormatConstructor(vm, this), static_cast<unsigned>(PropertyAttribute::DontEnum));
|
|
+#else
|
|
+ UNUSED_PARAM(&createDurationFormatConstructor);
|
|
+ UNUSED_PARAM(&createListFormatConstructor);
|
|
+#endif
|
|
}
|
|
|
|
Structure* IntlObject::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
|
|
diff --git a/Source/JavaScriptCore/runtime/IntlPluralRules.cpp b/Source/JavaScriptCore/runtime/IntlPluralRules.cpp
|
|
index 584c6ff2c435..af58373c78e8 100644
|
|
--- a/Source/JavaScriptCore/runtime/IntlPluralRules.cpp
|
|
+++ b/Source/JavaScriptCore/runtime/IntlPluralRules.cpp
|
|
@@ -36,8 +36,12 @@
|
|
#undef U_HIDE_DRAFT_API
|
|
#endif
|
|
#include <unicode/upluralrules.h>
|
|
+#if HAVE(ICU_U_NUMBER_FORMATTER)
|
|
#include <unicode/unumberformatter.h>
|
|
+#endif
|
|
+#if HAVE(ICU_U_NUMBER_RANGE_FORMATTER)
|
|
#include <unicode/unumberrangeformatter.h>
|
|
+#endif
|
|
#define U_HIDE_DRAFT_API 1
|
|
|
|
namespace JSC {
|
|
@@ -118,6 +122,7 @@ void IntlPluralRules::initializePluralRules(JSGlobalObject* globalObject, JSValu
|
|
auto locale = m_locale.utf8();
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
|
|
+#if HAVE(ICU_U_NUMBER_FORMATTER)
|
|
StringBuilder skeletonBuilder;
|
|
|
|
appendNumberFormatDigitOptionsToSkeleton(this, skeletonBuilder);
|
|
@@ -132,11 +137,36 @@ void IntlPluralRules::initializePluralRules(JSGlobalObject* globalObject, JSValu
|
|
return;
|
|
}
|
|
|
|
+#if HAVE(ICU_U_NUMBER_RANGE_FORMATTER)
|
|
m_numberRangeFormatter = std::unique_ptr<UNumberRangeFormatter, UNumberRangeFormatterDeleter>(unumrf_openForSkeletonWithCollapseAndIdentityFallback(upconverted.get(), skeletonView.length(), UNUM_RANGE_COLLAPSE_NONE, UNUM_IDENTITY_FALLBACK_RANGE, locale.data(), nullptr, &status));
|
|
if (U_FAILURE(status)) {
|
|
throwTypeError(globalObject, scope, "failed to initialize PluralRules"_s);
|
|
return;
|
|
}
|
|
+#endif
|
|
+#else
|
|
+ m_numberFormat = std::unique_ptr<UNumberFormat, UNumberFormatDeleter>(unum_open(UNUM_DECIMAL, nullptr, 0, locale.data(), nullptr, &status));
|
|
+ if (U_FAILURE(status)) {
|
|
+ throwTypeError(globalObject, scope, "failed to initialize PluralRules"_s);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ 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;
|
|
+ case IntlRoundingType::MorePrecision:
|
|
+ case IntlRoundingType::LessPrecision:
|
|
+ break;
|
|
+ }
|
|
+#endif
|
|
|
|
m_pluralRules = std::unique_ptr<UPluralRules, UPluralRulesDeleter>(uplrules_openForType(locale.data(), m_type == Type::Ordinal ? UPLURAL_TYPE_ORDINAL : UPLURAL_TYPE_CARDINAL, &status));
|
|
if (U_FAILURE(status)) {
|
|
@@ -230,6 +260,7 @@ JSValue IntlPluralRules::select(JSGlobalObject* globalObject, double value) cons
|
|
|
|
UErrorCode status = U_ZERO_ERROR;
|
|
|
|
+#if HAVE(ICU_U_NUMBER_FORMATTER)
|
|
auto formattedNumber = std::unique_ptr<UFormattedNumber, ICUDeleter<unumf_closeResult>>(unumf_openResult(&status));
|
|
if (U_FAILURE(status))
|
|
return throwTypeError(globalObject, scope, "failed to select plural value"_s);
|
|
@@ -241,8 +272,17 @@ JSValue IntlPluralRules::select(JSGlobalObject* globalObject, double value) cons
|
|
if (U_FAILURE(status))
|
|
return throwTypeError(globalObject, scope, "failed to select plural value"_s);
|
|
return jsString(vm, String(WTFMove(buffer)));
|
|
+#else
|
|
+ Vector<UChar, 8> result(8);
|
|
+ auto length = uplrules_selectWithFormat(m_pluralRules.get(), value, m_numberFormat.get(), result.data(), result.size(), &status);
|
|
+ if (U_FAILURE(status))
|
|
+ return throwTypeError(globalObject, scope, "failed to select plural value"_s);
|
|
+
|
|
+ return jsString(vm, String({ result.data(), static_cast<size_t>(length) }));
|
|
+#endif
|
|
}
|
|
|
|
+#if HAVE(ICU_U_NUMBER_RANGE_FORMATTER)
|
|
JSValue IntlPluralRules::selectRange(JSGlobalObject* globalObject, double start, double end) const
|
|
{
|
|
ASSERT(m_numberRangeFormatter);
|
|
@@ -268,5 +308,6 @@ JSValue IntlPluralRules::selectRange(JSGlobalObject* globalObject, double start,
|
|
return throwTypeError(globalObject, scope, "failed to select plural value"_s);
|
|
return jsString(vm, String(WTFMove(buffer)));
|
|
}
|
|
+#endif
|
|
|
|
} // namespace JSC
|
|
diff --git a/Source/JavaScriptCore/runtime/IntlPluralRules.h b/Source/JavaScriptCore/runtime/IntlPluralRules.h
|
|
index 26b7d72b16aa..7f476e03ca03 100644
|
|
--- a/Source/JavaScriptCore/runtime/IntlPluralRules.h
|
|
+++ b/Source/JavaScriptCore/runtime/IntlPluralRules.h
|
|
@@ -69,9 +69,12 @@ public:
|
|
|
|
void initializePluralRules(JSGlobalObject*, JSValue locales, JSValue options);
|
|
JSValue select(JSGlobalObject*, double value) const;
|
|
- JSValue selectRange(JSGlobalObject*, double start, double end) const;
|
|
JSObject* resolvedOptions(JSGlobalObject*) const;
|
|
|
|
+#if HAVE(ICU_U_NUMBER_RANGE_FORMATTER)
|
|
+ JSValue selectRange(JSGlobalObject*, double start, double end) const;
|
|
+#endif
|
|
+
|
|
private:
|
|
IntlPluralRules(VM&, Structure*);
|
|
DECLARE_DEFAULT_FINISH_CREATION;
|
|
@@ -82,8 +85,15 @@ private:
|
|
enum class Type : bool { Cardinal, Ordinal };
|
|
|
|
std::unique_ptr<UPluralRules, UPluralRulesDeleter> m_pluralRules;
|
|
+#if HAVE(ICU_U_NUMBER_FORMATTER)
|
|
std::unique_ptr<UNumberFormatter, UNumberFormatterDeleter> m_numberFormatter;
|
|
+#if HAVE(ICU_U_NUMBER_RANGE_FORMATTER)
|
|
std::unique_ptr<UNumberRangeFormatter, UNumberRangeFormatterDeleter> m_numberRangeFormatter;
|
|
+#endif
|
|
+#else
|
|
+ using UNumberFormatDeleter = ICUDeleter<unum_close>;
|
|
+ std::unique_ptr<UNumberFormat, UNumberFormatDeleter> m_numberFormat;
|
|
+#endif
|
|
|
|
String m_locale;
|
|
unsigned m_minimumIntegerDigits { 1 };
|
|
diff --git a/Source/JavaScriptCore/runtime/IntlPluralRulesPrototype.cpp b/Source/JavaScriptCore/runtime/IntlPluralRulesPrototype.cpp
|
|
index aae2cabe2aa7..6c908d3a7d53 100644
|
|
--- a/Source/JavaScriptCore/runtime/IntlPluralRulesPrototype.cpp
|
|
+++ b/Source/JavaScriptCore/runtime/IntlPluralRulesPrototype.cpp
|
|
@@ -33,7 +33,9 @@
|
|
namespace JSC {
|
|
|
|
static JSC_DECLARE_HOST_FUNCTION(intlPluralRulesPrototypeFuncSelect);
|
|
+#if HAVE(ICU_U_NUMBER_RANGE_FORMATTER)
|
|
static JSC_DECLARE_HOST_FUNCTION(intlPluralRulesPrototypeFuncSelectRange);
|
|
+#endif
|
|
static JSC_DECLARE_HOST_FUNCTION(intlPluralRulesPrototypeFuncResolvedOptions);
|
|
|
|
}
|
|
@@ -47,7 +49,6 @@ const ClassInfo IntlPluralRulesPrototype::s_info = { "Intl.PluralRules"_s, &Base
|
|
/* Source for IntlPluralRulesPrototype.lut.h
|
|
@begin pluralRulesPrototypeTable
|
|
select intlPluralRulesPrototypeFuncSelect DontEnum|Function 1
|
|
- selectRange intlPluralRulesPrototypeFuncSelectRange DontEnum|Function 2
|
|
resolvedOptions intlPluralRulesPrototypeFuncResolvedOptions DontEnum|Function 0
|
|
@end
|
|
*/
|
|
@@ -75,6 +76,9 @@ void IntlPluralRulesPrototype::finishCreation(VM& vm, JSGlobalObject* globalObje
|
|
ASSERT(inherits(info()));
|
|
JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
|
|
UNUSED_PARAM(globalObject);
|
|
+#if HAVE(ICU_U_NUMBER_RANGE_FORMATTER)
|
|
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->selectRange, intlPluralRulesPrototypeFuncSelectRange, static_cast<unsigned>(PropertyAttribute::DontEnum), 2, ImplementationVisibility::Public);
|
|
+#endif
|
|
}
|
|
|
|
JSC_DEFINE_HOST_FUNCTION(intlPluralRulesPrototypeFuncSelect, (JSGlobalObject* globalObject, CallFrame* callFrame))
|
|
@@ -95,6 +99,7 @@ JSC_DEFINE_HOST_FUNCTION(intlPluralRulesPrototypeFuncSelect, (JSGlobalObject* gl
|
|
RELEASE_AND_RETURN(scope, JSValue::encode(pluralRules->select(globalObject, value)));
|
|
}
|
|
|
|
+#if HAVE(ICU_U_NUMBER_RANGE_FORMATTER)
|
|
JSC_DEFINE_HOST_FUNCTION(intlPluralRulesPrototypeFuncSelectRange, (JSGlobalObject* globalObject, CallFrame* callFrame))
|
|
{
|
|
VM& vm = globalObject->vm();
|
|
@@ -119,6 +124,7 @@ JSC_DEFINE_HOST_FUNCTION(intlPluralRulesPrototypeFuncSelectRange, (JSGlobalObjec
|
|
|
|
RELEASE_AND_RETURN(scope, JSValue::encode(pluralRules->selectRange(globalObject, start, end)));
|
|
}
|
|
+#endif
|
|
|
|
JSC_DEFINE_HOST_FUNCTION(intlPluralRulesPrototypeFuncResolvedOptions, (JSGlobalObject* globalObject, CallFrame* callFrame))
|
|
{
|
|
diff --git a/Source/JavaScriptCore/runtime/IntlWorkaround.cpp b/Source/JavaScriptCore/runtime/IntlWorkaround.cpp
|
|
index c6c1fa0cd228..85d7e85469a7 100644
|
|
--- a/Source/JavaScriptCore/runtime/IntlWorkaround.cpp
|
|
+++ b/Source/JavaScriptCore/runtime/IntlWorkaround.cpp
|
|
@@ -26,17 +26,25 @@
|
|
#include "config.h"
|
|
#include "IntlWorkaround.h"
|
|
|
|
-#ifdef U_HIDE_DRAFT_API
|
|
+// ICU 69 introduces draft API ubrk_clone and deprecates ubrk_safeClone.
|
|
+#if defined(U_HIDE_DRAFT_API)
|
|
#undef U_HIDE_DRAFT_API
|
|
#endif
|
|
#include <unicode/ubrk.h>
|
|
-#define U_HIDE_DRAFT_API 1
|
|
+
|
|
+#if U_ICU_VERSION_MAJOR_NUM >= 69
|
|
+#define HAVE_ICU_UBRK_CLONE 1
|
|
+#endif
|
|
|
|
namespace JSC {
|
|
|
|
UBreakIterator* cloneUBreakIterator(const UBreakIterator* iterator, UErrorCode* status)
|
|
{
|
|
+#if HAVE(ICU_UBRK_CLONE)
|
|
return ubrk_clone(iterator, status);
|
|
+#else
|
|
+ return ubrk_safeClone(iterator, nullptr, nullptr, status);
|
|
+#endif
|
|
}
|
|
|
|
} // namespace JSC
|
|
diff --git a/Source/JavaScriptCore/runtime/JSDateMath.cpp b/Source/JavaScriptCore/runtime/JSDateMath.cpp
|
|
index 756cbccb1668..087bff354328 100644
|
|
--- a/Source/JavaScriptCore/runtime/JSDateMath.cpp
|
|
+++ b/Source/JavaScriptCore/runtime/JSDateMath.cpp
|
|
@@ -81,11 +81,24 @@
|
|
#include <wtf/unicode/CharacterNames.h>
|
|
#include <wtf/unicode/icu/ICUHelpers.h>
|
|
|
|
+#if U_ICU_VERSION_MAJOR_NUM >= 69 || (U_ICU_VERSION_MAJOR_NUM == 68 && USE(APPLE_INTERNAL_SDK))
|
|
+#define HAVE_ICU_C_TIMEZONE_API 1
|
|
#ifdef U_HIDE_DRAFT_API
|
|
#undef U_HIDE_DRAFT_API
|
|
#endif
|
|
#include <unicode/ucal.h>
|
|
-#define U_HIDE_DRAFT_API 1
|
|
+#else
|
|
+// icu::TimeZone and icu::BasicTimeZone features are only available in ICU C++ APIs.
|
|
+// We use these C++ APIs as an exception.
|
|
+#undef U_SHOW_CPLUSPLUS_API
|
|
+#define U_SHOW_CPLUSPLUS_API 1
|
|
+#include <unicode/basictz.h>
|
|
+#include <unicode/locid.h>
|
|
+#include <unicode/timezone.h>
|
|
+#include <unicode/unistr.h>
|
|
+#undef U_SHOW_CPLUSPLUS_API
|
|
+#define U_SHOW_CPLUSPLUS_API 0
|
|
+#endif
|
|
|
|
namespace JSC {
|
|
namespace JSDateMathInternal {
|
|
@@ -96,6 +109,7 @@ static constexpr bool verbose = false;
|
|
std::atomic<uint64_t> lastTimeZoneID { 1 };
|
|
#endif
|
|
|
|
+#if HAVE(ICU_C_TIMEZONE_API)
|
|
class OpaqueICUTimeZone {
|
|
WTF_MAKE_TZONE_ALLOCATED(OpaqueICUTimeZone);
|
|
public:
|
|
@@ -105,10 +119,26 @@ public:
|
|
|
|
WTF_MAKE_TZONE_ALLOCATED_IMPL(OpaqueICUTimeZone);
|
|
|
|
+#else
|
|
+static icu::TimeZone* toICUTimeZone(OpaqueICUTimeZone* timeZone)
|
|
+{
|
|
+ return std::bit_cast<icu::TimeZone*>(timeZone);
|
|
+}
|
|
+static OpaqueICUTimeZone* toOpaqueICUTimeZone(icu::TimeZone* timeZone)
|
|
+{
|
|
+ return std::bit_cast<OpaqueICUTimeZone*>(timeZone);
|
|
+}
|
|
+#endif
|
|
+
|
|
void OpaqueICUTimeZoneDeleter::operator()(OpaqueICUTimeZone* timeZone)
|
|
{
|
|
- if (timeZone)
|
|
+ if (timeZone) {
|
|
+#if HAVE(ICU_C_TIMEZONE_API)
|
|
delete timeZone;
|
|
+#else
|
|
+ delete toICUTimeZone(timeZone);
|
|
+#endif
|
|
+ }
|
|
}
|
|
|
|
// Get the combined UTC + DST offset for the time passed in.
|
|
@@ -126,6 +156,7 @@ LocalTimeOffset DateCache::calculateLocalTimeOffset(double millisecondsFromEpoch
|
|
// We can return any values in this case since later we fail when computing non timezone offset part anyway.
|
|
constexpr LocalTimeOffset failed { false, 0 };
|
|
|
|
+#if HAVE(ICU_C_TIMEZONE_API)
|
|
auto& timeZoneCache = *this->timeZoneCache();
|
|
ucal_setMillis(timeZoneCache.m_calendar.get(), millisecondsFromEpoch, &status);
|
|
if (U_FAILURE(status))
|
|
@@ -143,6 +174,21 @@ LocalTimeOffset DateCache::calculateLocalTimeOffset(double millisecondsFromEpoch
|
|
if (U_FAILURE(status))
|
|
return failed;
|
|
}
|
|
+#else
|
|
+ auto& timeZoneCache = *toICUTimeZone(this->timeZoneCache());
|
|
+ if (inputTimeType != WTF::LocalTime) {
|
|
+ constexpr bool isLocalTime = false;
|
|
+ timeZoneCache.getOffset(millisecondsFromEpoch, isLocalTime, rawOffset, dstOffset, status);
|
|
+ if (U_FAILURE(status))
|
|
+ return failed;
|
|
+ } else {
|
|
+ // icu::TimeZone is a timezone instance which inherits icu::BasicTimeZone.
|
|
+ // https://unicode-org.atlassian.net/browse/ICU-13705 will move getOffsetFromLocal to icu::TimeZone.
|
|
+ static_cast<const icu::BasicTimeZone&>(timeZoneCache).getOffsetFromLocal(millisecondsFromEpoch, icu::BasicTimeZone::kFormer, icu::BasicTimeZone::kFormer, rawOffset, dstOffset, status);
|
|
+ if (U_FAILURE(status))
|
|
+ return failed;
|
|
+ }
|
|
+#endif
|
|
|
|
return { !!dstOffset, rawOffset + dstOffset };
|
|
}
|
|
@@ -427,12 +473,32 @@ double DateCache::parseDate(JSGlobalObject* globalObject, VM& vm, const String&
|
|
// https://tc39.es/ecma402/#sec-defaulttimezone
|
|
String DateCache::defaultTimeZone()
|
|
{
|
|
+#if HAVE(ICU_C_TIMEZONE_API)
|
|
return timeZoneCache()->m_canonicalTimeZoneID;
|
|
+#else
|
|
+ icu::UnicodeString timeZoneID;
|
|
+ icu::UnicodeString canonicalTimeZoneID;
|
|
+ auto& timeZone = *toICUTimeZone(timeZoneCache());
|
|
+ timeZone.getID(timeZoneID);
|
|
+
|
|
+ UErrorCode status = U_ZERO_ERROR;
|
|
+ UBool isSystem = false;
|
|
+ icu::TimeZone::getCanonicalID(timeZoneID, canonicalTimeZoneID, isSystem, status);
|
|
+ if (U_FAILURE(status))
|
|
+ return "UTC"_s;
|
|
+
|
|
+ String canonical = String({ canonicalTimeZoneID.getBuffer(), static_cast<size_t>(canonicalTimeZoneID.length()) });
|
|
+ if (isUTCEquivalent(canonical))
|
|
+ return "UTC"_s;
|
|
+
|
|
+ return canonical;
|
|
+#endif
|
|
}
|
|
|
|
String DateCache::timeZoneDisplayName(bool isDST)
|
|
{
|
|
if (m_timeZoneStandardDisplayNameCache.isNull()) {
|
|
+#if HAVE(ICU_C_TIMEZONE_API)
|
|
auto& timeZoneCache = *this->timeZoneCache();
|
|
CString language = defaultLanguage().utf8();
|
|
{
|
|
@@ -447,6 +513,21 @@ String DateCache::timeZoneDisplayName(bool isDST)
|
|
if (U_SUCCESS(status))
|
|
m_timeZoneDSTDisplayNameCache = String::adopt(WTFMove(dstDisplayNameBuffer));
|
|
}
|
|
+#else
|
|
+ auto& timeZoneCache = *toICUTimeZone(this->timeZoneCache());
|
|
+ String language = defaultLanguage();
|
|
+ icu::Locale locale(language.utf8().data());
|
|
+ {
|
|
+ icu::UnicodeString standardDisplayName;
|
|
+ timeZoneCache.getDisplayName(false /* inDaylight */, icu::TimeZone::LONG, locale, standardDisplayName);
|
|
+ m_timeZoneStandardDisplayNameCache = String({ standardDisplayName.getBuffer(), static_cast<size_t>(standardDisplayName.length()) });
|
|
+ }
|
|
+ {
|
|
+ icu::UnicodeString dstDisplayName;
|
|
+ timeZoneCache.getDisplayName(true /* inDaylight */, icu::TimeZone::LONG, locale, dstDisplayName);
|
|
+ m_timeZoneDSTDisplayNameCache = String({ dstDisplayName.getBuffer(), static_cast<size_t>(dstDisplayName.length()) });
|
|
+ }
|
|
+#endif
|
|
}
|
|
if (isDST)
|
|
return m_timeZoneDSTDisplayNameCache;
|
|
@@ -485,6 +566,7 @@ void DateCache::timeZoneCacheSlow()
|
|
|
|
Vector<UChar, 32> timeZoneID;
|
|
getTimeZoneOverride(timeZoneID);
|
|
+#if HAVE(ICU_C_TIMEZONE_API)
|
|
auto* cache = new OpaqueICUTimeZone;
|
|
|
|
String canonical;
|
|
@@ -508,6 +590,14 @@ void DateCache::timeZoneCacheSlow()
|
|
ASSERT_UNUSED(status, U_SUCCESS(status));
|
|
ucal_setGregorianChange(cache->m_calendar.get(), minECMAScriptTime, &status); // Ignore "unsupported" error.
|
|
m_timeZoneCache = std::unique_ptr<OpaqueICUTimeZone, OpaqueICUTimeZoneDeleter>(cache);
|
|
+#else
|
|
+ if (!timeZoneID.isEmpty()) {
|
|
+ m_timeZoneCache = std::unique_ptr<OpaqueICUTimeZone, OpaqueICUTimeZoneDeleter>(toOpaqueICUTimeZone(icu::TimeZone::createTimeZone(icu::UnicodeString(timeZoneID.data(), timeZoneID.size()))));
|
|
+ return;
|
|
+ }
|
|
+ // Do not use icu::TimeZone::createDefault. ICU internally has a cache for timezone and createDefault returns this cached value.
|
|
+ m_timeZoneCache = std::unique_ptr<OpaqueICUTimeZone, OpaqueICUTimeZoneDeleter>(toOpaqueICUTimeZone(icu::TimeZone::detectHostTimeZone()));
|
|
+#endif
|
|
}
|
|
|
|
void DateCache::resetIfNecessarySlow()
|
|
--
|
|
2.49.0
|
|
|
|
diff --git a/Source/JavaScriptCore/runtime/JSDateMath.cpp b/Source/JavaScriptCore/runtime/JSDateMath.cpp
|
|
index 087bff354328..997cfae0f8e6 100644
|
|
--- a/Source/JavaScriptCore/runtime/JSDateMath.cpp
|
|
+++ b/Source/JavaScriptCore/runtime/JSDateMath.cpp
|
|
@@ -74,6 +74,7 @@
|
|
|
|
#include "ExceptionHelpers.h"
|
|
#include "VM.h"
|
|
+#include <bit>
|
|
#include <limits>
|
|
#include <wtf/DateMath.h>
|
|
#include <wtf/Language.h>
|