diff --git a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp b/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp index 45de3dc7b3d37..7fc777f2e39f9 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 @@ -1443,6 +1447,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)); @@ -1521,6 +1527,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); @@ -1539,6 +1547,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)) { @@ -1576,6 +1585,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) @@ -1585,6 +1605,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); @@ -1788,6 +1809,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 1eabb3a5a8031..b5f4f5d505b52 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 b7ef4bab865fd..694ab7afea0c0 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 7f601df93cfc4..fb9032e769158 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; @@ -624,12 +639,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, { }); @@ -665,6 +683,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 @@ -673,6 +695,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, { }); @@ -825,6 +848,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 f9db4b2eb2e44..7c7f7e127954b 100644 --- a/Source/JavaScriptCore/runtime/IntlDurationFormat.h +++ b/Source/JavaScriptCore/runtime/IntlDurationFormat.h @@ -101,7 +101,9 @@ class IntlDurationFormat final : public JSNonFinalObject { 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 8fb342027af54..c25cc5f9e90fa 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