File webkit2gtk3-icu65.patch of Package webkit2gtk3.38256
diff -urp webkitgtk-2.47.90.orig/Source/cmake/OptionsGTK.cmake webkitgtk-2.47.90/Source/cmake/OptionsGTK.cmake
--- webkitgtk-2.47.90.orig/Source/cmake/OptionsGTK.cmake 2025-03-11 17:29:57.246208919 -0500
+++ webkitgtk-2.47.90/Source/cmake/OptionsGTK.cmake 2025-03-11 17:47:23.053252957 -0500
@@ -10,11 +10,11 @@ set(USER_AGENT_BRANDING "" CACHE 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 2.6.4 REQUIRED COMPONENTS ICU)
+find_package(ICU 65.1 REQUIRED COMPONENTS data i18n uc)
find_package(JPEG REQUIRED)
find_package(Epoxy 1.4.0 REQUIRED)
-find_package(LibXml2 2.9.13 REQUIRED)
+find_package(LibXml2 2.9.7 REQUIRED)
find_package(PNG REQUIRED)
find_package(SQLite3 REQUIRED)
find_package(Threads REQUIRED)
diff -urp webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp
--- webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp 2025-02-25 02:25:37.787305000 -0600
+++ webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp 2025-03-11 17:31:15.879583146 -0500
@@ -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:
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(c
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(
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(
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::formatRangeT
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::formatRangeT
}
return parts;
+#else
+ UNUSED_PARAM(startDate);
+ UNUSED_PARAM(endDate);
+ throwTypeError(globalObject, scope, "Failed to format date interval"_s);
+ return { };
+#endif
}
diff -urp webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlDateTimeFormat.h webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlDateTimeFormat.h
--- webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlDateTimeFormat.h 2025-02-25 02:25:37.787305000 -0600
+++ webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlDateTimeFormat.h 2025-03-11 17:31:15.880099793 -0500
@@ -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 -urp webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlDateTimeFormatPrototype.cpp webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlDateTimeFormatPrototype.cpp
--- webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlDateTimeFormatPrototype.cpp 2025-02-25 02:25:37.787305000 -0600
+++ webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlDateTimeFormatPrototype.cpp 2025-03-11 17:31:15.880282900 -0500
@@ -56,7 +56,6 @@ const ClassInfo IntlDateTimeFormatProtot
@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::finish
{
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 -urp webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlDurationFormat.cpp webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlDurationFormat.cpp
--- webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlDurationFormat.cpp 2025-02-25 02:25:37.787305000 -0600
+++ webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlDurationFormat.cpp 2025-03-11 17:31:15.880554644 -0500
@@ -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::initializeDurat
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::initializeDurat
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(J
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(JSGlo
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::formatToPart
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::formatToPart
}
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 -urp webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlDurationFormat.h webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlDurationFormat.h
--- webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlDurationFormat.h 2025-02-25 02:25:37.787305000 -0600
+++ webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlDurationFormat.h 2025-03-11 17:31:15.880830756 -0500
@@ -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 -urp webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlListFormat.cpp webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlListFormat.cpp
--- webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlListFormat.cpp 2025-02-25 02:25:37.791305000 -0600
+++ webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlListFormat.cpp 2025-03-11 17:31:15.880976512 -0500
@@ -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::initializeListForma
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::initializeListForma
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> stringListFromI
});
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(JSGlobalO
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(JSGlobalO
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(JS
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(JS
}
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 -urp webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlListFormat.h webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlListFormat.h
--- webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlListFormat.h 2025-02-25 02:25:37.791305000 -0600
+++ webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlListFormat.h 2025-03-11 17:31:15.881192380 -0500
@@ -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 -urp webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp
--- webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp 2025-02-25 02:25:37.791305000 -0600
+++ webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlNumberFormat.cpp 2025-03-11 17:31:15.881401415 -0500
@@ -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> wel
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(UNumb
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::initializeNumberF
// 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
@@ -553,11 +566,120 @@ void IntlNumberFormat::initializeNumberF
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
@@ -569,6 +691,7 @@ JSValue IntlNumberFormat::format(JSGloba
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));
@@ -580,6 +703,12 @@ JSValue IntlNumberFormat::format(JSGloba
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)));
}
@@ -593,6 +722,7 @@ JSValue IntlNumberFormat::format(JSGloba
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));
@@ -604,9 +734,16 @@ JSValue IntlNumberFormat::format(JSGloba
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();
@@ -674,6 +811,7 @@ JSValue IntlNumberFormat::formatRange(JS
return jsString(vm, String({ string, static_cast<size_t>(length) }));
}
+#endif
static constexpr int32_t literalField = -1;
struct IntlNumberFormatField {
@@ -786,6 +924,7 @@ static Vector<IntlNumberFormatField> fla
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));
@@ -1027,6 +1166,7 @@ JSValue IntlNumberFormat::formatRangeToP
return parts;
}
+#endif
ASCIILiteral IntlNumberFormat::styleString(Style style)
{
@@ -1324,6 +1464,7 @@ JSValue IntlNumberFormat::formatToParts(
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))
@@ -1338,6 +1479,13 @@ JSValue IntlNumberFormat::formatToParts(
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));
@@ -1351,6 +1499,7 @@ JSValue IntlNumberFormat::formatToParts(
return parts;
}
+#if HAVE(ICU_U_NUMBER_FORMATTER)
JSValue IntlNumberFormat::formatToParts(JSGlobalObject* globalObject, IntlMathematicalValue&& value, JSString* sourceType) const
{
VM& vm = globalObject->vm();
@@ -1395,6 +1544,7 @@ JSValue IntlNumberFormat::formatToParts(
return parts;
}
+#endif
IntlMathematicalValue IntlMathematicalValue::parseString(JSGlobalObject* globalObject, StringView view)
{
diff -urp webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlNumberFormat.h webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlNumberFormat.h
--- webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlNumberFormat.h 2025-02-25 02:25:37.791305000 -0600
+++ webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlNumberFormat.h 2025-03-11 17:31:15.881997513 -0500
@@ -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 { Stan
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 -urp webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.cpp webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.cpp
--- webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.cpp 2025-02-25 02:25:37.791305000 -0600
+++ webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlNumberFormatPrototype.cpp 2025-03-11 17:31:15.882149090 -0500
@@ -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 IntlNumberFormatPrototyp
/* 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::finishCr
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(intlNumberForma
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(intlNumberForma
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(intlNumberForma
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(intlNumberForma
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(intlNumberForma
RELEASE_AND_RETURN(scope, JSValue::encode(numberFormat->formatRangeToParts(globalObject, WTFMove(start), WTFMove(end))));
}
+#endif
JSC_DEFINE_HOST_FUNCTION(intlNumberFormatPrototypeFuncResolvedOptions, (JSGlobalObject* globalObject, CallFrame* callFrame))
{
diff -urp webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlObject.cpp webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlObject.cpp
--- webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlObject.cpp 2025-02-25 02:25:37.791305000 -0600
+++ webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlObject.cpp 2025-03-11 17:31:15.882398862 -0500
@@ -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,
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 -urp webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlPluralRules.cpp webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlPluralRules.cpp
--- webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlPluralRules.cpp 2025-02-25 02:25:37.791305000 -0600
+++ webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlPluralRules.cpp 2025-03-11 17:31:15.882688861 -0500
@@ -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::initializePluralRu
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::initializePluralRu
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(JSGlobal
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(JSGlobal
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(JSG
return throwTypeError(globalObject, scope, "failed to select plural value"_s);
return jsString(vm, String(WTFMove(buffer)));
}
+#endif
} // namespace JSC
diff -urp webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlPluralRules.h webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlPluralRules.h
--- webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlPluralRules.h 2025-02-25 02:25:37.791305000 -0600
+++ webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlPluralRules.h 2025-03-11 17:31:15.882868300 -0500
@@ -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 -urp webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlPluralRulesPrototype.cpp webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlPluralRulesPrototype.cpp
--- webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlPluralRulesPrototype.cpp 2025-02-25 02:25:37.791305000 -0600
+++ webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlPluralRulesPrototype.cpp 2025-03-11 17:31:15.882982827 -0500
@@ -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
/* 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::finishCre
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(intlPluralRules
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(intlPluralRules
RELEASE_AND_RETURN(scope, JSValue::encode(pluralRules->selectRange(globalObject, start, end)));
}
+#endif
JSC_DEFINE_HOST_FUNCTION(intlPluralRulesPrototypeFuncResolvedOptions, (JSGlobalObject* globalObject, CallFrame* callFrame))
{
diff -urp webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlWorkaround.cpp webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlWorkaround.cpp
--- webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/IntlWorkaround.cpp 2025-02-25 02:25:37.791305000 -0600
+++ webkitgtk-2.47.90/Source/JavaScriptCore/runtime/IntlWorkaround.cpp 2025-03-11 17:31:15.883079660 -0500
@@ -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 -urp webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/JSDateMath.cpp webkitgtk-2.47.90/Source/JavaScriptCore/runtime/JSDateMath.cpp
--- webkitgtk-2.47.90.orig/Source/JavaScriptCore/runtime/JSDateMath.cpp 2025-02-25 02:25:37.799305400 -0600
+++ webkitgtk-2.47.90/Source/JavaScriptCore/runtime/JSDateMath.cpp 2025-03-11 19:02:57.503766370 -0500
@@ -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::calculateLoca
// 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::calculateLoca
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(JSGlobalObje
// 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(bo
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;
@@ -520,6 +601,7 @@ void DateCache::timeZoneCacheSlow()
{
ASSERT(!m_timeZoneCache);
auto [canonical, timeZoneID] = retrieveTimeZoneInformation();
+#if HAVE(ICU_C_TIMEZONE_API)
auto* cache = new OpaqueICUTimeZone;
cache->m_canonicalTimeZoneID = WTFMove(canonical);
UErrorCode status = U_ZERO_ERROR;
@@ -527,6 +609,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()
Only in webkitgtk-2.47.90/Source/JavaScriptCore/runtime: .JSDateMath.cpp.swp