From ebc0c4a088acbc523bda3b935b8c59a6568ae318 Mon Sep 17 00:00:00 2001 From: Michael Catanzaro 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 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 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 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> retrieveTimeZoneInformation() -{ - Locker locker { timeZoneCacheLock }; - static NeverDestroyed, 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 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 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 DateCache::cachedDateInstanceData(double millisecondsFromEpoch) @@ -519,10 +482,28 @@ Ref DateCache::cachedDateInstanceData(double millisecondsFromE void DateCache::timeZoneCacheSlow() { ASSERT(!m_timeZoneCache); - auto [canonical, timeZoneID] = retrieveTimeZoneInformation(); + + Vector 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 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>(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 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 #include +#if HAVE(ICU_U_DATE_INTERVAL_FORMAT_FORMAT_RANGE_TO_PARTS) #include #ifdef U_HIDE_DRAFT_API #undef U_HIDE_DRAFT_API #endif +#endif // HAVE(ICU_U_DATE_INTERVAL_FORMAT_FORMAT_RANGE_TO_PARTS) #include +#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> formattedValueFromDateRange(UDateIntervalFormat& dateIntervalFormat, UDateFormat& dateFormat, double startDate, double endDate, UErrorCode& status) { auto result = std::unique_ptr>(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 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(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 #include #include +#if HAVE(ICU_U_LIST_FORMATTER) #define U_HIDE_DRAFT_API 1 +#endif + +#if HAVE(ICU_U_LIST_FORMATTER) #include +#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 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 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 +#if HAVE(ICU_U_LIST_FORMATTER) #define U_HIDE_DRAFT_API 1 +#endif + +#if HAVE(ICU_U_LIST_FORMATTER) #include +#endif WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN @@ -107,6 +114,7 @@ void IntlListFormat::initializeListFormat(JSGlobalObject* globalObject, JSValue m_style = intlOption