From 9fe72b90bda180bcafd79f28a5d1c02d4b3a4e09 Mon Sep 17 00:00:00 2001 From: Timothy Hatcher Date: Wed, 4 Oct 2023 15:56:51 -0700 Subject: [PATCH 01/16] Inject Web Extension bindings before the InjectedBundle. https://webkit.org/b/262576 Reviewed by Brian Weinstein. Reverse the order of inject so Safari can inject after WebKit if needed. Aslo adopt RefPtr in more spots to match Chris's change in bd0e961. * Source/WebKit/WebProcess/WebCoreSupport/WebLocalFrameLoaderClient.cpp: (WebKit::WebLocalFrameLoaderClient::dispatchDidStartProvisionalLoad): (WebKit::WebLocalFrameLoaderClient::dispatchDidCommitLoad): (WebKit::WebLocalFrameLoaderClient::dispatchDidFinishLoad): (WebKit::WebLocalFrameLoaderClient::dispatchGlobalObjectAvailable): (WebKit::WebLocalFrameLoaderClient::dispatchServiceWorkerGlobalObjectAvailable): Canonical link: https://commits.webkit.org/268878@main --- .../WebLocalFrameLoaderClient.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebLocalFrameLoaderClient.cpp b/Source/WebKit/WebProcess/WebCoreSupport/WebLocalFrameLoaderClient.cpp index 9c27ea6ed436..53003e097a66 100644 --- a/Source/WebKit/WebProcess/WebCoreSupport/WebLocalFrameLoaderClient.cpp +++ b/Source/WebKit/WebProcess/WebCoreSupport/WebLocalFrameLoaderClient.cpp @@ -560,7 +560,7 @@ void WebLocalFrameLoaderClient::dispatchDidStartProvisionalLoad() #if ENABLE(WK_WEB_EXTENSIONS) // Notify the extensions controller. - if (auto* extensionControllerProxy = webPage->webExtensionControllerProxy()) + if (RefPtr extensionControllerProxy = webPage->webExtensionControllerProxy()) extensionControllerProxy->didStartProvisionalLoadForFrame(*webPage, m_frame, url); #endif @@ -617,7 +617,7 @@ void WebLocalFrameLoaderClient::dispatchDidCommitLoad(std::optionalwebExtensionControllerProxy()) + if (RefPtr extensionControllerProxy = webPage->webExtensionControllerProxy()) extensionControllerProxy->didCommitLoadForFrame(*webPage, m_frame, m_frame->url()); #endif @@ -736,7 +736,7 @@ void WebLocalFrameLoaderClient::dispatchDidFinishLoad() #if ENABLE(WK_WEB_EXTENSIONS) // Notify the extensions controller. - if (auto* extensionControllerProxy = webPage->webExtensionControllerProxy()) + if (RefPtr extensionControllerProxy = webPage->webExtensionControllerProxy()) extensionControllerProxy->didFinishLoadForFrame(*webPage, m_frame, m_frame->url()); #endif @@ -1698,12 +1698,12 @@ void WebLocalFrameLoaderClient::dispatchGlobalObjectAvailable(DOMWrapperWorld& w if (!webPage) return; - webPage->injectedBundleLoaderClient().globalObjectIsAvailableForFrame(*webPage, m_frame, world); - #if ENABLE(WK_WEB_EXTENSIONS) - if (auto* extensionControllerProxy = webPage->webExtensionControllerProxy()) + if (RefPtr extensionControllerProxy = webPage->webExtensionControllerProxy()) extensionControllerProxy->globalObjectIsAvailableForFrame(*webPage, m_frame, world); #endif + + webPage->injectedBundleLoaderClient().globalObjectIsAvailableForFrame(*webPage, m_frame, world); } void WebLocalFrameLoaderClient::dispatchServiceWorkerGlobalObjectAvailable(DOMWrapperWorld& world) @@ -1712,12 +1712,12 @@ void WebLocalFrameLoaderClient::dispatchServiceWorkerGlobalObjectAvailable(DOMWr if (!webPage) return; - webPage->injectedBundleLoaderClient().serviceWorkerGlobalObjectIsAvailableForFrame(*webPage, m_frame, world); - #if ENABLE(WK_WEB_EXTENSIONS) - if (auto* extensionControllerProxy = webPage->webExtensionControllerProxy()) + if (RefPtr extensionControllerProxy = webPage->webExtensionControllerProxy()) extensionControllerProxy->serviceWorkerGlobalObjectIsAvailableForFrame(*webPage, m_frame, world); #endif + + webPage->injectedBundleLoaderClient().serviceWorkerGlobalObjectIsAvailableForFrame(*webPage, m_frame, world); } void WebLocalFrameLoaderClient::willInjectUserScript(DOMWrapperWorld& world) From c1c9b7014e95a86527bdc43271a0b2d688c02dc2 Mon Sep 17 00:00:00 2001 From: Chris Dumez Date: Wed, 4 Oct 2023 16:18:46 -0700 Subject: [PATCH 02/16] Add Vector::appendList() function which takes in a std::initializer_list https://bugs.webkit.org/show_bug.cgi?id=262598 Reviewed by Brent Fulgham. Add Vector::appendList() function which takes in a std::initializer_list and use it in a few places. Note that we already have a Vector constructor taking a std::initializer_list. * Source/WTF/wtf/URLParser.cpp: (WTF::appendCodePoint): * Source/WTF/wtf/Vector.h: (WTF::Vector::appendList): * Source/WebCore/PAL/pal/text/TextCodecCJK.cpp: (PAL::urlEncodedEntityUnencodableHandler): (PAL::entityUnencodableHandler): * Source/WebCore/platform/graphics/cg/GradientRendererCG.cpp: (WebCore::GradientRendererCG::makeGradient const): * Source/WebCore/platform/graphics/gstreamer/eme/CDMThunder.cpp: (WebCore::CDMPrivateThunder::supportedInitDataTypes const): * Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp: * Source/WebCore/platform/text/LocaleNone.cpp: (WebCore::LocaleNone::timeAMPMLabels): * Source/WebKit/NetworkProcess/webrtc/NetworkRTCTCPSocketCocoa.mm: (WebKit::NetworkRTCTCPSocketCocoa::createMessageBuffer): * Tools/TestWebKitAPI/Tests/WTF/Vector.cpp: (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/268879@main --- Source/WTF/wtf/URLParser.cpp | 4 +--- Source/WTF/wtf/Vector.h | 1 + Source/WebCore/PAL/pal/text/TextCodecCJK.cpp | 14 +++----------- .../platform/graphics/cg/GradientRendererCG.cpp | 10 ++-------- .../graphics/gstreamer/eme/CDMThunder.cpp | 6 +----- .../platform/mock/MockRealtimeVideoSource.cpp | 4 +--- Source/WebCore/platform/text/LocaleNone.cpp | 4 +--- .../webrtc/NetworkRTCTCPSocketCocoa.mm | 3 +-- Tools/TestWebKitAPI/Tests/WTF/Vector.cpp | 17 +++++++++++++++++ 9 files changed, 28 insertions(+), 35 deletions(-) diff --git a/Source/WTF/wtf/URLParser.cpp b/Source/WTF/wtf/URLParser.cpp index 800872baf935..56c50e8e0879 100644 --- a/Source/WTF/wtf/URLParser.cpp +++ b/Source/WTF/wtf/URLParser.cpp @@ -47,9 +47,7 @@ ALWAYS_INLINE static void appendCodePoint(Vector& destination, UChar32 co destination.append(static_cast(codePoint)); return; } - destination.reserveCapacity(destination.size() + 2); - destination.uncheckedAppend(U16_LEAD(codePoint)); - destination.uncheckedAppend(U16_TRAIL(codePoint)); + destination.appendList({ U16_LEAD(codePoint), U16_TRAIL(codePoint) }); } enum URLCharacterClass { diff --git a/Source/WTF/wtf/Vector.h b/Source/WTF/wtf/Vector.h index e194403e70eb..1c1152e50822 100644 --- a/Source/WTF/wtf/Vector.h +++ b/Source/WTF/wtf/Vector.h @@ -862,6 +862,7 @@ class Vector : private VectorBuffer { template ALWAYS_INLINE void append(const U* u, size_t size) { append(u, size); } template ALWAYS_INLINE bool tryAppend(const U* u, size_t size) { return append(u, size); } template ALWAYS_INLINE void append(std::span span) { append(span.data(), span.size()); } + template ALWAYS_INLINE void appendList(std::initializer_list initializerList) { append(std::data(initializerList), initializerList.size()); } template void appendVector(const Vector&); template void appendVector(Vector&&); diff --git a/Source/WebCore/PAL/pal/text/TextCodecCJK.cpp b/Source/WebCore/PAL/pal/text/TextCodecCJK.cpp index 5c231e5f7aa9..9227b3a5c71b 100644 --- a/Source/WebCore/PAL/pal/text/TextCodecCJK.cpp +++ b/Source/WebCore/PAL/pal/text/TextCodecCJK.cpp @@ -1124,23 +1124,15 @@ static void appendDecimal(UChar32 c, Vector& result) static void urlEncodedEntityUnencodableHandler(UChar32 c, Vector& result) { result.reserveCapacity(result.size() + 9 + maxUChar32Digits); - result.uncheckedAppend('%'); - result.uncheckedAppend('2'); - result.uncheckedAppend('6'); - result.uncheckedAppend('%'); - result.uncheckedAppend('2'); - result.uncheckedAppend('3'); + result.appendList({ '%', '2', '6', '%', '2', '3' }); appendDecimal(c, result); - result.uncheckedAppend('%'); - result.uncheckedAppend('3'); - result.uncheckedAppend('B'); + result.appendList({ '%', '3', 'B' }); } static void entityUnencodableHandler(UChar32 c, Vector& result) { result.reserveCapacity(result.size() + 3 + maxUChar32Digits); - result.uncheckedAppend('&'); - result.uncheckedAppend('#'); + result.appendList({ '&', '#' }); appendDecimal(c, result); result.uncheckedAppend(';'); } diff --git a/Source/WebCore/platform/graphics/cg/GradientRendererCG.cpp b/Source/WebCore/platform/graphics/cg/GradientRendererCG.cpp index f61a8e537a02..c3fd9794c5ef 100644 --- a/Source/WebCore/platform/graphics/cg/GradientRendererCG.cpp +++ b/Source/WebCore/platform/graphics/cg/GradientRendererCG.cpp @@ -486,10 +486,7 @@ GradientRendererCG::Strategy GradientRendererCG::makeGradient(ColorInterpolation if (hasOnlyBoundedSRGBColorStops(stops)) { for (const auto& stop : stops) { auto [r, g, b, a] = stop.color.toColorTypeLossy>().resolved(); - colorComponents.uncheckedAppend(r); - colorComponents.uncheckedAppend(g); - colorComponents.uncheckedAppend(b); - colorComponents.uncheckedAppend(a); + colorComponents.appendList({ r, g, b, a }); locations.uncheckedAppend(stop.offset); } @@ -499,10 +496,7 @@ GradientRendererCG::Strategy GradientRendererCG::makeGradient(ColorInterpolation using OutputSpaceColorType = std::conditional_t, ExtendedSRGBA, SRGBA>; for (const auto& stop : stops) { auto [r, g, b, a] = stop.color.toColorTypeLossy().resolved(); - colorComponents.uncheckedAppend(r); - colorComponents.uncheckedAppend(g); - colorComponents.uncheckedAppend(b); - colorComponents.uncheckedAppend(a); + colorComponents.appendList({ r, g, b, a }); locations.uncheckedAppend(stop.offset); } diff --git a/Source/WebCore/platform/graphics/gstreamer/eme/CDMThunder.cpp b/Source/WebCore/platform/graphics/gstreamer/eme/CDMThunder.cpp index f9cb1e675129..2bdbafd656ac 100644 --- a/Source/WebCore/platform/graphics/gstreamer/eme/CDMThunder.cpp +++ b/Source/WebCore/platform/graphics/gstreamer/eme/CDMThunder.cpp @@ -150,11 +150,7 @@ Vector CDMPrivateThunder::supportedInitDataTypes() const static std::once_flag onceFlag; static Vector supportedInitDataTypes; std::call_once(onceFlag, [] { - supportedInitDataTypes.reserveInitialCapacity(4); - supportedInitDataTypes.uncheckedAppend("keyids"_s); - supportedInitDataTypes.uncheckedAppend("cenc"_s); - supportedInitDataTypes.uncheckedAppend("webm"_s); - supportedInitDataTypes.uncheckedAppend("cbcs"_s); + supportedInitDataTypes.appendList({ "keyids"_s, "cenc"_s, "webm"_s, "cbcs"_s }); }); return supportedInitDataTypes; } diff --git a/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp b/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp index 44b79b790d89..ed4af67cba09 100644 --- a/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp +++ b/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp @@ -86,9 +86,7 @@ MockRealtimeVideoSource::MockRealtimeVideoSource(String&& deviceID, AtomString&& ASSERT(device); m_device = *device; - m_dashWidths.reserveInitialCapacity(2); - m_dashWidths.uncheckedAppend(6); - m_dashWidths.uncheckedAppend(6); + m_dashWidths.appendList({ 6, 6 }); if (mockDisplay()) { auto& properties = std::get(m_device.properties); diff --git a/Source/WebCore/platform/text/LocaleNone.cpp b/Source/WebCore/platform/text/LocaleNone.cpp index a8da65620974..55824cf26807 100644 --- a/Source/WebCore/platform/text/LocaleNone.cpp +++ b/Source/WebCore/platform/text/LocaleNone.cpp @@ -136,9 +136,7 @@ const Vector& LocaleNone::timeAMPMLabels() { if (!m_timeAMPMLabels.isEmpty()) return m_timeAMPMLabels; - m_timeAMPMLabels.reserveCapacity(2); - m_timeAMPMLabels.uncheckedAppend("AM"); - m_timeAMPMLabels.uncheckedAppend("PM"); + m_timeAMPMLabels.appendList({ "AM"_s, "PM"_s }); return m_timeAMPMLabels; } diff --git a/Source/WebKit/NetworkProcess/webrtc/NetworkRTCTCPSocketCocoa.mm b/Source/WebKit/NetworkProcess/webrtc/NetworkRTCTCPSocketCocoa.mm index 2b5d2bfc692c..df6f051dbd4d 100644 --- a/Source/WebKit/NetworkProcess/webrtc/NetworkRTCTCPSocketCocoa.mm +++ b/Source/WebKit/NetworkProcess/webrtc/NetworkRTCTCPSocketCocoa.mm @@ -195,8 +195,7 @@ static inline void processIncomingData(RetainPtr&& nwConnection // Prepend length. Vector buffer; buffer.reserveInitialCapacity(size + 2); - buffer.uncheckedAppend((size >> 8) & 0xFF); - buffer.uncheckedAppend(size & 0xFF); + buffer.appendList({ (size >> 8) & 0xFF, size & 0xFF }); buffer.append(data, size); return buffer; } diff --git a/Tools/TestWebKitAPI/Tests/WTF/Vector.cpp b/Tools/TestWebKitAPI/Tests/WTF/Vector.cpp index 409550d73977..6a7fb4d55357 100644 --- a/Tools/TestWebKitAPI/Tests/WTF/Vector.cpp +++ b/Tools/TestWebKitAPI/Tests/WTF/Vector.cpp @@ -339,6 +339,23 @@ TEST(WTF_Vector, ConstructorTakingLengthAndFunctor) EXPECT_EQ(vector[4], 4U); } +TEST(WTF_Vector, AppendList) +{ + Vector vector({ 1, 2, 3 }); + EXPECT_EQ(vector.size(), 3U); + EXPECT_EQ(vector[0], 1U); + EXPECT_EQ(vector[1], 2U); + EXPECT_EQ(vector[2], 3U); + vector.appendList({ 4, 5, 6 }); + EXPECT_EQ(vector.size(), 6U); + EXPECT_EQ(vector[0], 1U); + EXPECT_EQ(vector[1], 2U); + EXPECT_EQ(vector[2], 3U); + EXPECT_EQ(vector[3], 4U); + EXPECT_EQ(vector[4], 5U); + EXPECT_EQ(vector[5], 6U); +} + TEST(WTF_Vector, Reverse) { Vector intVector; From 0345168e97b5e2c1fa074c8b5c9d721e23ae60ce Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Wed, 4 Oct 2023 16:19:34 -0700 Subject: [PATCH 03/16] NativePromise should provide a safe way to pass some argument types https://bugs.webkit.org/show_bug.cgi?id=262437 rdar://116274506 Reviewed by Youenn Fablet. We expand the scope of CrossThreadCopier so that it can always deal with r-values, including those without an isolatedCopy() method. Add specialisation for void, std::tuple and AtomString. We allow using non-threadsafe refcount when using only r-value as the object can be safely moved around. NativePromise aims to add a layer between the producer and the consumer such that the producer doesn't have to know the threading model of the consumer. To achieve this, we needed to have a way to guarantee that the object returned by the producer is usable on any threads. By using this expanded CrossThreadCopier in NativePromise we achieve that goal. It is now safe to have NativePromise using Strings, AtomString and any supported composite objects using those (tuple, variant, pair, expected, Vector, optional, HashMap, HashSet) Should more specialisation be needed, they should be added to CrossThreadCopier. Non Exclusive NativePromise requires the programmer to explicitly define the behaviour: that is always use CrossThreadCopy or never do. Add API tests. * Source/WTF/wtf/CrossThreadCopier.cpp: * Source/WTF/wtf/CrossThreadCopier.h: * Source/WTF/wtf/Forward.h: * Source/WTF/wtf/NativePromise.h: (WTF::operator|): (WTF::operator&): * Source/WTF/wtf/TypeTraits.h: * Source/WebCore/Modules/webaudio/AsyncAudioDecoder.cpp: Make use of the ability of rejecting with an Exception object. (WebCore::AsyncAudioDecoder::decodeAsync): * Source/WebCore/Modules/webaudio/AsyncAudioDecoder.h: Update definition of DecodingTaskPromise * Source/WebCore/Modules/webaudio/BaseAudioContext.cpp: (WebCore::BaseAudioContext::decodeAudioData): * Source/WebCore/dom/ExceptionOr.h: * Source/WebKit/Scripts/webkit/messages.py: (message_to_struct_declaration): * Source/WebKit/Scripts/webkit/tests/TestWithCVPixelBufferMessages.h: * Source/WebKit/Scripts/webkit/tests/TestWithImageDataMessages.h: * Source/WebKit/Scripts/webkit/tests/TestWithLegacyReceiverMessages.h: * Source/WebKit/Scripts/webkit/tests/TestWithSemaphoreMessages.h: * Source/WebKit/Scripts/webkit/tests/TestWithStreamMessages.h: * Source/WebKit/Scripts/webkit/tests/TestWithSuperclassMessages.h: * Source/WebKit/Scripts/webkit/tests/TestWithoutAttributesMessages.h: * Source/WebKit/Scripts/webkit/tests/TestWithoutUsingIPCConnectionMessages.h: * Tools/TestWebKitAPI/Tests/WTF/NativePromise.cpp: (TestWebKitAPI::TEST): Canonical link: https://commits.webkit.org/268880@main --- Source/WTF/wtf/CrossThreadCopier.cpp | 6 - Source/WTF/wtf/CrossThreadCopier.h | 151 +++++++++- Source/WTF/wtf/Forward.h | 2 +- Source/WTF/wtf/NativePromise.h | 84 ++++-- Source/WTF/wtf/TypeTraits.h | 13 + .../Modules/webaudio/AsyncAudioDecoder.cpp | 2 +- .../Modules/webaudio/AsyncAudioDecoder.h | 12 +- .../Modules/webaudio/BaseAudioContext.cpp | 2 +- Source/WebCore/dom/ExceptionOr.h | 6 +- Source/WebKit/Scripts/webkit/messages.py | 6 +- .../tests/TestWithCVPixelBufferMessages.h | 2 +- .../webkit/tests/TestWithImageDataMessages.h | 2 +- .../tests/TestWithLegacyReceiverMessages.h | 8 +- .../webkit/tests/TestWithSemaphoreMessages.h | 2 +- .../webkit/tests/TestWithStreamMessages.h | 4 +- .../webkit/tests/TestWithSuperclassMessages.h | 8 +- .../tests/TestWithoutAttributesMessages.h | 8 +- .../TestWithoutUsingIPCConnectionMessages.h | 8 +- .../Tests/IPC/IPCTestUtilities.h | 2 +- .../TestWebKitAPI/Tests/WTF/NativePromise.cpp | 284 +++++++++++++++++- 20 files changed, 525 insertions(+), 87 deletions(-) diff --git a/Source/WTF/wtf/CrossThreadCopier.cpp b/Source/WTF/wtf/CrossThreadCopier.cpp index 17d971ada563..4f348bee7333 100644 --- a/Source/WTF/wtf/CrossThreadCopier.cpp +++ b/Source/WTF/wtf/CrossThreadCopier.cpp @@ -44,11 +44,6 @@ static_assert((std::is_same, CrossThreadC static_assert((std::is_same, CrossThreadCopier::Type>::value), "RawPointerTest"); static_assert((std::is_same, CrossThreadCopier>::Type>::value), "RawPointerTest"); -// Add specializations for RefCounted types which will let us verify that no other template matches. -template struct CrossThreadCopierBase> { - typedef int Type; -}; - template struct CrossThreadCopierBase { typedef int Type; }; @@ -57,7 +52,6 @@ template struct CrossThreadCopierBase { class CopierRefCountedTest : public RefCounted { }; -static_assert((std::is_same>::Type>::value), "CrossThreadCopier specialization improperly applied to RefPtr<> of a RefCounted (but not ThreadSafeRefCounted) type"); static_assert((std::is_same::Type>::value), "CrossThreadCopier specialization improperly applied to raw pointer of a RefCounted (but not ThreadSafeRefCounted) type"); } // namespace WTF diff --git a/Source/WTF/wtf/CrossThreadCopier.h b/Source/WTF/wtf/CrossThreadCopier.h index 1e44d4aed236..889741e20774 100644 --- a/Source/WTF/wtf/CrossThreadCopier.h +++ b/Source/WTF/wtf/CrossThreadCopier.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2009, 2010 Google Inc. All rights reserved. - * Copyright (C) 2014-2019 Apple Inc. All rights reserved. + * Copyright (C) 2014-2023 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -31,13 +31,17 @@ #pragma once +#include #include +#include #include +#include #include #include #include #include #include +#include #include namespace WTF { @@ -68,7 +72,9 @@ struct CrossThreadCopierBaseHelper { }; template struct CrossThreadCopierPassThrough { - typedef T Type; + static_assert(CrossThreadCopierBaseHelper::IsEnumOrConvertibleToInteger::value, "CrossThreadCopierPassThrough only used for enums or integers"); + using Type = T; + static constexpr bool IsNeeded = false; static Type copy(const T& parameter) { return parameter; @@ -82,37 +88,89 @@ template struct CrossThreadCopierBase : public Cross }; // Classes that have an isolatedCopy() method get a default specialization. -template struct CrossThreadCopierBase { - template static auto copy(U&& value) +template +struct CrossThreadCopierBase { + using Type = T; + static constexpr bool IsNeeded = HasIsolatedCopy::value; + template static auto copy(U&& value) -> Type { - return std::forward(value).isolatedCopy(); + if constexpr (HasIsolatedCopy::value) + return std::forward(value).isolatedCopy(); + else + return std::forward(value); } }; // Custom copy methods. template struct CrossThreadCopierBase { - typedef typename CrossThreadCopierBaseHelper::RemovePointer::Type RefCountedType; + using RefCountedType = typename CrossThreadCopierBaseHelper::RemovePointer::Type; static_assert(std::is_convertible::value, "T is not convertible to ThreadSafeRefCounted!"); - typedef RefPtr Type; + using Type = RefPtr; + static constexpr bool IsNeeded = false; + static Type copy(const T& refPtr) { return refPtr; } + static Type copy(T&& refPtr) + { + return WTFMove(refPtr); + } +}; + +// Can only be moved +template struct CrossThreadCopierBase> { + using Type = Ref; + static constexpr bool IsNeeded = false; + static Type copy(Type&& ref) + { + return WTFMove(ref); + } +}; + +// Can only be moved +template struct CrossThreadCopierBase> { + using Type = RefPtr; + static constexpr bool IsNeeded = false; + static Type copy(Type&& ref) + { + return WTFMove(ref); + } }; template struct CrossThreadCopierBase> { static_assert(std::is_convertible::value, "T is not convertible to ThreadSafeRefCounted!"); + static constexpr bool IsNeeded = false; - typedef Ref Type; + using Type = Ref; static Type copy(const Type& ref) { return ref; } + static Type copy(Type&& ref) + { + return WTFMove(ref); + } +}; + +// Default specialization for AtomString of CrossThreadCopyable classes. +template<> struct CrossThreadCopierBase { + using Type = String; + static constexpr bool IsNeeded = true; + static Type copy(const AtomString& source) + { + return source.string().isolatedCopy(); + } + static Type copy(AtomString&& source) + { + return source.releaseString().isolatedCopy(); + } }; template<> struct CrossThreadCopierBase { - typedef WTF::ASCIILiteral Type; + using Type = WTF::ASCIILiteral; + static constexpr bool IsNeeded = false; static Type copy(const Type& source) { return source; @@ -120,7 +178,8 @@ template<> struct CrossThreadCopierBase { }; template struct CrossThreadCopierBase> { - typedef ObjectIdentifierGeneric Type; + using Type = ObjectIdentifierGeneric; + static constexpr bool IsNeeded = false; static Type copy(const Type& source) { return source; @@ -134,6 +193,7 @@ struct CrossThreadCopier : public CrossThreadCopierBase struct CrossThreadCopierBase> { using Type = Vector; + static constexpr bool IsNeeded = CrossThreadCopier::IsNeeded; static Type copy(const Type& source) { return WTF::map(source, [](auto& object) { @@ -147,10 +207,11 @@ template struct CrossThreadCopierBase > { - typedef HashSet Type; + using Type = HashSet; + static constexpr bool IsNeeded = CrossThreadCopier::IsNeeded; static Type copy(const Type& source) { Type destination; @@ -171,7 +232,8 @@ template struct CrossThreadCopierBase > { // Default specialization for HashMaps of CrossThreadCopyable classes template struct CrossThreadCopierBase> { - typedef HashMap Type; + using Type = HashMap; + static constexpr bool IsNeeded = CrossThreadCopier::IsNeeded || CrossThreadCopier::IsNeeded; static Type copy(const Type& source) { Type destination; @@ -191,7 +253,8 @@ struct CrossThreadCopierBase struct CrossThreadCopierBase > { - typedef std::pair Type; + using Type = std::pair; + static constexpr bool IsNeeded = CrossThreadCopier::IsNeeded || CrossThreadCopier::IsNeeded; template static Type copy(U&& source) { return std::make_pair(CrossThreadCopier::copy(std::get<0>(std::forward(source))), CrossThreadCopier::copy(std::get<1>(std::forward(source)))); @@ -200,6 +263,8 @@ template struct CrossThreadCopierBase struct CrossThreadCopierBase> { + using Type = std::optional; + static constexpr bool IsNeeded = CrossThreadCopier::IsNeeded; template static std::optional copy(U&& source) { if (!source) @@ -210,7 +275,9 @@ template struct CrossThreadCopierBase // Default specialization for Markable of CrossThreadCopyable class. template struct CrossThreadCopierBase> { - template static Markable copy(V&& source) + using Type = Markable; + static constexpr bool IsNeeded = CrossThreadCopier::IsNeeded; + template static Type copy(V&& source) { if (!source) return std::nullopt; @@ -219,12 +286,14 @@ template struct CrossThreadCopierBase struct CrossThreadCopierBase { + static constexpr bool IsNeeded = false; static std::nullptr_t copy(std::nullptr_t) { return nullptr; } }; // Default specialization for std::variant of CrossThreadCopyable classes. template struct CrossThreadCopierBase> { using Type = std::variant; + static constexpr bool IsNeeded = (CrossThreadCopier>::IsNeeded || ...); static std::variant copy(const Type& source) { return std::visit([] (auto& type) -> std::variant { @@ -239,11 +308,61 @@ template struct CrossThreadCopierBase +struct CrossThreadCopierBase { + static constexpr bool IsNeeded = false; + using Type = void; +}; + +template struct CrossThreadCopierBase > { + using Type = Expected; + static constexpr bool IsNeeded = CrossThreadCopier>::IsNeeded || CrossThreadCopier>::IsNeeded; + static Type copy(const Type& source) + { + if (source.has_value()) { + if constexpr (std::is_void_v) + return source; + else + return CrossThreadCopier::copy(source.value()); + } + return Unexpected(CrossThreadCopier::copy(source.error())); + } + + static Type copy(Type&& source) + { + if (source.has_value()) { + if constexpr (std::is_void_v) + return WTFMove(source); + else + return CrossThreadCopier::copy(WTFMove(source.value())); + } + return Unexpected(CrossThreadCopier::copy(WTFMove(source.error()))); + } +}; + +// Default specialization for std::tuple of CrossThreadCopyable classes. +template struct CrossThreadCopierBase> { + using Type = std::tuple; + static constexpr bool IsNeeded = (CrossThreadCopier>::IsNeeded || ...); + static Type copy(const Type& source) + { + return std::apply([](Ts const&... ts) { + return std::make_tuple((CrossThreadCopier>::copy(ts), ...)); + }, source); + } + static Type copy(Type&& source) + { + return std::apply([](Ts&&... ts) { + return std::make_tuple((CrossThreadCopier>::copy(WTFMove(ts)), ...)); + }, WTFMove(source)); + } +}; + template auto crossThreadCopy(T&& source) { return CrossThreadCopier>::copy(std::forward(source)); } - + } // namespace WTF using WTF::CrossThreadCopierBaseHelper; diff --git a/Source/WTF/wtf/Forward.h b/Source/WTF/wtf/Forward.h index 02b60e80e16c..0d101674c60a 100644 --- a/Source/WTF/wtf/Forward.h +++ b/Source/WTF/wtf/Forward.h @@ -122,7 +122,7 @@ template, typename = HashTraits> class HashCountedSet; template, typename = HashTraits, typename = HashTraits, typename = HashTableTraits> class HashMap; template, typename = HashTraits, typename = HashTableTraits> class HashSet; -template class NativePromise; +template class NativePromise; } diff --git a/Source/WTF/wtf/NativePromise.h b/Source/WTF/wtf/NativePromise.h index b501fba720a8..600307de8e74 100644 --- a/Source/WTF/wtf/NativePromise.h +++ b/Source/WTF/wtf/NativePromise.h @@ -33,7 +33,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -70,6 +72,10 @@ namespace WTF { * - values are passed to the resolve/reject callbacks through either const references or pointers. * - the resolve or reject object will be deleted on the last SerialFunctionDispatcher that got used. * + * By default, a NativePromise will use crossThreadCopy() on the resolved or rejected object if it contains a type with the `isolatedCopy()` method + * or an AtomString (be it directly, or in a composited object (e.g. Vector). + * This behaviour can be overridden with either PromiseOption::WithCrossThreadCopy or PromiseOption::WithoutCrossThreadCopy + * * A typical workflow would be as follow: * If the work is to be done immediately: * From the producer side: @@ -94,7 +100,8 @@ namespace WTF { * * By disconnecting the NativePromiseRequest (via NativePromiseRequest::disconnect(), the then()/whenSettled() callbacks will not be run. * - * For now, care should be taken by the Producer to only return an object that is usable on the target's queue (don't return an AtomString for example) + * The object given to resolve, reject or resolveOrReject must have a CrossThreadCopier specialisation as needed. + * The type of this object may not be identical to ResolveValueType or RejectValueType as the methods allow for implicit conversion. * * Examples: * 1. Basic usage. methodA runs on the main thread, methodB must run on a WorkQueue, and expects a std::unique. @@ -207,13 +214,40 @@ enum class PromiseDispatchMode : uint8_t { }; -template +enum class PromiseOption : uint8_t { + Default = 0, // Exclusive | WithAutomaticCrossThreadCopy + NonExclusive = (1 << 0), + WithCrossThreadCopy = (1 << 2), + WithoutCrossThreadCopy = (1 << 3), +}; +constexpr unsigned operator|(PromiseOption a, PromiseOption b) +{ + return static_cast(a) | static_cast(b); +} +constexpr unsigned operator|(unsigned a, PromiseOption b) +{ + return a | static_cast(b); +} +constexpr unsigned operator&(PromiseOption a, PromiseOption b) +{ + return static_cast(a) & static_cast(b); +} +constexpr unsigned operator&(unsigned a, PromiseOption b) +{ + return a & static_cast(b); +} + +template class NativePromise final : public NativePromiseBase, public ConvertibleToNativePromise { public: - using Result = Expected; - using Error = Unexpected; - using ResolveValueType = ResolveValueT; - using RejectValueType = RejectValueT; + static constexpr bool IsExclusive = !(options & PromiseOption::NonExclusive); + static constexpr bool WithCrossThreadCopy = !!(options & PromiseOption::WithCrossThreadCopy); + static constexpr bool WithAutomaticCrossThreadCopy = !(options & (PromiseOption::WithCrossThreadCopy | PromiseOption::WithoutCrossThreadCopy)) && (CrossThreadCopier::IsNeeded || CrossThreadCopier::IsNeeded); + static_assert(!WithAutomaticCrossThreadCopy || IsExclusive, "Using Non-Exclusive NativePromise with a ResolveValueT or RejectValueT requiring a call to isolatedCopy() must be explicitly set with WithCrossThreadCopy or WithoutCrossThreadCopy option"); + using ResolveValueType = std::conditional_t::Type, ResolveValueT>; + using RejectValueType = std::conditional_t::Type, RejectValueT>; + using Result = Expected; + using Error = Unexpected; // used by IsConvertibleToNativePromise to determine how to cast the result. using PromiseType = NativePromise; @@ -328,8 +362,8 @@ class NativePromise final : public NativePromiseBase, public ConvertibleToNative return p; } - using AllPromiseType = NativePromise, RejectValueType, IsExclusive>; - using AllSettledPromiseType = NativePromise, bool, IsExclusive>; + using AllPromiseType = NativePromise, RejectValueType, options>; + using AllSettledPromiseType = NativePromise, bool, options>; private: friend class Producer; @@ -340,7 +374,10 @@ class NativePromise final : public NativePromiseBase, public ConvertibleToNative Locker lock { m_lock }; PROMISE_LOG(resolveSite, " resolving ", *this); ASSERT(isNothing()); - m_result = std::forward(resolveValue); + if constexpr (WithCrossThreadCopy || WithAutomaticCrossThreadCopy) + m_result = crossThreadCopy(std::forward(resolveValue)); + else + m_result = std::forward(resolveValue); dispatchAll(lock); } @@ -361,17 +398,24 @@ class NativePromise final : public NativePromiseBase, public ConvertibleToNative Locker lock { m_lock }; PROMISE_LOG(rejectSite, " rejecting ", *this); ASSERT(isNothing()); - m_result = Unexpected(std::forward(rejectValue)); + if constexpr (WithCrossThreadCopy || WithAutomaticCrossThreadCopy) + m_result = Unexpected(crossThreadCopy(std::forward(rejectValue))); + else + m_result = Unexpected(std::forward(rejectValue)); dispatchAll(lock); } template void resolveOrReject(ResolveOrRejectValue_&& result, const Logger::LogSiteIdentifier& site) { + static_assert(std::is_convertible_v, "resolveOrReject() argument must be implicitly convertible to NativePromise's Result"); Locker lock { m_lock }; ASSERT(isNothing()); PROMISE_LOG(site, " resolveOrRejecting ", *this); - m_result = std::forward(result); + if constexpr (WithCrossThreadCopy || WithAutomaticCrossThreadCopy) + m_result = crossThreadCopy(std::forward(result)); + else + m_result = std::forward(result); dispatchAll(lock); } @@ -675,7 +719,7 @@ class NativePromise final : public NativePromiseBase, public ConvertibleToNative template class ThenCommand : public ConvertibleToNativePromise { // Allow Promise::then() to access the private constructor, - template + template friend class NativePromise; // used by IsConvertibleToNativePromise to determine how to cast the result. @@ -979,12 +1023,12 @@ class NativePromise final : public NativePromiseBase, public ConvertibleToNative std::atomic m_dispatchMode { PromiseDispatchMode::Default }; }; -template -class NativePromise::Producer final : public ConvertibleToNativePromise { +template +class NativePromise::Producer final : public ConvertibleToNativePromise { WTF_MAKE_FAST_ALLOCATED; public: // used by IsConvertibleToNativePromise to determine how to cast the result. - using PromiseType = NativePromise; + using PromiseType = NativePromise; explicit Producer(PromiseDispatchMode dispatchMode = PromiseDispatchMode::Default, const Logger::LogSiteIdentifier& creationSite = DEFAULT_LOGSITEIDENTIFIER) : m_promise(adoptRef(new PromiseType(creationSite))) @@ -1120,10 +1164,10 @@ class NativePromise::Producer final : }; // A generic promise type that does the trick for simple use cases. -using GenericPromise = NativePromise; +using GenericPromise = NativePromise; // A generic, non-exclusive promise type that does the trick for simple use cases. -using GenericNonExclusivePromise = NativePromise; +using GenericNonExclusivePromise = NativePromise; template class NativePromiseRequest final { @@ -1184,9 +1228,9 @@ static auto invokeAsync(SerialFunctionDispatcher& targetQueue, Function&& functi return promise; } -template -struct LogArgument> { - static String toString(const NativePromise& p) +template +struct LogArgument> { + static String toString(const NativePromise& p) { return makeString("NativePromise", LogArgument::toString(&p), '<', LogArgument::toString(p.logSiteIdentifier()), '>'); } diff --git a/Source/WTF/wtf/TypeTraits.h b/Source/WTF/wtf/TypeTraits.h index d5d306e3778c..d76ac6b1e2bd 100644 --- a/Source/WTF/wtf/TypeTraits.h +++ b/Source/WTF/wtf/TypeTraits.h @@ -107,6 +107,19 @@ static auto HasRefCountMethodsTest(long) -> std::false_type; template struct HasRefCountMethods : decltype(detail::HasRefCountMethodsTest(0)) { }; +// HasIsolatedCopy() +namespace detail { + +template +static auto HasIsolatedCopyTest(int) -> SFINAE1True().isolatedCopy())>; +template +static auto HasIsolatedCopyTest(long) -> std::false_type; + +} // namespace detail + +template +struct HasIsolatedCopy : decltype(detail::HasIsolatedCopyTest(0)) { }; + // LooksLikeRCSerialDispatcher implementation namespace detail { diff --git a/Source/WebCore/Modules/webaudio/AsyncAudioDecoder.cpp b/Source/WebCore/Modules/webaudio/AsyncAudioDecoder.cpp index 47bfb9244738..0eb7477c35d0 100644 --- a/Source/WebCore/Modules/webaudio/AsyncAudioDecoder.cpp +++ b/Source/WebCore/Modules/webaudio/AsyncAudioDecoder.cpp @@ -47,7 +47,7 @@ Ref AsyncAudioDecoder::decodeAsync(Ref&& audio // The ArrayBuffer must be deleted on the main thread, send it back there to be derefed. callOnMainThread([audioData = WTFMove(audioData)] { }); if (!audioBuffer) - return DecodingTaskPromise::createAndReject(EncodingError); + return DecodingTaskPromise::createAndReject(Exception { EncodingError, "Decoding failed"_s }); return DecodingTaskPromise::createAndResolve(audioBuffer.releaseNonNull()); }); } diff --git a/Source/WebCore/Modules/webaudio/AsyncAudioDecoder.h b/Source/WebCore/Modules/webaudio/AsyncAudioDecoder.h index 20faf4efa898..7a69d9d19c5d 100644 --- a/Source/WebCore/Modules/webaudio/AsyncAudioDecoder.h +++ b/Source/WebCore/Modules/webaudio/AsyncAudioDecoder.h @@ -24,7 +24,8 @@ #pragma once -#include "ExceptionCode.h" +#include "Exception.h" +#include #include #include @@ -32,18 +33,13 @@ namespace JSC { class ArrayBuffer; } -namespace WTF { -template -class NativePromise; -} - namespace WebCore { class AudioBuffer; // AsyncAudioDecoder asynchronously decodes audio file data from an ArrayBuffer in a worker thread. // Upon successful decoding, the DecodingTaskPromise will be resolved with the decoded AudioBuffer -// otherwise an ExceptionCode will be returned. -using DecodingTaskPromise = WTF::NativePromise, ExceptionCode, true /* isExclusive */>; +// otherwise an Exception will be returned. +using DecodingTaskPromise = WTF::NativePromise, Exception>; class AsyncAudioDecoder final { WTF_MAKE_FAST_ALLOCATED; diff --git a/Source/WebCore/Modules/webaudio/BaseAudioContext.cpp b/Source/WebCore/Modules/webaudio/BaseAudioContext.cpp index 062c709ff628..eb384263fb4c 100644 --- a/Source/WebCore/Modules/webaudio/BaseAudioContext.cpp +++ b/Source/WebCore/Modules/webaudio/BaseAudioContext.cpp @@ -304,7 +304,7 @@ void BaseAudioContext::decodeAudioData(Ref&& audioData, RefPtrreject(Exception { result.error(), "Decoding failed"_s }); + promise.value()->reject(WTFMove(result.error())); if (errorCallback) errorCallback->handleEvent(nullptr); return; diff --git a/Source/WebCore/dom/ExceptionOr.h b/Source/WebCore/dom/ExceptionOr.h index cdc616985af7..09ae01665bb3 100644 --- a/Source/WebCore/dom/ExceptionOr.h +++ b/Source/WebCore/dom/ExceptionOr.h @@ -202,7 +202,8 @@ template using TypeOrExceptionOrUnderlyingType = typename TypeOrExc namespace WTF { template struct CrossThreadCopierBase > { - typedef WebCore::ExceptionOr Type; + using Type = WebCore::ExceptionOr; + static constexpr bool IsNeeded = true; static Type copy(const Type& source) { if (source.hasException()) @@ -218,7 +219,8 @@ template struct CrossThreadCopierBase struct CrossThreadCopierBase > { - typedef WebCore::ExceptionOr Type; + using Type = WebCore::ExceptionOr; + static constexpr bool IsNeeded = true; static Type copy(const Type& source) { if (source.hasException()) diff --git a/Source/WebKit/Scripts/webkit/messages.py b/Source/WebKit/Scripts/webkit/messages.py index 35cbaebac27f..ce4cea2042f7 100644 --- a/Source/WebKit/Scripts/webkit/messages.py +++ b/Source/WebKit/Scripts/webkit/messages.py @@ -234,11 +234,11 @@ def message_to_struct_declaration(receiver, message): result.append(' using ReplyArguments = std::tuple<%s>;\n' % ', '.join([parameter.type for parameter in message.reply_parameters])) if not message.has_attribute(SYNCHRONOUS_ATTRIBUTE): if len(message.reply_parameters) == 0: - result.append(' using Promise = WTF::NativePromise;\n') + result.append(' using Promise = WTF::NativePromise;\n') elif len(message.reply_parameters) == 1: - result.append(' using Promise = WTF::NativePromise<%s, IPC::Error, true>;\n' % message.reply_parameters[0].type) + result.append(' using Promise = WTF::NativePromise<%s, IPC::Error>;\n' % message.reply_parameters[0].type) else: - result.append(' using Promise = WTF::NativePromise, IPC::Error, true>;\n' % ', '.join([parameter.type for parameter in message.reply_parameters])) + result.append(' using Promise = WTF::NativePromise, IPC::Error>;\n' % ', '.join([parameter.type for parameter in message.reply_parameters])) if len(function_parameters): result.append(' %s%s(%s)' % (len(function_parameters) == 1 and 'explicit ' or '', message.name, ', '.join([' '.join(x) for x in function_parameters]))) diff --git a/Source/WebKit/Scripts/webkit/tests/TestWithCVPixelBufferMessages.h b/Source/WebKit/Scripts/webkit/tests/TestWithCVPixelBufferMessages.h index 28cb7ee40f86..a4b0cd71bb1c 100644 --- a/Source/WebKit/Scripts/webkit/tests/TestWithCVPixelBufferMessages.h +++ b/Source/WebKit/Scripts/webkit/tests/TestWithCVPixelBufferMessages.h @@ -81,7 +81,7 @@ class ReceiveCVPixelBuffer { static IPC::MessageName asyncMessageReplyName() { return IPC::MessageName::TestWithCVPixelBuffer_ReceiveCVPixelBufferReply; } static constexpr auto callbackThread = WTF::CompletionHandlerCallThread::ConstructionThread; using ReplyArguments = std::tuple>; - using Promise = WTF::NativePromise, IPC::Error, true>; + using Promise = WTF::NativePromise, IPC::Error>; auto&& arguments() { return WTFMove(m_arguments); diff --git a/Source/WebKit/Scripts/webkit/tests/TestWithImageDataMessages.h b/Source/WebKit/Scripts/webkit/tests/TestWithImageDataMessages.h index a31afe8042ef..1b179c2e0e14 100644 --- a/Source/WebKit/Scripts/webkit/tests/TestWithImageDataMessages.h +++ b/Source/WebKit/Scripts/webkit/tests/TestWithImageDataMessages.h @@ -76,7 +76,7 @@ class ReceiveImageData { static IPC::MessageName asyncMessageReplyName() { return IPC::MessageName::TestWithImageData_ReceiveImageDataReply; } static constexpr auto callbackThread = WTF::CompletionHandlerCallThread::ConstructionThread; using ReplyArguments = std::tuple>; - using Promise = WTF::NativePromise, IPC::Error, true>; + using Promise = WTF::NativePromise, IPC::Error>; auto&& arguments() { return WTFMove(m_arguments); diff --git a/Source/WebKit/Scripts/webkit/tests/TestWithLegacyReceiverMessages.h b/Source/WebKit/Scripts/webkit/tests/TestWithLegacyReceiverMessages.h index cc52297ec6d3..2e613ee93334 100644 --- a/Source/WebKit/Scripts/webkit/tests/TestWithLegacyReceiverMessages.h +++ b/Source/WebKit/Scripts/webkit/tests/TestWithLegacyReceiverMessages.h @@ -307,7 +307,7 @@ class CreatePlugin { static IPC::MessageName asyncMessageReplyName() { return IPC::MessageName::TestWithLegacyReceiver_CreatePluginReply; } static constexpr auto callbackThread = WTF::CompletionHandlerCallThread::ConstructionThread; using ReplyArguments = std::tuple; - using Promise = WTF::NativePromise; + using Promise = WTF::NativePromise; CreatePlugin(uint64_t pluginInstanceID, const WebKit::Plugin::Parameters& parameters) : m_arguments(pluginInstanceID, parameters) { @@ -334,7 +334,7 @@ class RunJavaScriptAlert { static IPC::MessageName asyncMessageReplyName() { return IPC::MessageName::TestWithLegacyReceiver_RunJavaScriptAlertReply; } static constexpr auto callbackThread = WTF::CompletionHandlerCallThread::ConstructionThread; using ReplyArguments = std::tuple<>; - using Promise = WTF::NativePromise; + using Promise = WTF::NativePromise; RunJavaScriptAlert(uint64_t frameID, const String& message) : m_arguments(frameID, message) { @@ -361,7 +361,7 @@ class GetPlugins { static IPC::MessageName asyncMessageReplyName() { return IPC::MessageName::TestWithLegacyReceiver_GetPluginsReply; } static constexpr auto callbackThread = WTF::CompletionHandlerCallThread::ConstructionThread; using ReplyArguments = std::tuple>; - using Promise = WTF::NativePromise, IPC::Error, true>; + using Promise = WTF::NativePromise, IPC::Error>; explicit GetPlugins(bool refresh) : m_arguments(refresh) { @@ -528,7 +528,7 @@ class InterpretKeyEvent { static IPC::MessageName asyncMessageReplyName() { return IPC::MessageName::TestWithLegacyReceiver_InterpretKeyEventReply; } static constexpr auto callbackThread = WTF::CompletionHandlerCallThread::ConstructionThread; using ReplyArguments = std::tuple>; - using Promise = WTF::NativePromise, IPC::Error, true>; + using Promise = WTF::NativePromise, IPC::Error>; explicit InterpretKeyEvent(uint32_t type) : m_arguments(type) { diff --git a/Source/WebKit/Scripts/webkit/tests/TestWithSemaphoreMessages.h b/Source/WebKit/Scripts/webkit/tests/TestWithSemaphoreMessages.h index 1024ffee70ad..f3abe81e0844 100644 --- a/Source/WebKit/Scripts/webkit/tests/TestWithSemaphoreMessages.h +++ b/Source/WebKit/Scripts/webkit/tests/TestWithSemaphoreMessages.h @@ -75,7 +75,7 @@ class ReceiveSemaphore { static IPC::MessageName asyncMessageReplyName() { return IPC::MessageName::TestWithSemaphore_ReceiveSemaphoreReply; } static constexpr auto callbackThread = WTF::CompletionHandlerCallThread::ConstructionThread; using ReplyArguments = std::tuple; - using Promise = WTF::NativePromise; + using Promise = WTF::NativePromise; auto&& arguments() { return WTFMove(m_arguments); diff --git a/Source/WebKit/Scripts/webkit/tests/TestWithStreamMessages.h b/Source/WebKit/Scripts/webkit/tests/TestWithStreamMessages.h index ff43dcd614d2..da6be4080425 100644 --- a/Source/WebKit/Scripts/webkit/tests/TestWithStreamMessages.h +++ b/Source/WebKit/Scripts/webkit/tests/TestWithStreamMessages.h @@ -81,7 +81,7 @@ class SendStringAsync { static IPC::MessageName asyncMessageReplyName() { return IPC::MessageName::TestWithStream_SendStringAsyncReply; } static constexpr auto callbackThread = WTF::CompletionHandlerCallThread::ConstructionThread; using ReplyArguments = std::tuple; - using Promise = WTF::NativePromise; + using Promise = WTF::NativePromise; explicit SendStringAsync(const String& url) : m_arguments(url) { @@ -139,7 +139,7 @@ class CallWithIdentifier { static IPC::MessageName asyncMessageReplyName() { return IPC::MessageName::TestWithStream_CallWithIdentifierReply; } static constexpr auto callbackThread = WTF::CompletionHandlerCallThread::ConstructionThread; using ReplyArguments = std::tuple<>; - using Promise = WTF::NativePromise; + using Promise = WTF::NativePromise; auto&& arguments() { return WTFMove(m_arguments); diff --git a/Source/WebKit/Scripts/webkit/tests/TestWithSuperclassMessages.h b/Source/WebKit/Scripts/webkit/tests/TestWithSuperclassMessages.h index 42a7dcd0cae3..b7ab69fbedcb 100644 --- a/Source/WebKit/Scripts/webkit/tests/TestWithSuperclassMessages.h +++ b/Source/WebKit/Scripts/webkit/tests/TestWithSuperclassMessages.h @@ -81,7 +81,7 @@ class TestAsyncMessage { static IPC::MessageName asyncMessageReplyName() { return IPC::MessageName::TestWithSuperclass_TestAsyncMessageReply; } static constexpr auto callbackThread = WTF::CompletionHandlerCallThread::MainThread; using ReplyArguments = std::tuple; - using Promise = WTF::NativePromise; + using Promise = WTF::NativePromise; explicit TestAsyncMessage(WebKit::TestTwoStateEnum twoStateEnum) : m_arguments(twoStateEnum) { @@ -110,7 +110,7 @@ class TestAsyncMessageWithNoArguments { static IPC::MessageName asyncMessageReplyName() { return IPC::MessageName::TestWithSuperclass_TestAsyncMessageWithNoArgumentsReply; } static constexpr auto callbackThread = WTF::CompletionHandlerCallThread::ConstructionThread; using ReplyArguments = std::tuple<>; - using Promise = WTF::NativePromise; + using Promise = WTF::NativePromise; auto&& arguments() { return WTFMove(m_arguments); @@ -134,7 +134,7 @@ class TestAsyncMessageWithMultipleArguments { static IPC::MessageName asyncMessageReplyName() { return IPC::MessageName::TestWithSuperclass_TestAsyncMessageWithMultipleArgumentsReply; } static constexpr auto callbackThread = WTF::CompletionHandlerCallThread::ConstructionThread; using ReplyArguments = std::tuple; - using Promise = WTF::NativePromise, IPC::Error, true>; + using Promise = WTF::NativePromise, IPC::Error>; auto&& arguments() { return WTFMove(m_arguments); @@ -158,7 +158,7 @@ class TestAsyncMessageWithConnection { static IPC::MessageName asyncMessageReplyName() { return IPC::MessageName::TestWithSuperclass_TestAsyncMessageWithConnectionReply; } static constexpr auto callbackThread = WTF::CompletionHandlerCallThread::ConstructionThread; using ReplyArguments = std::tuple; - using Promise = WTF::NativePromise; + using Promise = WTF::NativePromise; explicit TestAsyncMessageWithConnection(const int& value) : m_arguments(value) { diff --git a/Source/WebKit/Scripts/webkit/tests/TestWithoutAttributesMessages.h b/Source/WebKit/Scripts/webkit/tests/TestWithoutAttributesMessages.h index 0f2e88a5ed81..6b49b21a6a24 100644 --- a/Source/WebKit/Scripts/webkit/tests/TestWithoutAttributesMessages.h +++ b/Source/WebKit/Scripts/webkit/tests/TestWithoutAttributesMessages.h @@ -307,7 +307,7 @@ class CreatePlugin { static IPC::MessageName asyncMessageReplyName() { return IPC::MessageName::TestWithoutAttributes_CreatePluginReply; } static constexpr auto callbackThread = WTF::CompletionHandlerCallThread::ConstructionThread; using ReplyArguments = std::tuple; - using Promise = WTF::NativePromise; + using Promise = WTF::NativePromise; CreatePlugin(uint64_t pluginInstanceID, const WebKit::Plugin::Parameters& parameters) : m_arguments(pluginInstanceID, parameters) { @@ -334,7 +334,7 @@ class RunJavaScriptAlert { static IPC::MessageName asyncMessageReplyName() { return IPC::MessageName::TestWithoutAttributes_RunJavaScriptAlertReply; } static constexpr auto callbackThread = WTF::CompletionHandlerCallThread::ConstructionThread; using ReplyArguments = std::tuple<>; - using Promise = WTF::NativePromise; + using Promise = WTF::NativePromise; RunJavaScriptAlert(uint64_t frameID, const String& message) : m_arguments(frameID, message) { @@ -361,7 +361,7 @@ class GetPlugins { static IPC::MessageName asyncMessageReplyName() { return IPC::MessageName::TestWithoutAttributes_GetPluginsReply; } static constexpr auto callbackThread = WTF::CompletionHandlerCallThread::ConstructionThread; using ReplyArguments = std::tuple>; - using Promise = WTF::NativePromise, IPC::Error, true>; + using Promise = WTF::NativePromise, IPC::Error>; explicit GetPlugins(bool refresh) : m_arguments(refresh) { @@ -528,7 +528,7 @@ class InterpretKeyEvent { static IPC::MessageName asyncMessageReplyName() { return IPC::MessageName::TestWithoutAttributes_InterpretKeyEventReply; } static constexpr auto callbackThread = WTF::CompletionHandlerCallThread::ConstructionThread; using ReplyArguments = std::tuple>; - using Promise = WTF::NativePromise, IPC::Error, true>; + using Promise = WTF::NativePromise, IPC::Error>; explicit InterpretKeyEvent(uint32_t type) : m_arguments(type) { diff --git a/Source/WebKit/Scripts/webkit/tests/TestWithoutUsingIPCConnectionMessages.h b/Source/WebKit/Scripts/webkit/tests/TestWithoutUsingIPCConnectionMessages.h index 70119ac4f05d..d66e21b65311 100644 --- a/Source/WebKit/Scripts/webkit/tests/TestWithoutUsingIPCConnectionMessages.h +++ b/Source/WebKit/Scripts/webkit/tests/TestWithoutUsingIPCConnectionMessages.h @@ -70,7 +70,7 @@ class MessageWithoutArgumentAndEmptyReply { static IPC::MessageName asyncMessageReplyName() { return IPC::MessageName::TestWithoutUsingIPCConnection_MessageWithoutArgumentAndEmptyReplyReply; } static constexpr auto callbackThread = WTF::CompletionHandlerCallThread::ConstructionThread; using ReplyArguments = std::tuple<>; - using Promise = WTF::NativePromise; + using Promise = WTF::NativePromise; auto&& arguments() { return WTFMove(m_arguments); @@ -92,7 +92,7 @@ class MessageWithoutArgumentAndReplyWithArgument { static IPC::MessageName asyncMessageReplyName() { return IPC::MessageName::TestWithoutUsingIPCConnection_MessageWithoutArgumentAndReplyWithArgumentReply; } static constexpr auto callbackThread = WTF::CompletionHandlerCallThread::ConstructionThread; using ReplyArguments = std::tuple; - using Promise = WTF::NativePromise; + using Promise = WTF::NativePromise; auto&& arguments() { return WTFMove(m_arguments); @@ -137,7 +137,7 @@ class MessageWithArgumentAndEmptyReply { static IPC::MessageName asyncMessageReplyName() { return IPC::MessageName::TestWithoutUsingIPCConnection_MessageWithArgumentAndEmptyReplyReply; } static constexpr auto callbackThread = WTF::CompletionHandlerCallThread::ConstructionThread; using ReplyArguments = std::tuple<>; - using Promise = WTF::NativePromise; + using Promise = WTF::NativePromise; explicit MessageWithArgumentAndEmptyReply(const String& argument) : m_arguments(argument) { @@ -164,7 +164,7 @@ class MessageWithArgumentAndReplyWithArgument { static IPC::MessageName asyncMessageReplyName() { return IPC::MessageName::TestWithoutUsingIPCConnection_MessageWithArgumentAndReplyWithArgumentReply; } static constexpr auto callbackThread = WTF::CompletionHandlerCallThread::ConstructionThread; using ReplyArguments = std::tuple; - using Promise = WTF::NativePromise; + using Promise = WTF::NativePromise; explicit MessageWithArgumentAndReplyWithArgument(const String& argument) : m_arguments(argument) { diff --git a/Tools/TestWebKitAPI/Tests/IPC/IPCTestUtilities.h b/Tools/TestWebKitAPI/Tests/IPC/IPCTestUtilities.h index 09ef203783b7..a4d981680ad8 100644 --- a/Tools/TestWebKitAPI/Tests/IPC/IPCTestUtilities.h +++ b/Tools/TestWebKitAPI/Tests/IPC/IPCTestUtilities.h @@ -65,7 +65,7 @@ struct MockTestMessageWithAsyncReply1 { static constexpr IPC::MessageName asyncMessageReplyName() { return IPC::MessageName::WebPage_GetBytecodeProfileReply; } std::tuple<> arguments() { return { }; } using ReplyArguments = std::tuple; - using Promise = WTF::NativePromise; + using Promise = WTF::NativePromise; }; class MockConnectionClient final : public IPC::Connection::Client { diff --git a/Tools/TestWebKitAPI/Tests/WTF/NativePromise.cpp b/Tools/TestWebKitAPI/Tests/WTF/NativePromise.cpp index 591483265789..3d5cc1b53d32 100644 --- a/Tools/TestWebKitAPI/Tests/WTF/NativePromise.cpp +++ b/Tools/TestWebKitAPI/Tests/WTF/NativePromise.cpp @@ -49,8 +49,8 @@ using namespace WTF; namespace TestWebKitAPI { -using TestPromise = NativePromise; -using TestPromiseExcl = NativePromise; +using TestPromise = NativePromise; +using TestPromiseExcl = NativePromise; class WorkQueueWithShutdown : public WorkQueue { public: @@ -293,7 +293,7 @@ TEST(NativePromise, GenericPromise) // You can mix & match promise types and chain them together. // Producer also accepts syntax using operator-> for consistency with a consumer's promise. GenericPromise::Producer p5; - using MyPromise = NativePromise; + using MyPromise = NativePromise; p5->whenSettled(queue, [](GenericPromise::Result result) { EXPECT_TRUE(result.has_value()); @@ -313,7 +313,7 @@ TEST(NativePromise, PromiseRequest) { // We declare the Request holder before using the runLoop to ensure it stays in scope for the entire run. // ASSERTION FAILED: !m_request - using MyPromise = NativePromise; + using MyPromise = NativePromise; NativePromiseRequest request1; runInCurrentRunLoop([&](auto& runLoop) { @@ -777,7 +777,7 @@ TEST(NativePromise, Chaining) TEST(NativePromise, MoveOnlyType) { - using MyPromise = NativePromise, bool, true>; + using MyPromise = NativePromise, std::unique_ptr>; AutoWorkQueue awq; auto queue = awq.queue(); @@ -794,14 +794,284 @@ TEST(NativePromise, MoveOnlyType) [queue](MyPromise::Result&& val) { EXPECT_TRUE(val.has_value()); EXPECT_EQ(87, *(val.value())); + }); + + MyPromise::createAndReject(makeUniqueWithoutFastMallocCheck(87))->whenSettled(queue, + [queue](MyPromise::Result&& val) { + EXPECT_FALSE(val.has_value()); + EXPECT_EQ(87, *(val.error())); + queue->beginShutdown(); + }); +} + +TEST(NativePromise, WTFString) +{ + using MyPromise = NativePromise; + + AutoWorkQueue awq2; + auto queue2 = awq2.queue(); + + AutoWorkQueue awq; + auto queue = awq.queue(); + + MyPromise::createAndResolve("hello"_s)->then(queue, + [](String&& val) { + EXPECT_EQ(String("hello"_s), val); + }, + [] { + EXPECT_TRUE(false); + }); + + MyPromise::createAndResolve("hello"_s)->whenSettled(queue, + [queue](MyPromise::Result&& val) { + EXPECT_TRUE(val.has_value()); + EXPECT_EQ(String("hello"_s), val.value()); + EXPECT_TRUE(val.value().isSafeToSendToAnotherThread()); + }); + + MyPromise::createAndReject("error"_s)->whenSettled(queue, + [queue](MyPromise::Result&& val) { + EXPECT_FALSE(val.has_value()); + EXPECT_EQ(String("error"_s), val.error()); + EXPECT_TRUE(val.error().isSafeToSendToAnotherThread()); + }); + + MyPromise::createAndResolve(String("hello"_s))->then(queue, + [](String&& val) { + EXPECT_EQ(String("hello"_s), val); + EXPECT_TRUE(val.isSafeToSendToAnotherThread()); + }, + [] { + EXPECT_TRUE(false); + }); + + // Check that we can receive the value by const reference too. + MyPromise::createAndResolve(String("hello"_s))->then(queue, + [](const String& val) { + EXPECT_EQ(String("hello"_s), val); + EXPECT_TRUE(val.isSafeToSendToAnotherThread()); + }, + [] { + EXPECT_TRUE(false); + }); + + // Can pass object implecitly convertible to ResolveValueType + MyPromise::createAndResolve(AtomString("hello"_s))->then(queue, + [](String&& val) { + EXPECT_EQ(String("hello"_s), val); + EXPECT_TRUE(val.isSafeToSendToAnotherThread()); + }, + [] { + EXPECT_TRUE(false); + }); + + MyPromise::createAndResolve(AtomString("hello"_s))->then(queue, + [](const String& val) { + EXPECT_EQ(String("hello"_s), val); + EXPECT_TRUE(val.isSafeToSendToAnotherThread()); + }, + [] { + EXPECT_TRUE(false); + }); + + MyPromise::createAndResolve(AtomString("hello"_s))->then(queue, + [](String val) { + EXPECT_EQ(String("hello"_s), val); + EXPECT_TRUE(val.isSafeToSendToAnotherThread()); + }, + [] { + EXPECT_TRUE(false); + }); + + MyPromise::createAndResolve(String("hello"_s))->whenSettled(queue, + [](MyPromise::Result&& val) { + EXPECT_TRUE(val.has_value()); + EXPECT_TRUE(val.value().isSafeToSendToAnotherThread()); + EXPECT_EQ(String("hello"_s), val.value()); + }); + + MyPromise::createAndResolve(String("hello"_s))->whenSettled(queue, + [](MyPromise::Result val) { + EXPECT_TRUE(val.has_value()); + EXPECT_TRUE(val.value().isSafeToSendToAnotherThread()); + EXPECT_EQ(String("hello"_s), val.value()); + }); + + MyPromise::createAndResolve(String("hello"_s))->whenSettled(queue, + [](const MyPromise::Result& val) { + EXPECT_TRUE(val.has_value()); + EXPECT_TRUE(val.value().isSafeToSendToAnotherThread()); + EXPECT_EQ(String("hello"_s), val.value()); + }); + + MyPromise::createAndReject(String("error"_s))->whenSettled(queue, + [](MyPromise::Result&& val) { + EXPECT_FALSE(val.has_value()); + EXPECT_TRUE(val.error().isSafeToSendToAnotherThread()); + EXPECT_EQ(String("error"_s), val.error()); + }); + + MyPromise::createAndResolve(AtomString("hello"_s))->whenSettled(queue, + [](MyPromise::Result&& val) { + EXPECT_TRUE(val.has_value()); + EXPECT_TRUE(val.value().isSafeToSendToAnotherThread()); + EXPECT_EQ(String("hello"_s), val.value()); + return MyPromise::createAndResolveOrReject(WTFMove(val)); + })->whenSettled(queue2, + [](MyPromise::Result val) { + EXPECT_TRUE(val.has_value()); + EXPECT_TRUE(val.value().isSafeToSendToAnotherThread()); + EXPECT_EQ(String("hello"_s), val.value()); + }); + + MyPromise::createAndResolve(AtomString("hello"_s))->whenSettled(queue, + [queue](MyPromise::Result val) { + EXPECT_TRUE(val.has_value()); + EXPECT_TRUE(val.value().isSafeToSendToAnotherThread()); + EXPECT_EQ(String("hello"_s), val.value()); queue->beginShutdown(); + // Don't move the result to make sure we get a new isolatedCopy. + return MyPromise::createAndResolveOrReject(val); + })->whenSettled(queue2, + [queue2](MyPromise::Result val) { + EXPECT_TRUE(val.has_value()); + EXPECT_TRUE(val.value().isSafeToSendToAnotherThread()); + EXPECT_EQ(String("hello"_s), val.value()); + queue2->beginShutdown(); + }); +} + +TEST(NativePromise, WTFStringWithDelayedResolve) +{ + using MyPromise = NativePromise; + + // The following steps runs strictly serially. + // 1. We create a promise on the main thread. + // 2. Dispatch a task that will `whenSettled()` on that promise on WorkQueue2. + // 3. We resolve on the main thread the promise with an AtomString. + // 4. Resolver will be called on WorkQueue1 and check that the string content is correct and the string created on the main thread was safely moved. + + AutoWorkQueue awq1; + awq1.queue(); + auto queue1 = awq1.queue(); + MyPromise::Producer producer; + bool hasRun = false; // AutoWorkQueue guarantees that there can't be concurrent accesses to hasRun. + { + AutoWorkQueue awq2; + auto queue2 = awq2.queue(); + queue2->dispatch([queue1, queue2, promise = Ref { producer }, &hasRun] { + promise->whenSettled(queue1, + [queue1](MyPromise::Result val) { + EXPECT_TRUE(val.has_value()); + EXPECT_TRUE(val.value().isSafeToSendToAnotherThread()); + EXPECT_EQ(String("hello"_s), val.value()); + queue1->beginShutdown(); + }); + hasRun = true; + queue2->beginShutdown(); }); + } + EXPECT_TRUE(hasRun); + producer.resolve(AtomString("hello"_s)); } +TEST(NativePromise, NonExclusiveWithCrossThreadCopy) +{ + int resolution = 0; + { + AutoWorkQueue awq; + auto queue = awq.queue(); + // If you replace PromiseOption::WithCrossThreadCopy with PromiseOption::WithoutCrossThreadCopy, this test will crash due to the AtomString being deleted on the target queue. + using MyPromise = NativePromise, bool, PromiseOption::NonExclusive | PromiseOption::WithCrossThreadCopy>; + static_assert(CrossThreadCopier>::IsNeeded); + MyPromise::Producer producer; + Ref p = producer; + p->whenSettled(queue, [&resolution] (const MyPromise::Result& val) { + EXPECT_TRUE(val.has_value()); + EXPECT_TRUE(val.value().has_value()); + EXPECT_TRUE(val.value().value().isSafeToSendToAnotherThread()); + EXPECT_EQ(String("that worked"_s), val.value().value()); + resolution++; + }); + p->whenSettled(queue, [&resolution] (MyPromise::Result val) { + EXPECT_TRUE(val.has_value()); + EXPECT_TRUE(val.value().has_value()); + // Being a non-exclusive promise, the value is passed by const reference, so we copied the object in val. + EXPECT_TRUE(!val.value().value().isSafeToSendToAnotherThread()); + EXPECT_EQ(String("that worked"_s), val.value().value()); + resolution++; + }); + p->whenSettled(queue, [queue, &resolution] (const MyPromise::Result& val) { + EXPECT_TRUE(val.has_value()); + EXPECT_TRUE(val.value().has_value()); + // The previous whenSettled() has run already, and the object was derefed. + EXPECT_TRUE(val.value().value().isSafeToSendToAnotherThread()); + EXPECT_EQ(String("that worked"_s), val.value().value()); + resolution++; + queue->beginShutdown(); + }); + producer.resolve(String(AtomString("that worked"_s))); + } + EXPECT_EQ(3, resolution); +} + +TEST(NativePromise, WithCrossThreadCopyType) +{ + using MyPromiseWithString = NativePromise; + static_assert(MyPromiseWithString::WithAutomaticCrossThreadCopy); + static_assert(CrossThreadCopier::IsNeeded); + // Check that if making a NativePromise with an AtomString, you actually get a String + static_assert(std::is_same_v); + + using MyPromiseWithoutString = NativePromise; + static_assert(!MyPromiseWithoutString::WithAutomaticCrossThreadCopy); + + using MyPromiseWithArrayOfString = NativePromise, bool>; + static_assert(MyPromiseWithArrayOfString::WithAutomaticCrossThreadCopy); + + using MyNonExclusivePromise = NativePromise, bool, PromiseOption::Default | PromiseOption::NonExclusive>; + // No need for crossThreadProxy for a Vector not containing a type with isolatedCopy() method. + static_assert(!MyNonExclusivePromise::WithAutomaticCrossThreadCopy); +} + +TEST(NativePromise, ExpectedWithString) +{ + using MyPromise = NativePromise, int>; + + AutoWorkQueue awq; + auto queue = awq.queue(); + + MyPromise::createAndResolve(String("hello"_s))->then(queue, + [](MyPromise::ResolveValueType&& val) { + EXPECT_TRUE(val.has_value()); + EXPECT_EQ(String("hello"_s), val.value()); + EXPECT_TRUE(val.value().isSafeToSendToAnotherThread()); + }, + [] { + EXPECT_TRUE(false); + }); + + MyPromise::createAndResolve(String("hello"_s))->whenSettled(queue, + [queue](MyPromise::Result&& val) { + EXPECT_TRUE(val.has_value()); + EXPECT_EQ(String("hello"_s), val.value()); + EXPECT_TRUE(val.value().value().isSafeToSendToAnotherThread()); + }); + + Expected error = Unexpected("error"_s); + MyPromise::createAndResolve(WTFMove(error))->whenSettled(queue, + [queue](MyPromise::Result&& val) { + EXPECT_TRUE(val.has_value()); + EXPECT_FALSE(val.value().has_value()); + EXPECT_EQ(String("error"_s), val.value().error()); + EXPECT_TRUE(val.value().error().isSafeToSendToAnotherThread()); + queue->beginShutdown(); + }); +} TEST(NativePromise, HeterogeneousChaining) { - using Promise1 = NativePromise, bool, true>; - using Promise2 = NativePromise, bool, true>; + using Promise1 = NativePromise, bool>; + using Promise2 = NativePromise, bool>; NativePromiseRequest holder; From e26a784c02c9912da618b5311a5877b4e5a6ef71 Mon Sep 17 00:00:00 2001 From: Ben Schwartz Date: Wed, 4 Oct 2023 16:25:29 -0700 Subject: [PATCH 04/16] [Gardening]: REGRESSION(iOS17/Sonoma): 8 WebCryptoAPI tests are constantly crashing. rdar://116490690 https://bugs.webkit.org/show_bug.cgi?id=262663 Unreviewed test gardening. * LayoutTests/platform/ios-16/TestExpectations: * LayoutTests/platform/ios/TestExpectations: * LayoutTests/platform/mac/TestExpectations: Canonical link: https://commits.webkit.org/268881@main --- LayoutTests/platform/ios-16/TestExpectations | 10 ++++++++++ LayoutTests/platform/ios/TestExpectations | 10 ++++++++++ LayoutTests/platform/mac/TestExpectations | 10 ++++++++++ 3 files changed, 30 insertions(+) diff --git a/LayoutTests/platform/ios-16/TestExpectations b/LayoutTests/platform/ios-16/TestExpectations index 6bcf7865ecd0..f5e9a784737e 100644 --- a/LayoutTests/platform/ios-16/TestExpectations +++ b/LayoutTests/platform/ios-16/TestExpectations @@ -20,3 +20,13 @@ accessibility/ios-simulator/inline-prediction-attributed-string.html [ Skip ] # Only supported with iOS 17 and later. media/media-webm-opus-variable-length.html [ Failure ] + +# webkit.org/b/262663 (REGRESSION(iOS17/Sonoma): 8 WebCryptoAPI tests are constantly crashing.) +imported/w3c/web-platform-tests/WebCryptoAPI/generateKey/failures_X25519.https.any.html [ Pass ] +imported/w3c/web-platform-tests/WebCryptoAPI/generateKey/failures_X25519.https.any.worker.html [ Pass ] +imported/w3c/web-platform-tests/WebCryptoAPI/generateKey/successes_X25519.https.any.html [ Pass ] +imported/w3c/web-platform-tests/WebCryptoAPI/generateKey/successes_X25519.https.any.worker.html [ Pass ] +imported/w3c/web-platform-tests/WebCryptoAPI/import_export/okp_importKey.https.any.html [ Pass ] +imported/w3c/web-platform-tests/WebCryptoAPI/import_export/okp_importKey.https.any.worker.html [ Pass ] +imported/w3c/web-platform-tests/WebCryptoAPI/import_export/okp_importKey_failures_X25519.https.any.html [ Pass ] +imported/w3c/web-platform-tests/WebCryptoAPI/import_export/okp_importKey_failures_X25519.https.any.worker.html [ Pass ] diff --git a/LayoutTests/platform/ios/TestExpectations b/LayoutTests/platform/ios/TestExpectations index 5e964725c8b1..cfbc4b25192e 100644 --- a/LayoutTests/platform/ios/TestExpectations +++ b/LayoutTests/platform/ios/TestExpectations @@ -4649,3 +4649,13 @@ imported/w3c/web-platform-tests/css/css-fonts/font-palette-modify.html [ ImageOn imported/w3c/web-platform-tests/css/css-fonts/font-palette-remove.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-fonts/palette-values-rule-add.html [ ImageOnlyFailure ] imported/w3c/web-platform-tests/css/css-fonts/palette-values-rule-delete.html [ ImageOnlyFailure ] + +# webkit.org/b/262663 (REGRESSION(iOS17/Sonoma): 8 WebCryptoAPI tests are constantly crashing.) +imported/w3c/web-platform-tests/WebCryptoAPI/generateKey/failures_X25519.https.any.html [ Crash ] +imported/w3c/web-platform-tests/WebCryptoAPI/generateKey/failures_X25519.https.any.worker.html [ Crash ] +imported/w3c/web-platform-tests/WebCryptoAPI/generateKey/successes_X25519.https.any.html [ Crash ] +imported/w3c/web-platform-tests/WebCryptoAPI/generateKey/successes_X25519.https.any.worker.html [ Crash ] +imported/w3c/web-platform-tests/WebCryptoAPI/import_export/okp_importKey.https.any.html [ Crash ] +imported/w3c/web-platform-tests/WebCryptoAPI/import_export/okp_importKey.https.any.worker.html [ Crash ] +imported/w3c/web-platform-tests/WebCryptoAPI/import_export/okp_importKey_failures_X25519.https.any.html [ Crash ] +imported/w3c/web-platform-tests/WebCryptoAPI/import_export/okp_importKey_failures_X25519.https.any.worker.html [ Crash ] diff --git a/LayoutTests/platform/mac/TestExpectations b/LayoutTests/platform/mac/TestExpectations index 98966a5b8fac..10039033017c 100644 --- a/LayoutTests/platform/mac/TestExpectations +++ b/LayoutTests/platform/mac/TestExpectations @@ -2886,3 +2886,13 @@ webkit.org/b/261306 imported/w3c/web-platform-tests/content-security-policy/repo # rdar://114294654 (REGRESSION (265615@main): [ Sonoma ] fast/attachment/cocoa/wide-attachment-rendering.html is a constant failure) [ Sonoma+ ] fast/attachment/cocoa/wide-attachment-rendering.html [ Failure ] + +# webkit.org/b/262663 (REGRESSION(iOS17/Sonoma): 8 WebCryptoAPI tests are constantly crashing.) +[ Sonoma ] imported/w3c/web-platform-tests/WebCryptoAPI/generateKey/failures_X25519.https.any.html [ Crash ] +[ Sonoma ] imported/w3c/web-platform-tests/WebCryptoAPI/generateKey/failures_X25519.https.any.worker.html [ Crash ] +[ Sonoma ] imported/w3c/web-platform-tests/WebCryptoAPI/generateKey/successes_X25519.https.any.html [ Crash ] +[ Sonoma ] imported/w3c/web-platform-tests/WebCryptoAPI/generateKey/successes_X25519.https.any.worker.html [ Crash ] +[ Sonoma ] imported/w3c/web-platform-tests/WebCryptoAPI/import_export/okp_importKey.https.any.html [ Crash ] +[ Sonoma ] imported/w3c/web-platform-tests/WebCryptoAPI/import_export/okp_importKey.https.any.worker.html [ Crash ] +[ Sonoma ] imported/w3c/web-platform-tests/WebCryptoAPI/import_export/okp_importKey_failures_X25519.https.any.html [ Crash ] +[ Sonoma ] imported/w3c/web-platform-tests/WebCryptoAPI/import_export/okp_importKey_failures_X25519.https.any.worker.html [ Crash ] From a776b382b039176264e7a49623eefc20bf87b4a2 Mon Sep 17 00:00:00 2001 From: Wenson Hsieh Date: Wed, 4 Oct 2023 16:31:54 -0700 Subject: [PATCH 05/16] REGRESSION (266680@main): iOS PLUM ~0.75% increased memory use https://bugs.webkit.org/show_bug.cgi?id=262575 rdar://114845469 Reviewed by Per Arne Vollan and Ryosuke Niwa. Add a runtime-enabled setting to control whether or not the opportunistic task scheduler should be enabled for the purposes of opportunistic sweeping and GC. This currently causes a memory regression on PLUM, specifically on certain iPhone models. * Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml: * Source/WebCore/page/OpportunisticTaskScheduler.cpp: (WebCore::OpportunisticTaskScheduler::runLoopObserverFired): Canonical link: https://commits.webkit.org/268882@main --- .../Preferences/UnifiedWebPreferences.yaml | 16 ++++++++++++++++ .../WebCore/page/OpportunisticTaskScheduler.cpp | 3 +++ 2 files changed, 19 insertions(+) diff --git a/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml b/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml index 96f1cf72103b..0497568acddb 100644 --- a/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml +++ b/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml @@ -4914,6 +4914,22 @@ OffscreenCanvasInWorkersEnabled: "PLATFORM(COCOA)": true default: false +# FIXME: Reenable this on iOS once we can mitigate impact on memory use. +OpportunisticSweepingAndGarbageCollectionEnabled: + type: bool + status: internal + humanReadableName: "Opportunistic Sweeping and GC" + humanReadableDescription: "Enable Opportunistic Sweeping and GC" + category: javascript + defaultValue: + WebKitLegacy: + default: false + WebKit: + "PLATFORM(IOS_FAMILY)": false + default: true + WebCore: + default: false + OpusDecoderEnabled: type: bool status: mature diff --git a/Source/WebCore/page/OpportunisticTaskScheduler.cpp b/Source/WebCore/page/OpportunisticTaskScheduler.cpp index 445a1dd85308..e217e186fd2c 100644 --- a/Source/WebCore/page/OpportunisticTaskScheduler.cpp +++ b/Source/WebCore/page/OpportunisticTaskScheduler.cpp @@ -101,6 +101,9 @@ void OpportunisticTaskScheduler::runLoopObserverFired() if (UNLIKELY(!page)) return; + if (!page->settings().opportunisticSweepingAndGarbageCollectionEnabled()) + return; + page->performOpportunisticallyScheduledTasks(deadline); } From b1787b8f7ddadd6efc3312f9a7dfdae460e142b6 Mon Sep 17 00:00:00 2001 From: Ryosuke Niwa Date: Wed, 4 Oct 2023 17:10:35 -0700 Subject: [PATCH 06/16] Make InteractionInformationRequest use generated serialization https://bugs.webkit.org/show_bug.cgi?id=262639 Reviewed by Alex Christensen. Use the generated serialization for InteractionInformationRequest. * Source/WebKit/DerivedSources-input.xcfilelist: * Source/WebKit/DerivedSources.make: * Source/WebKit/Shared/ios/InteractionInformationRequest.cpp: (WebKit::InteractionInformationRequest::encode const): Deleted. (WebKit::InteractionInformationRequest::decode): Deleted. * Source/WebKit/Shared/ios/InteractionInformationRequest.h: (WebKit::InteractionInformationRequest::InteractionInformationRequest): * Source/WebKit/Shared/ios/InteractionInformationRequest.serialization.in: Added. Canonical link: https://commits.webkit.org/268883@main --- Source/WebKit/DerivedSources-input.xcfilelist | 1 + Source/WebKit/DerivedSources.make | 1 + .../ios/InteractionInformationRequest.cpp | 45 ------------------- .../ios/InteractionInformationRequest.h | 19 ++++++-- ...ractionInformationRequest.serialization.in | 39 ++++++++++++++++ 5 files changed, 56 insertions(+), 49 deletions(-) create mode 100644 Source/WebKit/Shared/ios/InteractionInformationRequest.serialization.in diff --git a/Source/WebKit/DerivedSources-input.xcfilelist b/Source/WebKit/DerivedSources-input.xcfilelist index f444590d08e8..d04d49cd0fae 100644 --- a/Source/WebKit/DerivedSources-input.xcfilelist +++ b/Source/WebKit/DerivedSources-input.xcfilelist @@ -326,6 +326,7 @@ $(PROJECT_DIR)/Shared/WebsitePoliciesData.serialization.in $(PROJECT_DIR)/Shared/XR/XRSystem.serialization.in $(PROJECT_DIR)/Shared/ios/DynamicViewportSizeUpdate.serialization.in $(PROJECT_DIR)/Shared/ios/InteractionInformationAtPosition.serialization.in +$(PROJECT_DIR)/Shared/ios/InteractionInformationRequest.serialization.in $(PROJECT_DIR)/Shared/ios/WebAutocorrectionContext.serialization.in $(PROJECT_DIR)/Shared/ios/WebAutocorrectionData.serialization.in $(PROJECT_DIR)/Shared/mac/PDFContextMenuItem.serialization.in diff --git a/Source/WebKit/DerivedSources.make b/Source/WebKit/DerivedSources.make index 605294ec1555..4ec0ab87b078 100644 --- a/Source/WebKit/DerivedSources.make +++ b/Source/WebKit/DerivedSources.make @@ -521,6 +521,7 @@ SERIALIZATION_DESCRIPTION_FILES = \ Shared/GoToBackForwardItemParameters.serialization.in \ Shared/ios/DynamicViewportSizeUpdate.serialization.in \ Shared/ios/InteractionInformationAtPosition.serialization.in \ + Shared/ios/InteractionInformationRequest.serialization.in \ Shared/ios/WebAutocorrectionContext.serialization.in \ Shared/ios/WebAutocorrectionData.serialization.in \ Shared/LayerTreeContext.serialization.in \ diff --git a/Source/WebKit/Shared/ios/InteractionInformationRequest.cpp b/Source/WebKit/Shared/ios/InteractionInformationRequest.cpp index 050b870bd7bb..19718398c2a0 100644 --- a/Source/WebKit/Shared/ios/InteractionInformationRequest.cpp +++ b/Source/WebKit/Shared/ios/InteractionInformationRequest.cpp @@ -33,51 +33,6 @@ namespace WebKit { #if PLATFORM(IOS_FAMILY) -void InteractionInformationRequest::encode(IPC::Encoder& encoder) const -{ - encoder << point; - encoder << includeSnapshot; - encoder << includeLinkIndicator; - encoder << includeCaretContext; - encoder << includeHasDoubleClickHandler; - encoder << includeImageData; - encoder << gatherAnimations; - encoder << linkIndicatorShouldHaveLegacyMargins; - encoder << disallowUserAgentShadowContent; -} - -bool InteractionInformationRequest::decode(IPC::Decoder& decoder, InteractionInformationRequest& result) -{ - if (!decoder.decode(result.point)) - return false; - - if (!decoder.decode(result.includeSnapshot)) - return false; - - if (!decoder.decode(result.includeLinkIndicator)) - return false; - - if (!decoder.decode(result.includeCaretContext)) - return false; - - if (!decoder.decode(result.includeHasDoubleClickHandler)) - return false; - - if (!decoder.decode(result.includeImageData)) - return false; - - if (!decoder.decode(result.gatherAnimations)) - return false; - - if (!decoder.decode(result.linkIndicatorShouldHaveLegacyMargins)) - return false; - - if (!decoder.decode(result.disallowUserAgentShadowContent)) - return false; - - return true; -} - bool InteractionInformationRequest::isValidForRequest(const InteractionInformationRequest& other, int radius) const { if (other.includeSnapshot && !includeSnapshot) diff --git a/Source/WebKit/Shared/ios/InteractionInformationRequest.h b/Source/WebKit/Shared/ios/InteractionInformationRequest.h index c3ddf1495713..b8cc9f064365 100644 --- a/Source/WebKit/Shared/ios/InteractionInformationRequest.h +++ b/Source/WebKit/Shared/ios/InteractionInformationRequest.h @@ -51,15 +51,26 @@ struct InteractionInformationRequest { InteractionInformationRequest() { } explicit InteractionInformationRequest(WebCore::IntPoint point) + : point(point) + { + } + + explicit InteractionInformationRequest(WebCore::IntPoint point, bool includeSnapshot, bool includeLinkIndicator, bool includeCaretContext, bool includeHasDoubleClickHandler, + bool includeImageData, bool gatherAnimations, bool linkIndicatorShouldHaveLegacyMargins, bool disallowUserAgentShadowContent) + : point(point) + , includeSnapshot(includeSnapshot) + , includeLinkIndicator(includeLinkIndicator) + , includeCaretContext(includeCaretContext) + , includeHasDoubleClickHandler(includeHasDoubleClickHandler) + , includeImageData(includeImageData) + , gatherAnimations(gatherAnimations) + , linkIndicatorShouldHaveLegacyMargins(linkIndicatorShouldHaveLegacyMargins) + , disallowUserAgentShadowContent(disallowUserAgentShadowContent) { - this->point = point; } bool isValidForRequest(const InteractionInformationRequest&, int radius = 0) const; bool isApproximatelyValidForRequest(const InteractionInformationRequest&, int radius) const; - - void encode(IPC::Encoder&) const; - static WARN_UNUSED_RETURN bool decode(IPC::Decoder&, InteractionInformationRequest&); }; } diff --git a/Source/WebKit/Shared/ios/InteractionInformationRequest.serialization.in b/Source/WebKit/Shared/ios/InteractionInformationRequest.serialization.in new file mode 100644 index 000000000000..2aa8b28b8d7f --- /dev/null +++ b/Source/WebKit/Shared/ios/InteractionInformationRequest.serialization.in @@ -0,0 +1,39 @@ +# Copyright (C) 2023 Apple Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#if PLATFORM(IOS_FAMILY) + +struct WebKit::InteractionInformationRequest { + WebCore::IntPoint point; + + bool includeSnapshot; + bool includeLinkIndicator; + bool includeCaretContext; + bool includeHasDoubleClickHandler; + bool includeImageData; + + bool gatherAnimations; + bool linkIndicatorShouldHaveLegacyMargins; + bool disallowUserAgentShadowContent; +}; + +#endif From d265fb0d526aa8120a208bf62dc5a1e160400cc7 Mon Sep 17 00:00:00 2001 From: Mike Wyrzykowski Date: Wed, 4 Oct 2023 17:45:58 -0700 Subject: [PATCH 07/16] [WebGPU] built-in arrayLength is not supported https://bugs.webkit.org/show_bug.cgi?id=262644 Reviewed by Dan Glastonbury. Add lengths to all buffers in a bind group so we can support arrayLength() inside the shader. * Source/WebGPU/WGSL/WGSL.h: * Source/WebGPU/WebGPU/BindGroup.mm: (WebGPU::Device::createBindGroup): * Source/WebGPU/WebGPU/BindGroupLayout.h: * Source/WebGPU/WebGPU/BindGroupLayout.mm: (WebGPU::Device::createBindGroupLayout): (WebGPU::BindGroupLayout::bufferSizeIndexForEntryIndex const): * Source/WebGPU/WebGPU/ShaderModule.mm: (WebGPU::ShaderModule::convertPipelineLayout): Canonical link: https://commits.webkit.org/268884@main --- Source/WebGPU/WGSL/WGSL.h | 5 ++++ Source/WebGPU/WebGPU/BindGroup.mm | 3 +++ Source/WebGPU/WebGPU/BindGroupLayout.h | 2 ++ Source/WebGPU/WebGPU/BindGroupLayout.mm | 31 +++++++++++++++++++++++++ Source/WebGPU/WebGPU/ShaderModule.mm | 3 +++ 5 files changed, 44 insertions(+) diff --git a/Source/WebGPU/WGSL/WGSL.h b/Source/WebGPU/WGSL/WGSL.h index d67c232baafa..d89011ee6bbc 100644 --- a/Source/WebGPU/WGSL/WGSL.h +++ b/Source/WebGPU/WGSL/WGSL.h @@ -151,10 +151,15 @@ struct BindGroupLayoutEntry { using BindingMember = std::variant; BindingMember bindingMember; std::optional vertexArgumentBufferIndex; + std::optional vertexArgumentBufferSizeIndex; std::optional vertexBufferDynamicOffset; + std::optional fragmentArgumentBufferIndex; + std::optional fragmentArgumentBufferSizeIndex; std::optional fragmentBufferDynamicOffset; + std::optional computeArgumentBufferIndex; + std::optional computeArgumentBufferSizeIndex; std::optional computeBufferDynamicOffset; }; diff --git a/Source/WebGPU/WebGPU/BindGroup.mm b/Source/WebGPU/WebGPU/BindGroup.mm index dd76865b209b..e4a03c3c2ea5 100644 --- a/Source/WebGPU/WebGPU/BindGroup.mm +++ b/Source/WebGPU/WebGPU/BindGroup.mm @@ -478,6 +478,7 @@ static MTLResourceUsage resourceUsageForBindingAcccess(BindGroupLayout::BindingA continue; auto index = bindGroupLayout.argumentBufferIndexForEntryIndex(entry.binding, stage); + auto bufferSizeArgumentBufferIndex = bindGroupLayout.bufferSizeIndexForEntryIndex(entry.binding, stage); MTLResourceUsage resourceUsage = resourceUsageForBindingAcccess(*optionalAccess); if (bufferIsPresent) { @@ -487,6 +488,8 @@ static MTLResourceUsage resourceUsageForBindingAcccess(BindGroupLayout::BindingA [argumentEncoder[stage] setBuffer:buffer offset:entry.offset atIndex:index]; stageResources[metalRenderStage(stage)][resourceUsage - 1].append(buffer); + RELEASE_ASSERT(bufferSizeArgumentBufferIndex); + *(uint32_t*)[argumentEncoder[stage] constantDataAtIndex:*bufferSizeArgumentBufferIndex] = static_cast(entry.size == WGPU_WHOLE_MAP_SIZE ? buffer.length : entry.size); } else if (samplerIsPresent) { id sampler = WebGPU::fromAPI(entry.sampler).samplerState(); [argumentEncoder[stage] setSamplerState:sampler atIndex:index]; diff --git a/Source/WebGPU/WebGPU/BindGroupLayout.h b/Source/WebGPU/WebGPU/BindGroupLayout.h index 54fa7d94155a..91bc8d5b1466 100644 --- a/Source/WebGPU/WebGPU/BindGroupLayout.h +++ b/Source/WebGPU/WebGPU/BindGroupLayout.h @@ -59,6 +59,7 @@ class BindGroupLayout : public WGPUBindGroupLayoutImpl, public RefCounted; BindingLayout bindingLayout; ArgumentBufferIndices argumentBufferIndices; + ArgumentBufferIndices bufferSizeArgumentBufferIndices; std::optional vertexDynamicOffset; std::optional fragmentDynamicOffset; std::optional computeDynamicOffset; @@ -102,6 +103,7 @@ class BindGroupLayout : public WGPUBindGroupLayoutImpl, public RefCounted bindingAccessForBindingIndex(uint32_t bindingIndex, ShaderStage renderStage) const; NSUInteger argumentBufferIndexForEntryIndex(uint32_t bindingIndex, ShaderStage renderStage) const; + std::optional bufferSizeIndexForEntryIndex(uint32_t bindingIndex, ShaderStage renderStage) const; static bool isPresent(const WGPUBufferBindingLayout&); static bool isPresent(const WGPUSamplerBindingLayout&); diff --git a/Source/WebGPU/WebGPU/BindGroupLayout.mm b/Source/WebGPU/WebGPU/BindGroupLayout.mm index aa3b2b39ac1a..307201057df0 100644 --- a/Source/WebGPU/WebGPU/BindGroupLayout.mm +++ b/Source/WebGPU/WebGPU/BindGroupLayout.mm @@ -160,6 +160,7 @@ static bool containsStage(WGPUShaderStageFlags stageBitfield, auto stage) BindGroupLayout::EntriesContainer bindGroupLayoutEntries; size_t sizeOfDynamicOffsets[stageCount] = { 0, 0, 0 }; uint32_t bindingOffset[stageCount] = { 0, 0, 0 }; + uint32_t bufferCounts[stageCount] = { 0, 0, 0 }; for (auto& entry : descriptorEntries) { if (entry.nextInChain) { if (entry.nextInChain->sType != static_cast(WGPUSTypeExtended_BindGroupLayoutEntryExternalTexture)) @@ -213,6 +214,7 @@ static bool containsStage(WGPUShaderStageFlags stageBitfield, auto stage) std::optional dynamicOffsets[stageCount]; BindGroupLayout::ArgumentBufferIndices argumentBufferIndices; + BindGroupLayout::ArgumentBufferIndices bufferSizeArgumentBufferIndices; for (uint32_t stage = 0; stage < stageCount; ++stage) { if (containsStage(entry.visibility, stage)) { indicesForBinding.add(makeKey(entry.binding, stage), descriptors[0].access); @@ -222,6 +224,10 @@ static bool containsStage(WGPUShaderStageFlags stageBitfield, auto stage) dynamicOffsets[stage] = sizeOfDynamicOffsets[stage]; sizeOfDynamicOffsets[stage] += sizeof(uint32_t); } + if (BindGroupLayout::isPresent(entry.buffer)) { + ++bufferCounts[stage]; + bufferSizeArgumentBufferIndices[renderStage] = bufferCounts[stage]; + } for (int descriptorIndex = 0; descriptorIndex < maxGeneratedDescriptors; ++descriptorIndex) { if (MTLArgumentDescriptor *descriptor = descriptors[descriptorIndex]) @@ -240,6 +246,7 @@ static bool containsStage(WGPUShaderStageFlags stageBitfield, auto stage) entry.visibility, WTFMove(bindingLayout), WTFMove(argumentBufferIndices), + WTFMove(bufferSizeArgumentBufferIndices), WTFMove(dynamicOffsets[0]), WTFMove(dynamicOffsets[1]), WTFMove(dynamicOffsets[2]) @@ -249,6 +256,20 @@ static bool containsStage(WGPUShaderStageFlags stageBitfield, auto stage) auto label = fromAPI(descriptor.label); id argumentEncoders[stageCount]; for (size_t stage = 0; stage < stageCount; ++stage) { + auto renderStage = stages[stage]; + if (auto bufferCountPerStage = bufferCounts[stage]) { + NSUInteger maxIndex = [arguments[stage] objectAtIndex:arguments[stage].count - 1].index; + for (auto& entry : bindGroupLayoutEntries) { + if (entry.value.bufferSizeArgumentBufferIndices[renderStage]) + *entry.value.bufferSizeArgumentBufferIndices[renderStage] += maxIndex; + } + for (size_t bufferLengthIndex = 0; bufferLengthIndex < bufferCountPerStage; ++bufferLengthIndex) { + auto descriptor = [MTLArgumentDescriptor new]; + descriptor.dataType = MTLDataTypeInt; + descriptor.access = BindGroupLayout::BindingAccessReadOnly; + addDescriptor(arguments[stage], descriptor, maxIndex + bufferLengthIndex + 1); + } + } argumentEncoders[stage] = arguments[stage].count ? [m_device newArgumentEncoderWithArguments:arguments[stage]] : nil; argumentEncoders[stage].label = label; if (arguments[stage].count && !argumentEncoders[stage]) @@ -331,6 +352,16 @@ static bool containsStage(WGPUShaderStageFlags stageBitfield, auto stage) return NSNotFound; } +std::optional BindGroupLayout::bufferSizeIndexForEntryIndex(uint32_t bindingIndex, ShaderStage renderStage) const +{ + if (auto it = m_bindGroupLayoutEntries.find(bindingIndex); it != m_bindGroupLayoutEntries.end()) { + auto result = it->value.bufferSizeArgumentBufferIndices[renderStage]; + return result ? *result : NSNotFound; + } + + return NSNotFound; +} + } // namespace WebGPU #pragma mark WGPU Stubs diff --git a/Source/WebGPU/WebGPU/ShaderModule.mm b/Source/WebGPU/WebGPU/ShaderModule.mm index 32049d28e276..303e98b2a117 100644 --- a/Source/WebGPU/WebGPU/ShaderModule.mm +++ b/Source/WebGPU/WebGPU/ShaderModule.mm @@ -368,10 +368,13 @@ static auto wgslViewDimension(WGPUTextureViewDimension viewDimension) wgslEntry.visibility.fromRaw(entry.value.visibility); wgslEntry.bindingMember = convertBindingLayout(entry.value.bindingLayout); wgslEntry.vertexArgumentBufferIndex = entry.value.argumentBufferIndices[WebGPU::ShaderStage::Vertex]; + wgslEntry.vertexArgumentBufferSizeIndex = entry.value.bufferSizeArgumentBufferIndices[WebGPU::ShaderStage::Vertex]; wgslEntry.vertexBufferDynamicOffset = entry.value.vertexDynamicOffset; wgslEntry.fragmentArgumentBufferIndex = entry.value.argumentBufferIndices[WebGPU::ShaderStage::Fragment]; + wgslEntry.fragmentArgumentBufferSizeIndex = entry.value.bufferSizeArgumentBufferIndices[WebGPU::ShaderStage::Fragment]; wgslEntry.fragmentBufferDynamicOffset = entry.value.fragmentDynamicOffset; wgslEntry.computeArgumentBufferIndex = entry.value.argumentBufferIndices[WebGPU::ShaderStage::Compute]; + wgslEntry.computeArgumentBufferSizeIndex = entry.value.bufferSizeArgumentBufferIndices[WebGPU::ShaderStage::Compute]; wgslEntry.computeBufferDynamicOffset = entry.value.computeDynamicOffset; wgslBindGroupLayout.entries.append(wgslEntry); } From 09d53ca80dff2e5a8bda182b2d817490e5008065 Mon Sep 17 00:00:00 2001 From: Olivier Blin Date: Wed, 4 Oct 2023 17:54:34 -0700 Subject: [PATCH 08/16] [WebTransport] Fix build of trimToValidUTF8Length1024() with -Wreturn-std-move https://bugs.webkit.org/show_bug.cgi?id=262535 Reviewed by Alex Christensen. * Source/WebCore/Modules/webtransport/WebTransport.cpp: (WebCore::trimToValidUTF8Length1024): Call WTFMove() explicitly to avoid copying Canonical link: https://commits.webkit.org/268885@main --- Source/WebCore/Modules/webtransport/WebTransport.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/WebCore/Modules/webtransport/WebTransport.cpp b/Source/WebCore/Modules/webtransport/WebTransport.cpp index 911dd2113520..d1683d3108a8 100644 --- a/Source/WebCore/Modules/webtransport/WebTransport.cpp +++ b/Source/WebCore/Modules/webtransport/WebTransport.cpp @@ -212,16 +212,16 @@ static CString trimToValidUTF8Length1024(CString&& string) if (string.length() > 1024) string = CString(string.data(), 1024); else - return string; + return WTFMove(string); while (true) { if (!string.length()) - return string; + return WTFMove(string); auto decoded = String::fromUTF8(string.data(), string.length()); if (!decoded) string = CString(string.data(), string.length() - 1); else - return string; + return WTFMove(string); } } From e483494b6eaea1bc17ee16146a0e385b74b055f1 Mon Sep 17 00:00:00 2001 From: Pascoe Date: Wed, 4 Oct 2023 17:56:05 -0700 Subject: [PATCH 09/16] Make UserScript use generated serialization https://bugs.webkit.org/show_bug.cgi?id=262643 rdar://116483136 Reviewed by Alex Christensen. This patch starts to use the generated serialization for UserScript instead of manually specifying ::encode and ::decode. * Source/WebCore/page/UserScript.h: (WebCore::UserScript::encode const): Deleted. (WebCore::UserScript::decode): Deleted. * Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in: Canonical link: https://commits.webkit.org/268886@main --- Source/WebCore/page/UserScript.h | 64 ------------------- .../WebCoreArgumentCoders.serialization.in | 16 +++++ 2 files changed, 16 insertions(+), 64 deletions(-) diff --git a/Source/WebCore/page/UserScript.h b/Source/WebCore/page/UserScript.h index 503342a3550f..e28fdbc6ead7 100644 --- a/Source/WebCore/page/UserScript.h +++ b/Source/WebCore/page/UserScript.h @@ -60,9 +60,6 @@ class UserScript { UserContentInjectedFrames injectedFrames() const { return m_injectedFrames; } WaitForNotificationBeforeInjecting waitForNotificationBeforeInjecting() const { return m_waitForNotificationBeforeInjecting; } - template void encode(Encoder&) const; - template static std::optional decode(Decoder&); - private: String m_source; URL m_url; @@ -73,65 +70,4 @@ class UserScript { WaitForNotificationBeforeInjecting m_waitForNotificationBeforeInjecting { WaitForNotificationBeforeInjecting::No }; }; -template -void UserScript::encode(Encoder& encoder) const -{ - encoder << m_source; - encoder << m_url; - encoder << m_allowlist; - encoder << m_blocklist; - encoder << m_injectionTime; - encoder << m_injectedFrames; - encoder << m_waitForNotificationBeforeInjecting; -} - -template -std::optional UserScript::decode(Decoder& decoder) -{ - std::optional source; - decoder >> source; - if (!source) - return std::nullopt; - - std::optional url; - decoder >> url; - if (!url) - return std::nullopt; - - std::optional> allowlist; - decoder >> allowlist; - if (!allowlist) - return std::nullopt; - - std::optional> blocklist; - decoder >> blocklist; - if (!blocklist) - return std::nullopt; - - std::optional injectionTime; - decoder >> injectionTime; - if (!injectionTime) - return std::nullopt; - - std::optional injectedFrames; - decoder >> injectedFrames; - if (!injectedFrames) - return std::nullopt; - - std::optional waitForNotification; - decoder >> waitForNotification; - if (!waitForNotification) - return std::nullopt; - - return {{ - WTFMove(*source), - WTFMove(*url), - WTFMove(*allowlist), - WTFMove(*blocklist), - WTFMove(*injectionTime), - WTFMove(*injectedFrames), - WTFMove(*waitForNotification) - }}; -} - } // namespace WebCore diff --git a/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in b/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in index b31bdc8eb208..053359a64dcf 100644 --- a/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in +++ b/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in @@ -6299,3 +6299,19 @@ header: [Alias=class FontTaggedSettings, CustomHeader, LegacyPopulateFromEmptyConstructor] class WebCore::FontFeatureSettings { Vector m_list; }; + +enum class WebCore::UserScriptInjectionTime : bool; + +enum class WebCore::WaitForNotificationBeforeInjecting : bool; + +enum class WebCore::UserContentInjectedFrames : bool; + +class WebCore::UserScript { + String source(); + URL url(); + Vector allowlist(); + Vector blocklist(); + WebCore::UserScriptInjectionTime injectionTime(); + WebCore::UserContentInjectedFrames injectedFrames(); + WebCore::WaitForNotificationBeforeInjecting waitForNotificationBeforeInjecting(); +} From 728c278f57444c3efca0c1c0c342f6f03bd17d9c Mon Sep 17 00:00:00 2001 From: Chris Dumez Date: Wed, 4 Oct 2023 18:41:48 -0700 Subject: [PATCH 10/16] Reduce size of RenderText from 128 to 120 bytes on 64-bit https://bugs.webkit.org/show_bug.cgi?id=262655 Reviewed by Simon Fraser. Reduce size of RenderText from 128 to 120 bytes on 64-bit by leveraging Markable. * Source/WTF/wtf/Markable.h: (WTF::FloatMarkableTraits::isEmptyValue): (WTF::FloatMarkableTraits::emptyValue): (WTF::Markable::value_or const): * Source/WebCore/platform/graphics/FontSizeAdjust.h: (WebCore::FloatMarkableTraits::isEmptyValue): Deleted. (WebCore::FloatMarkableTraits::emptyValue): Deleted. * Source/WebCore/rendering/RenderText.cpp: (WebCore::RenderText::RenderText): * Source/WebCore/rendering/RenderText.h: Canonical link: https://commits.webkit.org/268887@main --- Source/WTF/wtf/Markable.h | 19 +++++++++++ .../platform/graphics/FontSizeAdjust.h | 14 +------- Source/WebCore/rendering/RenderText.cpp | 12 +++---- Source/WebCore/rendering/RenderText.h | 32 +++++++++---------- 4 files changed, 41 insertions(+), 36 deletions(-) diff --git a/Source/WTF/wtf/Markable.h b/Source/WTF/wtf/Markable.h index 37b81a5639d7..f36867a4a8db 100644 --- a/Source/WTF/wtf/Markable.h +++ b/Source/WTF/wtf/Markable.h @@ -76,6 +76,18 @@ struct IntegralMarkableTraits { } }; +struct FloatMarkableTraits { + constexpr static bool isEmptyValue(float value) + { + return value != value; + } + + constexpr static float emptyValue() + { + return std::numeric_limits::quiet_NaN(); + } +}; + // The goal of Markable is offering Optional without sacrificing storage efficiency. // Markable takes Traits, which should have isEmptyValue and emptyValue functions. By using // one value of T as an empty value, we can remove bool flag in Optional. This strategy is @@ -129,6 +141,13 @@ class Markable { constexpr const T& operator*() const& { return m_value; } constexpr T& operator*() & { return m_value; } + template constexpr T value_or(U&& fallback) const + { + if (bool(*this)) + return m_value; + return static_cast(std::forward(fallback)); + } + operator std::optional() && { if (bool(*this)) diff --git a/Source/WebCore/platform/graphics/FontSizeAdjust.h b/Source/WebCore/platform/graphics/FontSizeAdjust.h index 911d252bda13..a4a92eb858db 100644 --- a/Source/WebCore/platform/graphics/FontSizeAdjust.h +++ b/Source/WebCore/platform/graphics/FontSizeAdjust.h @@ -31,18 +31,6 @@ namespace WebCore { -struct FloatMarkableTraits { - constexpr static bool isEmptyValue(float value) - { - return value != value; - } - - constexpr static float emptyValue() - { - return std::numeric_limits::quiet_NaN(); - } -}; - struct FontSizeAdjust { friend bool operator==(const FontSizeAdjust&, const FontSizeAdjust&) = default; @@ -55,7 +43,7 @@ struct FontSizeAdjust { }; Metric metric { Metric::ExHeight }; bool isFromFont { false }; - Markable value { }; + Markable value { }; }; inline void add(Hasher& hasher, const FontSizeAdjust& fontSizeAdjust) diff --git a/Source/WebCore/rendering/RenderText.cpp b/Source/WebCore/rendering/RenderText.cpp index 739a14185e10..12d1763d25a6 100644 --- a/Source/WebCore/rendering/RenderText.cpp +++ b/Source/WebCore/rendering/RenderText.cpp @@ -84,16 +84,14 @@ using namespace WTF::Unicode; WTF_MAKE_ISO_ALLOCATED_IMPL(RenderText); struct SameSizeAsRenderText : public RenderObject { - void* pointers[2]; - uint32_t bitfields : 16; #if ENABLE(TEXT_AUTOSIZING) float candidateTextSize; #endif - float widths[2]; - std::optional minWidth; - std::optional maxWidth; - std::optional canUseSimplifiedTextMeasuring; + float widths[4]; + void* pointers[2]; String text; + std::optional canUseSimplifiedTextMeasuring; + uint32_t bitfields : 16; }; static_assert(sizeof(RenderText) == sizeof(SameSizeAsRenderText), "RenderText should stay small"); @@ -247,8 +245,8 @@ static unsigned offsetForPositionInRun(const InlineIterator::TextBox& textBox, f inline RenderText::RenderText(Type type, Node& node, const String& text) : RenderObject(type, node) - , m_containsOnlyASCII(text.impl()->containsOnlyASCII()) , m_text(text) + , m_containsOnlyASCII(text.impl()->containsOnlyASCII()) { ASSERT(!m_text.isNull()); setIsText(); diff --git a/Source/WebCore/rendering/RenderText.h b/Source/WebCore/rendering/RenderText.h index 8bb51d342e49..e92fa3340ff8 100644 --- a/Source/WebCore/rendering/RenderText.h +++ b/Source/WebCore/rendering/RenderText.h @@ -26,6 +26,7 @@ #include "RenderTextLineBoxes.h" #include "Text.h" #include +#include #include namespace WebCore { @@ -229,16 +230,27 @@ class RenderText : public RenderObject { float maxWordFragmentWidth(const RenderStyle&, const FontCascade&, StringView word, unsigned minimumPrefixLength, unsigned minimumSuffixLength, bool currentCharacterIsSpace, unsigned characterIndex, float xPos, float entireWordWidth, WordTrailingSpace&, WeakHashSet& fallbackFonts, GlyphOverflow&); float widthFromCacheConsideringPossibleTrailingSpace(const RenderStyle&, const FontCascade&, unsigned startIndex, unsigned wordLen, float xPos, bool currentCharacterIsSpace, WordTrailingSpace&, WeakHashSet& fallbackFonts, GlyphOverflow&) const; - // We put the bitfield first to minimize padding on 64-bit. +#if ENABLE(TEXT_AUTOSIZING) + // FIXME: This should probably be part of the text sizing structures in Document instead. That would save some memory. + float m_candidateComputedTextSize { 0 }; +#endif + Markable m_minWidth; + Markable m_maxWidth; + float m_beginMinWidth { 0 }; + float m_endMinWidth { 0 }; + + String m_text; + + std::optional m_canUseSimplifiedTextMeasuring; unsigned m_hasBreakableChar : 1 { false }; // Whether or not we can be broken into multiple lines. unsigned m_hasBreak : 1 { false }; // Whether or not we have a hard break (e.g.,
 with '\n').
     unsigned m_hasTab : 1 { false }; // Whether or not we have a variable width tab character (e.g., 
 with '\t').
     unsigned m_hasBeginWS : 1 { false }; // Whether or not we begin with WS (only true if we aren't pre)
     unsigned m_hasEndWS : 1 { false }; // Whether or not we end with WS (only true if we aren't pre)
     unsigned m_linesDirty : 1 { false }; // This bit indicates that the text run has already dirtied specific
-                           // line boxes, and this hint will enable layoutInlineChildren to avoid
-                           // just dirtying everything when character data is modified (e.g., appended/inserted
-                           // or removed).
+                                         // line boxes, and this hint will enable layoutInlineChildren to avoid
+                                         // just dirtying everything when character data is modified (e.g., appended/inserted
+                                         // or removed).
     unsigned m_needsVisualReordering : 1 { false };
     unsigned m_containsOnlyASCII : 1 { false };
     unsigned m_canUseSimpleFontCodePath : 1 { false };
@@ -246,18 +258,6 @@ class RenderText : public RenderObject {
     unsigned m_useBackslashAsYenSymbol : 1 { false };
     unsigned m_originalTextDiffersFromRendered : 1 { false };
     unsigned m_hasInlineWrapperForDisplayContents : 1 { false };
-
-#if ENABLE(TEXT_AUTOSIZING)
-    // FIXME: This should probably be part of the text sizing structures in Document instead. That would save some memory.
-    float m_candidateComputedTextSize { 0 };
-#endif
-    std::optional m_minWidth;
-    std::optional m_maxWidth;
-    std::optional m_canUseSimplifiedTextMeasuring { };
-    float m_beginMinWidth { 0 };
-    float m_endMinWidth { 0 };
-
-    String m_text;
 };
 
 String applyTextTransform(const RenderStyle&, const String&, UChar previousCharacter);

From 5a8e0d73650d475df214c4b141bdc1cc4d51255f Mon Sep 17 00:00:00 2001
From: Amanda Falke 
Date: Wed, 4 Oct 2023 18:59:51 -0700
Subject: [PATCH 11/16] [WPE] API test WebKitWebView/external-audio-rendering
 is a consistent timeout

Unreviewed test gardening

API test is a consistent timeout for the last few days in API release
bot, starting on or around 268722@main.

* Tools/TestWebKitAPI/glib/TestExpectations.json:

Canonical link: https://commits.webkit.org/268888@main
---
 Tools/TestWebKitAPI/glib/TestExpectations.json | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Tools/TestWebKitAPI/glib/TestExpectations.json b/Tools/TestWebKitAPI/glib/TestExpectations.json
index 200e7599d5b3..ff013cf49dbf 100644
--- a/Tools/TestWebKitAPI/glib/TestExpectations.json
+++ b/Tools/TestWebKitAPI/glib/TestExpectations.json
@@ -72,6 +72,9 @@
             },
             "/webkit/WebKitWebView/fullscreen": {
                 "expected": {"gtk": {"status": ["SKIP"], "bug": "webkit.org/b/248203"}}
+            },
+            "/webkit/WebKitWebView/external-audio-rendering": {
+                "expected": {"wpe": {"status": ["TIMEOUT"], "bug": "webkit.org/b/262625"}}
             }
         }
     },

From fa7447aa7e693cc4500f00fe4aa55de4d5dcf993 Mon Sep 17 00:00:00 2001
From: Yusuke Suzuki 
Date: Wed, 4 Oct 2023 19:01:41 -0700
Subject: [PATCH 12/16] Add fastRepaintRectInLocalCoordinates
 https://bugs.webkit.org/show_bug.cgi?id=262667 rdar://116492451

Reviewed by Said Abou-Hallawa.

Add fastRepaintRectInLocalCoordinates. We agreed that we will keep
repaintRectInLocalCoordinates as is. And repaintRectInLocalCoordinates will
be used only for RenderTreeAsText and checkEnclosure related things.
So approximate one will get fastRepaintRectInLocalCoordinates and
repainting code will use fastRepaintRectInLocalCoordinates.

* Source/WebCore/rendering/RenderBox.h:
* Source/WebCore/rendering/RenderObject.cpp:
(WebCore::RenderObject::fastRepaintRectInLocalCoordinates const):
* Source/WebCore/rendering/RenderObject.h:
* Source/WebCore/rendering/svg/RenderSVGContainer.h:
* Source/WebCore/rendering/svg/RenderSVGForeignObject.h:
* Source/WebCore/rendering/svg/RenderSVGGradientStop.h:
* Source/WebCore/rendering/svg/RenderSVGImage.h:
* Source/WebCore/rendering/svg/RenderSVGInline.h:
* Source/WebCore/rendering/svg/RenderSVGRoot.h:
* Source/WebCore/rendering/svg/RenderSVGShape.h:
* Source/WebCore/rendering/svg/RenderSVGText.h:
* Source/WebCore/rendering/svg/legacy/LegacyRenderSVGContainer.h:
* Source/WebCore/rendering/svg/legacy/LegacyRenderSVGForeignObject.h:
* Source/WebCore/rendering/svg/legacy/LegacyRenderSVGImage.h:
* Source/WebCore/rendering/svg/legacy/LegacyRenderSVGRoot.h:
* Source/WebCore/rendering/svg/legacy/LegacyRenderSVGShape.h:

Canonical link: https://commits.webkit.org/268889@main
---
 Source/WebCore/rendering/RenderBox.h                        | 1 +
 Source/WebCore/rendering/RenderObject.cpp                   | 6 ++++++
 Source/WebCore/rendering/RenderObject.h                     | 4 ++++
 Source/WebCore/rendering/svg/RenderSVGContainer.h           | 1 +
 Source/WebCore/rendering/svg/RenderSVGForeignObject.h       | 1 +
 Source/WebCore/rendering/svg/RenderSVGGradientStop.h        | 1 +
 Source/WebCore/rendering/svg/RenderSVGImage.h               | 1 +
 Source/WebCore/rendering/svg/RenderSVGInline.h              | 1 +
 Source/WebCore/rendering/svg/RenderSVGRoot.h                | 1 +
 Source/WebCore/rendering/svg/RenderSVGShape.h               | 1 +
 Source/WebCore/rendering/svg/RenderSVGText.h                | 1 +
 .../WebCore/rendering/svg/legacy/LegacyRenderSVGContainer.h | 1 +
 .../rendering/svg/legacy/LegacyRenderSVGForeignObject.h     | 1 +
 Source/WebCore/rendering/svg/legacy/LegacyRenderSVGImage.h  | 1 +
 Source/WebCore/rendering/svg/legacy/LegacyRenderSVGRoot.h   | 1 +
 Source/WebCore/rendering/svg/legacy/LegacyRenderSVGShape.h  | 1 +
 16 files changed, 24 insertions(+)

diff --git a/Source/WebCore/rendering/RenderBox.h b/Source/WebCore/rendering/RenderBox.h
index c5b3e62ddd76..0723d468834d 100644
--- a/Source/WebCore/rendering/RenderBox.h
+++ b/Source/WebCore/rendering/RenderBox.h
@@ -134,6 +134,7 @@ class RenderBox : public RenderBoxModelObject {
     void addFocusRingRects(Vector&, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer = nullptr) const override;
     
     FloatRect repaintRectInLocalCoordinates() const override { return borderBoxRect(); }
+    FloatRect fastRepaintRectInLocalCoordinates() const override { return borderBoxRect(); }
     FloatRect objectBoundingBox() const override { return borderBoxRect(); }
 
     // Note these functions are not equivalent of childrenOfType
diff --git a/Source/WebCore/rendering/RenderObject.cpp b/Source/WebCore/rendering/RenderObject.cpp
index 04beaa430b08..343120581cc0 100644
--- a/Source/WebCore/rendering/RenderObject.cpp
+++ b/Source/WebCore/rendering/RenderObject.cpp
@@ -2089,6 +2089,12 @@ FloatRect RenderObject::repaintRectInLocalCoordinates() const
     return FloatRect();
 }
 
+FloatRect RenderObject::fastRepaintRectInLocalCoordinates() const
+{
+    ASSERT_NOT_REACHED();
+    return FloatRect();
+}
+
 AffineTransform RenderObject::localTransform() const
 {
     return AffineTransform();
diff --git a/Source/WebCore/rendering/RenderObject.h b/Source/WebCore/rendering/RenderObject.h
index 6fae4a3c7fe8..71c981c8fe2d 100644
--- a/Source/WebCore/rendering/RenderObject.h
+++ b/Source/WebCore/rendering/RenderObject.h
@@ -507,6 +507,10 @@ class RenderObject : public CachedImageClient, public CanMakeCheckedPtr {
     // respecting clipping, masking, filters, opacity, stroke-width and markers
     virtual FloatRect repaintRectInLocalCoordinates() const;
 
+    // Returns approximate rectangle enclosing all of the painted content.
+    // This is always larger-or-equal to repaintRectInLocalCoordinates().
+    virtual FloatRect fastRepaintRectInLocalCoordinates() const;
+
     // This only returns the transform="" value from the element
     // most callsites want localToParentTransform() instead.
     virtual AffineTransform localTransform() const;
diff --git a/Source/WebCore/rendering/svg/RenderSVGContainer.h b/Source/WebCore/rendering/svg/RenderSVGContainer.h
index 130f5be006bc..bb05d9bbc247 100644
--- a/Source/WebCore/rendering/svg/RenderSVGContainer.h
+++ b/Source/WebCore/rendering/svg/RenderSVGContainer.h
@@ -46,6 +46,7 @@ class RenderSVGContainer : public RenderSVGModelObject {
     FloatRect objectBoundingBoxWithoutTransformations() const final { return m_objectBoundingBoxWithoutTransformations; }
     FloatRect strokeBoundingBox() const final { return m_strokeBoundingBox; }
     FloatRect repaintRectInLocalCoordinates() const final { return SVGBoundingBoxComputation::computeRepaintBoundingBox(*this); }
+    FloatRect fastRepaintRectInLocalCoordinates() const final { return repaintRectInLocalCoordinates(); }
 
 protected:
     RenderSVGContainer(Type, Document&, RenderStyle&&);
diff --git a/Source/WebCore/rendering/svg/RenderSVGForeignObject.h b/Source/WebCore/rendering/svg/RenderSVGForeignObject.h
index f4b264084c54..8290c8172cd6 100644
--- a/Source/WebCore/rendering/svg/RenderSVGForeignObject.h
+++ b/Source/WebCore/rendering/svg/RenderSVGForeignObject.h
@@ -47,6 +47,7 @@ class RenderSVGForeignObject final : public RenderSVGBlock {
     FloatRect objectBoundingBox() const final { return m_viewport; }
     FloatRect strokeBoundingBox() const final { return m_viewport; }
     FloatRect repaintRectInLocalCoordinates() const final { return SVGBoundingBoxComputation::computeRepaintBoundingBox(*this); }
+    FloatRect fastRepaintRectInLocalCoordinates() const final { return repaintRectInLocalCoordinates(); }
 
 private:
     void graphicsElement() const = delete;
diff --git a/Source/WebCore/rendering/svg/RenderSVGGradientStop.h b/Source/WebCore/rendering/svg/RenderSVGGradientStop.h
index 08ffed03301b..d0391165dcc3 100644
--- a/Source/WebCore/rendering/svg/RenderSVGGradientStop.h
+++ b/Source/WebCore/rendering/svg/RenderSVGGradientStop.h
@@ -49,6 +49,7 @@ class RenderSVGGradientStop final : public RenderElement {
     FloatRect objectBoundingBox() const override { return FloatRect(); }
     FloatRect strokeBoundingBox() const override { return FloatRect(); }
     FloatRect repaintRectInLocalCoordinates() const override { return FloatRect(); }
+    FloatRect fastRepaintRectInLocalCoordinates() const override { return repaintRectInLocalCoordinates(); }
     bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint&, HitTestAction) override { return false; }
 
     ASCIILiteral renderName() const override { return "RenderSVGGradientStop"_s; }
diff --git a/Source/WebCore/rendering/svg/RenderSVGImage.h b/Source/WebCore/rendering/svg/RenderSVGImage.h
index 16b52dbc7013..f700c685b060 100644
--- a/Source/WebCore/rendering/svg/RenderSVGImage.h
+++ b/Source/WebCore/rendering/svg/RenderSVGImage.h
@@ -58,6 +58,7 @@ class RenderSVGImage final : public RenderSVGModelObject {
     FloatRect objectBoundingBox() const final { return m_objectBoundingBox; }
     FloatRect strokeBoundingBox() const final { return m_objectBoundingBox; }
     FloatRect repaintRectInLocalCoordinates() const final { return SVGBoundingBoxComputation::computeRepaintBoundingBox(*this); }
+    FloatRect fastRepaintRectInLocalCoordinates() const final { return repaintRectInLocalCoordinates(); }
 
     void imageChanged(WrappedImagePtr, const IntRect* = nullptr) final;
 
diff --git a/Source/WebCore/rendering/svg/RenderSVGInline.h b/Source/WebCore/rendering/svg/RenderSVGInline.h
index 55138c136204..75cf40f6959f 100644
--- a/Source/WebCore/rendering/svg/RenderSVGInline.h
+++ b/Source/WebCore/rendering/svg/RenderSVGInline.h
@@ -49,6 +49,7 @@ class RenderSVGInline : public RenderInline {
     FloatRect objectBoundingBox() const final;
     FloatRect strokeBoundingBox() const final;
     FloatRect repaintRectInLocalCoordinates() const final;
+    FloatRect fastRepaintRectInLocalCoordinates() const final { return repaintRectInLocalCoordinates(); }
 
 #if ENABLE(LAYER_BASED_SVG_ENGINE)
     LayoutPoint currentSVGLayoutLocation() const final { return { }; }
diff --git a/Source/WebCore/rendering/svg/RenderSVGRoot.h b/Source/WebCore/rendering/svg/RenderSVGRoot.h
index 49b6572aa5e6..e039638b7761 100644
--- a/Source/WebCore/rendering/svg/RenderSVGRoot.h
+++ b/Source/WebCore/rendering/svg/RenderSVGRoot.h
@@ -68,6 +68,7 @@ class RenderSVGRoot final : public RenderReplaced {
     FloatRect objectBoundingBoxWithoutTransformations() const final { return m_objectBoundingBoxWithoutTransformations; }
     FloatRect strokeBoundingBox() const final { return m_strokeBoundingBox; }
     FloatRect repaintRectInLocalCoordinates() const final { return SVGBoundingBoxComputation::computeRepaintBoundingBox(*this); }
+    FloatRect fastRepaintRectInLocalCoordinates() const final { return repaintRectInLocalCoordinates(); }
 
     LayoutRect visualOverflowRectEquivalent() const { return SVGBoundingBoxComputation::computeVisualOverflowRect(*this); }
 
diff --git a/Source/WebCore/rendering/svg/RenderSVGShape.h b/Source/WebCore/rendering/svg/RenderSVGShape.h
index 8f4cade05c8c..95cf30364ead 100644
--- a/Source/WebCore/rendering/svg/RenderSVGShape.h
+++ b/Source/WebCore/rendering/svg/RenderSVGShape.h
@@ -79,6 +79,7 @@ class RenderSVGShape : public RenderSVGModelObject {
     FloatRect objectBoundingBox() const final { return m_fillBoundingBox; }
     FloatRect strokeBoundingBox() const final { return m_strokeBoundingBox; }
     FloatRect repaintRectInLocalCoordinates() const final { return SVGBoundingBoxComputation::computeRepaintBoundingBox(*this); }
+    FloatRect fastRepaintRectInLocalCoordinates() const final { return repaintRectInLocalCoordinates(); }
 
     FloatRect computeMarkerBoundingBox(const SVGBoundingBoxComputation::DecorationOptions&) const;
 
diff --git a/Source/WebCore/rendering/svg/RenderSVGText.h b/Source/WebCore/rendering/svg/RenderSVGText.h
index 05333242ba93..c99ecdd9c245 100644
--- a/Source/WebCore/rendering/svg/RenderSVGText.h
+++ b/Source/WebCore/rendering/svg/RenderSVGText.h
@@ -63,6 +63,7 @@ class RenderSVGText final : public RenderSVGBlock {
     FloatRect objectBoundingBox() const final { return m_objectBoundingBox; }
     FloatRect strokeBoundingBox() const final;
     FloatRect repaintRectInLocalCoordinates() const final;
+    FloatRect fastRepaintRectInLocalCoordinates() const final { return repaintRectInLocalCoordinates(); }
 
 #if ENABLE(LAYER_BASED_SVG_ENGINE)
     LayoutRect visualOverflowRectEquivalent() const { return SVGBoundingBoxComputation::computeVisualOverflowRect(*this); }
diff --git a/Source/WebCore/rendering/svg/legacy/LegacyRenderSVGContainer.h b/Source/WebCore/rendering/svg/legacy/LegacyRenderSVGContainer.h
index b3b8153454e1..6f038bd6e48c 100644
--- a/Source/WebCore/rendering/svg/legacy/LegacyRenderSVGContainer.h
+++ b/Source/WebCore/rendering/svg/legacy/LegacyRenderSVGContainer.h
@@ -53,6 +53,7 @@ class LegacyRenderSVGContainer : public LegacyRenderSVGModelObject {
     FloatRect objectBoundingBox() const final { return m_objectBoundingBox; }
     FloatRect strokeBoundingBox() const final { return m_strokeBoundingBox; }
     FloatRect repaintRectInLocalCoordinates() const final { return m_repaintBoundingBox; }
+    FloatRect fastRepaintRectInLocalCoordinates() const final { return repaintRectInLocalCoordinates(); }
 
     bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction) override;
 
diff --git a/Source/WebCore/rendering/svg/legacy/LegacyRenderSVGForeignObject.h b/Source/WebCore/rendering/svg/legacy/LegacyRenderSVGForeignObject.h
index d95486a3f865..988f80614009 100644
--- a/Source/WebCore/rendering/svg/legacy/LegacyRenderSVGForeignObject.h
+++ b/Source/WebCore/rendering/svg/legacy/LegacyRenderSVGForeignObject.h
@@ -45,6 +45,7 @@ class LegacyRenderSVGForeignObject final : public RenderSVGBlock {
     FloatRect objectBoundingBox() const override { return FloatRect(FloatPoint(), m_viewport.size()); }
     FloatRect strokeBoundingBox() const override { return FloatRect(FloatPoint(), m_viewport.size()); }
     FloatRect repaintRectInLocalCoordinates() const override { return FloatRect(FloatPoint(), m_viewport.size()); }
+    FloatRect fastRepaintRectInLocalCoordinates() const override { return repaintRectInLocalCoordinates(); }
 
     bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction) override;
 
diff --git a/Source/WebCore/rendering/svg/legacy/LegacyRenderSVGImage.h b/Source/WebCore/rendering/svg/legacy/LegacyRenderSVGImage.h
index 9197394249e4..45ff9c45d2cc 100644
--- a/Source/WebCore/rendering/svg/legacy/LegacyRenderSVGImage.h
+++ b/Source/WebCore/rendering/svg/legacy/LegacyRenderSVGImage.h
@@ -65,6 +65,7 @@ class LegacyRenderSVGImage final : public LegacyRenderSVGModelObject {
     FloatRect objectBoundingBox() const override { return m_objectBoundingBox; }
     FloatRect strokeBoundingBox() const override { return m_objectBoundingBox; }
     FloatRect repaintRectInLocalCoordinates() const override { return m_repaintBoundingBox; }
+    FloatRect fastRepaintRectInLocalCoordinates() const override { return repaintRectInLocalCoordinates(); }
 
     void addFocusRingRects(Vector&, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer = 0) const override;
 
diff --git a/Source/WebCore/rendering/svg/legacy/LegacyRenderSVGRoot.h b/Source/WebCore/rendering/svg/legacy/LegacyRenderSVGRoot.h
index 5f947dcd444e..21ce9d5b2deb 100644
--- a/Source/WebCore/rendering/svg/legacy/LegacyRenderSVGRoot.h
+++ b/Source/WebCore/rendering/svg/legacy/LegacyRenderSVGRoot.h
@@ -88,6 +88,7 @@ class LegacyRenderSVGRoot final : public RenderReplaced {
     FloatRect objectBoundingBox() const override { return m_objectBoundingBox; }
     FloatRect strokeBoundingBox() const override { return m_strokeBoundingBox; }
     FloatRect repaintRectInLocalCoordinates() const override { return m_repaintBoundingBox; }
+    FloatRect fastRepaintRectInLocalCoordinates() const override { return repaintRectInLocalCoordinates(); }
 
     bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) override;
 
diff --git a/Source/WebCore/rendering/svg/legacy/LegacyRenderSVGShape.h b/Source/WebCore/rendering/svg/legacy/LegacyRenderSVGShape.h
index 4170dcbc6222..e2fb76e5f607 100644
--- a/Source/WebCore/rendering/svg/legacy/LegacyRenderSVGShape.h
+++ b/Source/WebCore/rendering/svg/legacy/LegacyRenderSVGShape.h
@@ -96,6 +96,7 @@ class LegacyRenderSVGShape : public LegacyRenderSVGModelObject {
     bool strokeContains(const FloatPoint&, bool requiresStroke = true);
 
     FloatRect repaintRectInLocalCoordinates() const final { return m_repaintBoundingBox; }
+    FloatRect fastRepaintRectInLocalCoordinates() const final { return repaintRectInLocalCoordinates(); }
     const AffineTransform& localToParentTransform() const final { return m_localTransform; }
     AffineTransform localTransform() const final { return m_localTransform; }
 

From 7f9c65e1448579aad30b0ba29761465f52ea9068 Mon Sep 17 00:00:00 2001
From: Dan Glastonbury 
Date: Wed, 4 Oct 2023 19:28:05 -0700
Subject: [PATCH 13/16] [ANGLE] Fix update-angle after 268837@main
 https://bugs.webkit.org/show_bug.cgi?id=262671 rdar://116496840

Unreviewed build fix.

The use of grep to filter the output of git status interacts poorly with set
-e. When grep doesn't match any lines, a status code of 1 is returns with causes
the script to immediately exit when set -e is used.

Since we use the output, not the status code, to determine whether to proceed,
swallow the error by forcing the command result to true.

* Tools/Scripts/update-angle:

Canonical link: https://commits.webkit.org/268890@main
---
 Tools/Scripts/update-angle | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Tools/Scripts/update-angle b/Tools/Scripts/update-angle
index dc63c2fed841..435c3e6d2f4e 100755
--- a/Tools/Scripts/update-angle
+++ b/Tools/Scripts/update-angle
@@ -12,7 +12,7 @@ q="-q"
 
 # Check for modified files in WebKit ignoring untracked file except in ANGLE dir
 check_uncommitted_changes() {
-    modified_files=$(git status --porcelain | grep -e "^[^?]" -e "^?? Source/ThirdParty/ANGLE")
+    modified_files=$(git status --porcelain | grep -e "^[^?]" -e "^?? Source/ThirdParty/ANGLE") || true
     if [ -n "$modified_files" ]; then
         echo "WebKit has uncommitted or untracked changes. Commit, stash, or remove them:"
         echo "$modified_files"

From 2a3b8dbc610775d44d0fee33d9ebb2a0430fb44d Mon Sep 17 00:00:00 2001
From: Alan Baradlay 
Date: Wed, 4 Oct 2023 19:37:02 -0700
Subject: [PATCH 14/16] [IFC][Cleanup] Let's access placed floats through
 inline layout state https://bugs.webkit.org/show_bug.cgi?id=262571

Reviewed by Antti Koivisto.

* Source/WebCore/layout/formattingContexts/inline/InlineContentBalancer.cpp:
(WebCore::Layout::InlineContentBalancer::initialize):
* Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.cpp:
(WebCore::Layout::InlineFormattingContext::layout):
(WebCore::Layout::InlineFormattingContext::lineLayout):
(WebCore::Layout::InlineFormattingContext::layoutFloatContentOnly):
(WebCore::Layout::InlineFormattingContext::createDisplayContentForLineFromCachedContent):
* Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.h:
(WebCore::Layout::InlineFormattingContext::placedFloats): Deleted.
(WebCore::Layout::InlineFormattingContext::placedFloats const): Deleted.
* Source/WebCore/layout/formattingContexts/inline/InlineLayoutState.h:
(WebCore::Layout::InlineLayoutState::placedFloats const):
(WebCore::Layout::InlineLayoutState::placedFloats):
* Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.cpp:
(WebCore::Layout::LineBoxBuilder::adjustOutsideListMarkersPosition):
* Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.cpp:
(WebCore::Layout::LineBuilder::LineBuilder):
(WebCore::Layout::LineBuilder::floatConstrainedRect const):
(WebCore::Layout::LineBuilder::tryPlacingFloatBox):
(WebCore::Layout::LineBuilder::inlineLayoutState):
(WebCore::Layout::LineBuilder::placedFloats): Deleted.
* Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.h:
(WebCore::Layout::LineBuilder::floatingContext const):
(WebCore::Layout::LineBuilder::blockLayoutState const):
(WebCore::Layout::LineBuilder::placedFloats const): Deleted.

Canonical link: https://commits.webkit.org/268891@main
---
 .../inline/InlineContentBalancer.cpp               |  2 +-
 .../inline/InlineFormattingContext.cpp             |  8 ++++----
 .../inline/InlineFormattingContext.h               |  4 +---
 .../formattingContexts/inline/InlineLayoutState.h  |  3 +++
 .../inline/InlineLineBoxBuilder.cpp                |  2 +-
 .../inline/InlineLineBuilder.cpp                   | 14 +++++++-------
 .../formattingContexts/inline/InlineLineBuilder.h  |  6 ++++--
 7 files changed, 21 insertions(+), 18 deletions(-)

diff --git a/Source/WebCore/layout/formattingContexts/inline/InlineContentBalancer.cpp b/Source/WebCore/layout/formattingContexts/inline/InlineContentBalancer.cpp
index 3ab5b388202f..94a9a62ca2fd 100644
--- a/Source/WebCore/layout/formattingContexts/inline/InlineContentBalancer.cpp
+++ b/Source/WebCore/layout/formattingContexts/inline/InlineContentBalancer.cpp
@@ -112,7 +112,7 @@ InlineContentBalancer::InlineContentBalancer(InlineFormattingContext& inlineForm
 
 void InlineContentBalancer::initialize()
 {
-    if (!m_inlineFormattingContext.placedFloats().isEmpty()) {
+    if (!m_inlineFormattingContext.inlineLayoutState().placedFloats().isEmpty()) {
         m_cannotBalanceContent = true;
         return;
     }
diff --git a/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.cpp b/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.cpp
index 3aba2ae07c05..de951de9de28 100644
--- a/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.cpp
+++ b/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.cpp
@@ -72,7 +72,7 @@ InlineFormattingContext::InlineFormattingContext(const ElementBox& formattingCon
 
 InlineLayoutResult InlineFormattingContext::layout(const ConstraintsForInlineContent& constraints, const InlineDamage* lineDamage)
 {
-    auto& placedFloats = this->placedFloats();
+    auto& placedFloats = inlineLayoutState().placedFloats();
     if (!root().hasInFlowChild() && !root().hasOutOfFlowChild()) {
         // Float only content does not support partial layout.
         ASSERT(!lineDamage);
@@ -176,7 +176,7 @@ InlineLayoutResult InlineFormattingContext::lineLayout(AbstractLineBuilder& line
         return layoutResult;
     }
 
-    auto floatingContext = FloatingContext { *this, placedFloats() };
+    auto floatingContext = FloatingContext { *this, inlineLayoutState().placedFloats() };
     auto lineLogicalTop = InlineLayoutUnit { constraints.logicalTop() };
     auto previousLineEnd = std::optional { };
     auto leadingInlineItemPosition = needsLayoutRange.start;
@@ -217,7 +217,7 @@ void InlineFormattingContext::layoutFloatContentOnly(const ConstraintsForInlineC
     ASSERT(!root().hasInFlowChild());
 
     auto& inlineContentCache = this->inlineContentCache();
-    auto& placedFloats = this->placedFloats();
+    auto& placedFloats = inlineLayoutState().placedFloats();
     auto floatingContext = FloatingContext { *this, placedFloats };
 
     InlineItemsBuilder { inlineContentCache, root() }.build({ });
@@ -339,7 +339,7 @@ bool InlineFormattingContext::createDisplayContentForLineFromCachedContent(const
         inlineContentCache.clearMaximumIntrinsicWidthLayoutResult();
         return false;
     }
-    if (!placedFloats().isEmpty()) {
+    if (!inlineLayoutState().placedFloats().isEmpty()) {
         inlineContentCache.clearMaximumIntrinsicWidthLayoutResult();
         return false;
     }
diff --git a/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.h b/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.h
index 66f70b2b702a..f9329faa8675 100644
--- a/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.h
+++ b/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.h
@@ -65,13 +65,11 @@ class InlineFormattingContext : public FormattingContext {
 
     const InlineFormattingUtils& formattingUtils() const { return m_inlineFormattingUtils; }
     const InlineQuirks& quirks() const { return m_inlineQuirks; }
+
     // FIXME: This should just be "layout state" (pending on renaming LayoutState).
     InlineLayoutState& inlineLayoutState() { return m_inlineLayoutState; }
     const InlineLayoutState& inlineLayoutState() const { return m_inlineLayoutState; }
 
-    PlacedFloats& placedFloats() { return inlineLayoutState().parentBlockLayoutState().placedFloats(); }
-    const PlacedFloats& placedFloats() const { return inlineLayoutState().parentBlockLayoutState().placedFloats(); }
-
 private:
     InlineLayoutResult lineLayout(AbstractLineBuilder&, const InlineItemList&, InlineItemRange, std::optional, const ConstraintsForInlineContent&, const InlineDamage* = nullptr);
     void layoutFloatContentOnly(const ConstraintsForInlineContent&);
diff --git a/Source/WebCore/layout/formattingContexts/inline/InlineLayoutState.h b/Source/WebCore/layout/formattingContexts/inline/InlineLayoutState.h
index 895950216c87..525a59f70ea5 100644
--- a/Source/WebCore/layout/formattingContexts/inline/InlineLayoutState.h
+++ b/Source/WebCore/layout/formattingContexts/inline/InlineLayoutState.h
@@ -44,6 +44,9 @@ class InlineLayoutState {
     const BlockLayoutState& parentBlockLayoutState() const { return m_parentBlockLayoutState; }
     BlockLayoutState& parentBlockLayoutState() { return m_parentBlockLayoutState; }
 
+    const PlacedFloats& placedFloats() const { return m_parentBlockLayoutState.placedFloats(); }
+    PlacedFloats& placedFloats() { return m_parentBlockLayoutState.placedFloats(); }
+
     void setAvailableLineWidthOverride(AvailableLineWidthOverride availableLineWidthOverride) { m_availableLineWidthOverride = availableLineWidthOverride; }
     const AvailableLineWidthOverride& availableLineWidthOverride() const { return m_availableLineWidthOverride; }
 
diff --git a/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.cpp b/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.cpp
index 4efabdb199ad..47873b24a0ad 100644
--- a/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.cpp
+++ b/Source/WebCore/layout/formattingContexts/inline/InlineLineBoxBuilder.cpp
@@ -694,7 +694,7 @@ void LineBoxBuilder::computeLineBoxGeometry(LineBox& lineBox) const
 
 void LineBoxBuilder::adjustOutsideListMarkersPosition(LineBox& lineBox)
 {
-    auto floatingContext = FloatingContext { formattingContext(), formattingContext().placedFloats() };
+    auto floatingContext = FloatingContext { formattingContext(), inlineLayoutState().placedFloats() };
     auto lineBoxRect = lineBox.logicalRect();
     auto floatConstraints = floatingContext.constraints(LayoutUnit { lineBoxRect.top() }, LayoutUnit { lineBoxRect.bottom() }, FloatingContext::MayBeAboveLastFloat::No);
 
diff --git a/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.cpp b/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.cpp
index 505292f2e441..fff51fd581e9 100644
--- a/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.cpp
+++ b/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.cpp
@@ -229,6 +229,7 @@ LineBuilder::LineBuilder(InlineFormattingContext& inlineFormattingContext, Horiz
     : m_inlineFormattingContext(inlineFormattingContext)
     , m_rootHorizontalConstraints(rootHorizontalConstraints)
     , m_line(inlineFormattingContext)
+    , m_floatingContext(inlineFormattingContext, inlineFormattingContext.inlineLayoutState().placedFloats())
     , m_inlineItemList(inlineItemList)
 {
 }
@@ -742,10 +743,10 @@ static inline InlineLayoutUnit availableWidth(const LineCandidate::InlineContent
 LineBuilder::UsedConstraints LineBuilder::floatConstrainedRect(const InlineRect& logicalRect, InlineLayoutUnit marginStart) const
 {
     auto constraints = [&]() -> LineBuilder::UsedConstraints {
-        if (isInIntrinsicWidthMode() || placedFloats().isEmpty())
+        if (isInIntrinsicWidthMode() || floatingContext().isEmpty())
             return { logicalRect, marginStart, { } };
 
-        auto constraints = formattingContext().formattingUtils().floatConstraintsForLine(logicalRect.top(), logicalRect.height(), FloatingContext { formattingContext(), placedFloats() });
+        auto constraints = formattingContext().formattingUtils().floatConstraintsForLine(logicalRect.top(), logicalRect.height(), floatingContext());
         if (!constraints.left && !constraints.right)
             return { logicalRect, marginStart, { } };
 
@@ -888,7 +889,7 @@ bool LineBuilder::tryPlacingFloatBox(const Box& floatBox, MayOverConstrainLine m
     if (isFloatLayoutSuspended())
         return false;
 
-    auto floatingContext = FloatingContext { formattingContext(), placedFloats() };
+    auto& floatingContext = this->floatingContext();
     auto boxGeometry = [&]() -> BoxGeometry {
         auto marginTrim = rootStyle().marginTrim();
         if (!marginTrim.containsAny({ MarginTrimType::InlineStart, MarginTrimType::InlineEnd }) || m_lineIsConstrainedByFloat.containsAll({ UsedFloat::Left, UsedFloat::Right }))
@@ -955,8 +956,7 @@ bool LineBuilder::tryPlacingFloatBox(const Box& floatBox, MayOverConstrainLine m
     auto placeFloatBox = [&] {
         auto lineIndex = m_previousLine ? (m_previousLine->lineIndex + 1) : 0lu;
         auto floatItem = floatingContext.makeFloatItem(floatBox, boxGeometry, lineIndex);
-        // FIXME: Maybe FloatingContext should be able to preserve FloatItems and the caller should mutate the PlacedFloats instead.
-        placedFloats().append(floatItem);
+        inlineLayoutState().placedFloats().append(floatItem);
         m_placedFloats.append(floatItem);
     };
     placeFloatBox();
@@ -1238,9 +1238,9 @@ const InlineLayoutState& LineBuilder::inlineLayoutState() const
     return formattingContext().inlineLayoutState();
 }
 
-PlacedFloats& LineBuilder::placedFloats()
+InlineLayoutState& LineBuilder::inlineLayoutState()
 {
-    return formattingContext().placedFloats();
+    return formattingContext().inlineLayoutState();
 }
 
 }
diff --git a/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.h b/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.h
index e2467ae8677c..553c6f1d6e1f 100644
--- a/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.h
+++ b/Source/WebCore/layout/formattingContexts/inline/InlineLineBuilder.h
@@ -93,10 +93,11 @@ class LineBuilder : public AbstractLineBuilder {
 
     InlineFormattingContext& formattingContext() { return m_inlineFormattingContext; }
     const InlineFormattingContext& formattingContext() const { return m_inlineFormattingContext; }
+    const FloatingContext& floatingContext() const { return m_floatingContext; }
+
     const InlineLayoutState& inlineLayoutState() const;
+    InlineLayoutState& inlineLayoutState();
     const BlockLayoutState& blockLayoutState() const { return inlineLayoutState().parentBlockLayoutState(); }
-    PlacedFloats& placedFloats();
-    const PlacedFloats& placedFloats() const { return const_cast(*this).placedFloats(); }
     const ElementBox& root() const;
     const RenderStyle& rootStyle() const;
 
@@ -106,6 +107,7 @@ class LineBuilder : public AbstractLineBuilder {
     std::optional m_rootHorizontalConstraints;
 
     Line m_line;
+    FloatingContext m_floatingContext;
     InlineRect m_lineInitialLogicalRect;
     InlineRect m_lineLogicalRect;
     InlineLayoutUnit m_lineMarginStart { 0.f };

From f7984e2d658a06fc1380090ab7bd14f7c3a5e554 Mon Sep 17 00:00:00 2001
From: Eric Carlson 
Date: Wed, 4 Oct 2023 15:21:31 -0700
Subject: [PATCH 15/16] [MediaStream] Add support for
 ImageCapture.getPhotoSettings https://bugs.webkit.org/show_bug.cgi?id=262466
 rdar://116322614

Reviewed by NOBODY (OOPS!).

Add ImageCapture.getPhotoSettings and implement support in MockRealtimeVideoSource and
AVVideoCaptureSource.

* LayoutTests/fast/mediastream/image-capture-get-photo-settings-expected.txt: Added.
* LayoutTests/fast/mediastream/image-capture-get-photo-settings.html: Added.
* Source/WebCore/DerivedSources.make:

* Source/WebCore/Modules/mediastream/ImageCapture.cpp:
(WebCore::ImageCapture::getPhotoSettings):
* Source/WebCore/Modules/mediastream/ImageCapture.h:
* Source/WebCore/Modules/mediastream/ImageCapture.idl:

* Source/WebCore/Modules/mediastream/MediaStreamTrack.cpp:
(WebCore::MediaStreamTrack::getPhotoSettings const):
* Source/WebCore/Modules/mediastream/MediaStreamTrack.h:

* Source/WebCore/Modules/mediastream/PhotoSettings.idl: Added.

* Source/WebCore/Sources.txt:
* Source/WebCore/WebCore.xcodeproj/project.pbxproj:

* Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.cpp:
(WebCore::MediaStreamTrackPrivate::getPhotoSettings):
* Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.h:

* Source/WebCore/platform/mediastream/PhotoSettings.h: Added.

* Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp:
(WebCore::RealtimeMediaSource::getPhotoSettings):
* Source/WebCore/platform/mediastream/RealtimeMediaSource.h:
(WebCore::PhotoSettingsOrError::PhotoSettingsOrError):
(WebCore::PhotoSettingsOrError::operator bool const):

* Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.h:
* Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.mm:
(WebCore::toFillLightMode):
(WebCore::AVVideoCaptureSource::getPhotoSettings):

* Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp:
(WebCore::MockRealtimeVideoSource::getPhotoSettings):
(WebCore::MockRealtimeVideoSource::settingsDidChange):
* Source/WebCore/platform/mock/MockRealtimeVideoSource.h:

* Source/WebKit/Scripts/webkit/messages.py:
(headers_for_type):

* Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in:

* Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.cpp:
(WebKit::UserMediaCaptureManagerProxy::SourceProxy::getPhotoSettings):
(WebKit::UserMediaCaptureManagerProxy::getPhotoSettings):
* Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.h:
* Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.messages.in:

* Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSource.cpp:
(WebKit::RemoteRealtimeMediaSource::getPhotoSettings):
* Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSource.h:

* Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSourceProxy.cpp:
(WebKit::RemoteRealtimeMediaSourceProxy::getPhotoSettings):
* Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSourceProxy.h:
---
 ...ge-capture-get-photo-settings-expected.txt |  5 ++
 .../image-capture-get-photo-settings.html     | 48 +++++++++++++++++++
 Source/WebCore/CMakeLists.txt                 |  1 +
 Source/WebCore/DerivedSources.make            |  1 +
 Source/WebCore/Headers.cmake                  |  1 +
 .../Modules/mediastream/ImageCapture.cpp      | 10 ++++
 .../Modules/mediastream/ImageCapture.h        |  4 ++
 .../Modules/mediastream/ImageCapture.idl      |  3 +-
 .../Modules/mediastream/MediaStreamTrack.cpp  | 17 +++++++
 .../Modules/mediastream/MediaStreamTrack.h    |  2 +
 .../Modules/mediastream/PhotoSettings.idl     | 35 ++++++++++++++
 Source/WebCore/Sources.txt                    |  1 +
 .../WebCore/WebCore.xcodeproj/project.pbxproj | 12 +++++
 .../mediastream/MediaStreamTrackPrivate.cpp   |  5 ++
 .../mediastream/MediaStreamTrackPrivate.h     |  1 +
 .../platform/mediastream/PhotoSettings.h      | 44 +++++++++++++++++
 .../mediastream/RealtimeMediaSource.cpp       |  5 ++
 .../mediastream/RealtimeMediaSource.h         | 24 ++++++++++
 .../mediastream/mac/AVVideoCaptureSource.h    |  2 +
 .../mediastream/mac/AVVideoCaptureSource.mm   | 40 ++++++++++++++++
 .../platform/mock/MockRealtimeVideoSource.cpp | 26 ++++++++++
 .../platform/mock/MockRealtimeVideoSource.h   |  2 +
 Source/WebKit/Scripts/webkit/messages.py      |  1 +
 .../WebCoreArgumentCoders.serialization.in    | 14 ++++++
 .../Cocoa/UserMediaCaptureManagerProxy.cpp    | 15 ++++++
 .../Cocoa/UserMediaCaptureManagerProxy.h      |  5 +-
 .../UserMediaCaptureManagerProxy.messages.in  |  1 +
 .../cocoa/RemoteRealtimeMediaSource.cpp       |  5 ++
 .../cocoa/RemoteRealtimeMediaSource.h         |  1 +
 .../cocoa/RemoteRealtimeMediaSourceProxy.cpp  |  5 ++
 .../cocoa/RemoteRealtimeMediaSourceProxy.h    |  1 +
 31 files changed, 334 insertions(+), 3 deletions(-)
 create mode 100644 LayoutTests/fast/mediastream/image-capture-get-photo-settings-expected.txt
 create mode 100644 LayoutTests/fast/mediastream/image-capture-get-photo-settings.html
 create mode 100644 Source/WebCore/Modules/mediastream/PhotoSettings.idl
 create mode 100644 Source/WebCore/platform/mediastream/PhotoSettings.h

diff --git a/LayoutTests/fast/mediastream/image-capture-get-photo-settings-expected.txt b/LayoutTests/fast/mediastream/image-capture-get-photo-settings-expected.txt
new file mode 100644
index 000000000000..bd6bb23b02c1
--- /dev/null
+++ b/LayoutTests/fast/mediastream/image-capture-get-photo-settings-expected.txt
@@ -0,0 +1,5 @@
+
+
+PASS getPhotoSettings() on an 'ended' track should throw "InvalidStateError"
+PASS Check getPhotoSettings()
+
diff --git a/LayoutTests/fast/mediastream/image-capture-get-photo-settings.html b/LayoutTests/fast/mediastream/image-capture-get-photo-settings.html
new file mode 100644
index 000000000000..ebf1598b1322
--- /dev/null
+++ b/LayoutTests/fast/mediastream/image-capture-get-photo-settings.html
@@ -0,0 +1,48 @@
+
+
+
+    
+    ImageCapture getPhotoSettings
+    
+    
+
+
+    
+    
+
+
diff --git a/Source/WebCore/CMakeLists.txt b/Source/WebCore/CMakeLists.txt
index cdbd0f9ac004..14858ef2a6a0 100644
--- a/Source/WebCore/CMakeLists.txt
+++ b/Source/WebCore/CMakeLists.txt
@@ -459,6 +459,7 @@ set(WebCore_NON_SVG_IDL_FILES
     Modules/mediastream/OverconstrainedError.idl
     Modules/mediastream/OverconstrainedErrorEvent.idl
     Modules/mediastream/PhotoCapabilities.idl
+    Modules/mediastream/PhotoSettings.idl
     Modules/mediastream/RTCAnswerOptions.idl
     Modules/mediastream/RTCCertificate.idl
     Modules/mediastream/RTCConfiguration.idl
diff --git a/Source/WebCore/DerivedSources.make b/Source/WebCore/DerivedSources.make
index 628808d00706..503a7228a692 100644
--- a/Source/WebCore/DerivedSources.make
+++ b/Source/WebCore/DerivedSources.make
@@ -454,6 +454,7 @@ JS_BINDING_IDLS := \
     $(WebCore)/Modules/mediastream/OverconstrainedError.idl \
     $(WebCore)/Modules/mediastream/OverconstrainedErrorEvent.idl \
     $(WebCore)/Modules/mediastream/PhotoCapabilities.idl \
+    $(WebCore)/Modules/mediastream/PhotoSettings.idl \
     $(WebCore)/Modules/mediastream/RedEyeReduction.idl \
     $(WebCore)/Modules/mediastream/RTCAnswerOptions.idl \
     $(WebCore)/Modules/mediastream/RTCCertificate.idl \
diff --git a/Source/WebCore/Headers.cmake b/Source/WebCore/Headers.cmake
index 964b0a2aea25..0e5a2800cf1e 100644
--- a/Source/WebCore/Headers.cmake
+++ b/Source/WebCore/Headers.cmake
@@ -2152,6 +2152,7 @@ set(WebCore_PRIVATE_FRAMEWORK_HEADERS
     platform/mediastream/MediaStreamTrackPrivate.h
     platform/mediastream/MeteringMode.h
     platform/mediastream/PhotoCapabilities.h
+    platform/mediastream/PhotoSettings.h
     platform/mediastream/RedEyeReduction.h
     platform/mediastream/RTCDataChannelHandler.h
     platform/mediastream/RTCDataChannelHandlerClient.h
diff --git a/Source/WebCore/Modules/mediastream/ImageCapture.cpp b/Source/WebCore/Modules/mediastream/ImageCapture.cpp
index 0e3ac2b9223d..3fb8da362196 100644
--- a/Source/WebCore/Modules/mediastream/ImageCapture.cpp
+++ b/Source/WebCore/Modules/mediastream/ImageCapture.cpp
@@ -63,6 +63,16 @@ void ImageCapture::getPhotoCapabilities(PhotoCapabilitiesPromise&& promise)
     m_track->getPhotoCapabilities(WTFMove(promise));
 }
 
+void ImageCapture::getPhotoSettings(PhotoSettingsPromise&& promise)
+{
+    if (m_track->readyState() == MediaStreamTrack::State::Ended) {
+        promise.reject(Exception { InvalidStateError, "Track has ended"_s });
+        return;
+    }
+
+    m_track->getPhotoSettings(WTFMove(promise));
+}
+
 const char* ImageCapture::activeDOMObjectName() const
 {
     return "ImageCapture";
diff --git a/Source/WebCore/Modules/mediastream/ImageCapture.h b/Source/WebCore/Modules/mediastream/ImageCapture.h
index eaa2024fd3aa..ff03eda74dc8 100644
--- a/Source/WebCore/Modules/mediastream/ImageCapture.h
+++ b/Source/WebCore/Modules/mediastream/ImageCapture.h
@@ -32,6 +32,7 @@
 #include "JSDOMPromiseDeferred.h"
 #include "MediaStreamTrack.h"
 #include "PhotoCapabilities.h"
+#include "PhotoSettings.h"
 
 namespace WebCore {
 
@@ -45,6 +46,9 @@ class ImageCapture : public RefCounted, public ActiveDOMObject {
     using PhotoCapabilitiesPromise = DOMPromiseDeferred>;
     void getPhotoCapabilities(PhotoCapabilitiesPromise&&);
 
+    using PhotoSettingsPromise = DOMPromiseDeferred>;
+    void getPhotoSettings(PhotoSettingsPromise&&);
+
     Ref track() const { return m_track; }
 
 private:
diff --git a/Source/WebCore/Modules/mediastream/ImageCapture.idl b/Source/WebCore/Modules/mediastream/ImageCapture.idl
index a5a11da93201..0dd7ff529f56 100644
--- a/Source/WebCore/Modules/mediastream/ImageCapture.idl
+++ b/Source/WebCore/Modules/mediastream/ImageCapture.idl
@@ -37,8 +37,7 @@
     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=262467
     // Promise takePhoto(optional PhotoSettings photoSettings = {});
 
-    // FIXME: https://bugs.webkit.org/show_bug.cgi?id=262466
-    // Promise getPhotoSettings();
+    Promise getPhotoSettings();
 
     readonly attribute MediaStreamTrack track;
 };
diff --git a/Source/WebCore/Modules/mediastream/MediaStreamTrack.cpp b/Source/WebCore/Modules/mediastream/MediaStreamTrack.cpp
index f87658719064..9f74482bebd2 100644
--- a/Source/WebCore/Modules/mediastream/MediaStreamTrack.cpp
+++ b/Source/WebCore/Modules/mediastream/MediaStreamTrack.cpp
@@ -39,6 +39,7 @@
 #include "JSMeteringMode.h"
 #include "JSOverconstrainedError.h"
 #include "JSPhotoCapabilities.h"
+#include "JSPhotoSettings.h"
 #include "LocalFrame.h"
 #include "Logging.h"
 #include "MediaConstraints.h"
@@ -328,6 +329,22 @@ void MediaStreamTrack::getPhotoCapabilities(DOMPromiseDeferred>&& promise) const
+{
+    m_private->getPhotoSettings([protectedThis = Ref { *this }, promise = WTFMove(promise)](auto&& result) mutable {
+        if (!result) {
+            // https://w3c.github.io/mediacapture-image/#ref-for-dom-imagecapture-getphotosettings②
+            // If the data cannot be gathered for any reason (for example, the MediaStreamTrack being ended
+            // asynchronously), then reject p with a new DOMException whose name is OperationError, and
+            // abort these steps.
+            promise.reject(Exception { OperationError, WTFMove(result.errorMessage) });
+            return;
+        }
+
+        promise.resolve(WTFMove(*result.settings));
+    });
+}
+
 static MediaConstraints createMediaConstraints(const std::optional& constraints)
 {
     if (!constraints) {
diff --git a/Source/WebCore/Modules/mediastream/MediaStreamTrack.h b/Source/WebCore/Modules/mediastream/MediaStreamTrack.h
index db7d35ac13bd..a8d32011d050 100644
--- a/Source/WebCore/Modules/mediastream/MediaStreamTrack.h
+++ b/Source/WebCore/Modules/mediastream/MediaStreamTrack.h
@@ -39,6 +39,7 @@
 #include "MediaTrackCapabilities.h"
 #include "MediaTrackConstraints.h"
 #include "PhotoCapabilities.h"
+#include "PhotoSettings.h"
 #include "PlatformMediaSession.h"
 #include 
 
@@ -130,6 +131,7 @@ class MediaStreamTrack
     TrackCapabilities getCapabilities() const;
 
     void getPhotoCapabilities(DOMPromiseDeferred>&&) const;
+    void getPhotoSettings(DOMPromiseDeferred>&&) const;
 
     const MediaTrackConstraints& getConstraints() const { return m_constraints; }
     void setConstraints(MediaTrackConstraints&& constraints) { m_constraints = WTFMove(constraints); }
diff --git a/Source/WebCore/Modules/mediastream/PhotoSettings.idl b/Source/WebCore/Modules/mediastream/PhotoSettings.idl
new file mode 100644
index 000000000000..9c7f355ef4ec
--- /dev/null
+++ b/Source/WebCore/Modules/mediastream/PhotoSettings.idl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2023 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// https://w3c.github.io/mediacapture-image/#photosettings-section
+
+[
+    Conditional=MEDIA_STREAM,
+    JSGenerateToJSObject
+] dictionary PhotoSettings {
+    FillLightMode   fillLightMode;
+    double          imageHeight;
+    double          imageWidth;
+    boolean         redEyeReduction;
+};
diff --git a/Source/WebCore/Sources.txt b/Source/WebCore/Sources.txt
index f0bcd009d37f..016c117a3825 100644
--- a/Source/WebCore/Sources.txt
+++ b/Source/WebCore/Sources.txt
@@ -3966,6 +3966,7 @@ JSPermissionState.cpp
 JSPermissionStatus.cpp
 JSPermissions.cpp
 JSPhotoCapabilities.cpp
+JSPhotoSettings.cpp
 JSPictureInPictureEvent.cpp
 JSPictureInPictureWindow.cpp
 JSPlaneLayout.cpp
diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj
index f26f29258155..4cc7429f38c2 100644
--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj
+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj
@@ -136,6 +136,8 @@
 		073930DC2AC6452800C1D1B1 /* MeteringMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 073930DB2AC6452700C1D1B1 /* MeteringMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		073930DE2AC6478C00C1D1B1 /* MediaSettingsRange.h in Headers */ = {isa = PBXBuildFile; fileRef = 073930DD2AC6478B00C1D1B1 /* MediaSettingsRange.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		073930E02AC6490B00C1D1B1 /* PhotoCapabilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 073930DF2AC6490B00C1D1B1 /* PhotoCapabilities.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		073931172ACC6D1E00C1D1B1 /* PhotoSettings.h in Headers */ = {isa = PBXBuildFile; fileRef = 073931162ACC6D1D00C1D1B1 /* PhotoSettings.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		0739311A2ACCBF3C00C1D1B1 /* JSPhotoSettings.h in Headers */ = {isa = PBXBuildFile; fileRef = 073931182ACCBF3B00C1D1B1 /* JSPhotoSettings.h */; };
 		073955BB27AB277F009A08D2 /* ScreenCaptureKitSharingSessionManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 07035D3227A9B60B00FB03E4 /* ScreenCaptureKitSharingSessionManager.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		073B87671E4385AC0071C0EC /* AudioSampleBufferList.h in Headers */ = {isa = PBXBuildFile; fileRef = 073B87631E43859D0071C0EC /* AudioSampleBufferList.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		073B87691E4385AC0071C0EC /* AudioSampleDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 073B87651E43859D0071C0EC /* AudioSampleDataSource.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -6735,6 +6737,10 @@
 		073930DB2AC6452700C1D1B1 /* MeteringMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MeteringMode.h; sourceTree = ""; };
 		073930DD2AC6478B00C1D1B1 /* MediaSettingsRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaSettingsRange.h; sourceTree = ""; };
 		073930DF2AC6490B00C1D1B1 /* PhotoCapabilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PhotoCapabilities.h; sourceTree = ""; };
+		073931142ACC6CEE00C1D1B1 /* PhotoSettings.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = PhotoSettings.idl; sourceTree = ""; };
+		073931162ACC6D1D00C1D1B1 /* PhotoSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PhotoSettings.h; sourceTree = ""; };
+		073931182ACCBF3B00C1D1B1 /* JSPhotoSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSPhotoSettings.h; path = JSPhotoSettings.h; sourceTree = ""; };
+		073931192ACCBF3B00C1D1B1 /* JSPhotoSettings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JSPhotoSettings.cpp; path = JSPhotoSettings.cpp; sourceTree = ""; };
 		073B87561E40DCE50071C0EC /* AudioStreamDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioStreamDescription.h; sourceTree = ""; };
 		073B87571E40DCFD0071C0EC /* CAAudioStreamDescription.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CAAudioStreamDescription.cpp; sourceTree = ""; };
 		073B87581E40DCFD0071C0EC /* CAAudioStreamDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CAAudioStreamDescription.h; sourceTree = ""; };
@@ -20493,6 +20499,7 @@
 				41E408381DCB747900EFCE19 /* PeerConnectionBackend.cpp */,
 				5E2C434D1BCEE2E50001E2BC /* PeerConnectionBackend.h */,
 				073FF3A12AC4C96D0099275E /* PhotoCapabilities.idl */,
+				073931142ACC6CEE00C1D1B1 /* PhotoSettings.idl */,
 				073FF37F2AC3ADED0099275E /* RedEyeReduction.idl */,
 				316DCB2B1E78F3A9001B5F87 /* RTCAnswerOptions.h */,
 				316DCB2C1E78F3A9001B5F87 /* RTCAnswerOptions.idl */,
@@ -20720,6 +20727,7 @@
 				073930DB2AC6452700C1D1B1 /* MeteringMode.h */,
 				5EBB89381C77BDA400C65D41 /* PeerMediaDescription.h */,
 				073930DF2AC6490B00C1D1B1 /* PhotoCapabilities.h */,
+				073931162ACC6D1D00C1D1B1 /* PhotoSettings.h */,
 				41103AAA1E39790A00769F03 /* RealtimeIncomingAudioSource.cpp */,
 				41103AA91E39790A00769F03 /* RealtimeIncomingAudioSource.h */,
 				5CDD83391E4324BB00621E92 /* RealtimeIncomingVideoSource.cpp */,
@@ -20916,6 +20924,8 @@
 				0704A4141D6F39FB0086DCDB /* JSOverconstrainedErrorEvent.h */,
 				073930BB2AC4D2CA00C1D1B1 /* JSPhotoCapabilities.cpp */,
 				073930B72AC4D29E00C1D1B1 /* JSPhotoCapabilities.h */,
+				073931192ACCBF3B00C1D1B1 /* JSPhotoSettings.cpp */,
+				073931182ACCBF3B00C1D1B1 /* JSPhotoSettings.h */,
 				073FF3862AC4825E0099275E /* JSRedEyeReduction.cpp */,
 				073FF3872AC4825E0099275E /* JSRedEyeReduction.h */,
 				316DCB2D1E78F496001B5F87 /* JSRTCAnswerOptions.cpp */,
@@ -39630,6 +39640,7 @@
 				8A9A588811E84F37008ACFD1 /* JSPerformanceTiming.h in Headers */,
 				FDEA6247152102FC00479DF0 /* JSPeriodicWave.h in Headers */,
 				073930B92AC4D29F00C1D1B1 /* JSPhotoCapabilities.h in Headers */,
+				0739311A2ACCBF3C00C1D1B1 /* JSPhotoSettings.h in Headers */,
 				1D0026A42374D62400CA6CDF /* JSPictureInPictureWindow.h in Headers */,
 				712BE4891FE86875002031CC /* JSPlaybackDirection.h in Headers */,
 				93B70D6C09EB0C7C009D8468 /* JSPluginElementFunctions.h in Headers */,
@@ -40628,6 +40639,7 @@
 				93B0A65626CDD14100AA21E4 /* PermissionStatus.h in Headers */,
 				49D5DC2E0F423A73008F20FD /* PerspectiveTransformOperation.h in Headers */,
 				073930E02AC6490B00C1D1B1 /* PhotoCapabilities.h in Headers */,
+				073931172ACC6D1E00C1D1B1 /* PhotoSettings.h in Headers */,
 				1D2F8E042344751600993B68 /* PictureInPictureEvent.h in Headers */,
 				1DBC1B562347B3D200B901AF /* PictureInPictureObserver.h in Headers */,
 				1D2C82B7236A3F6A0055D6C5 /* PictureInPictureSupport.h in Headers */,
diff --git a/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.cpp b/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.cpp
index 1df3c4f7f2d2..661a5dd6998e 100644
--- a/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.cpp
+++ b/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.cpp
@@ -188,6 +188,11 @@ void MediaStreamTrackPrivate::getPhotoCapabilities(RealtimeMediaSource::PhotoCap
     m_source->getPhotoCapabilities(WTFMove(completion));
 }
 
+void MediaStreamTrackPrivate::getPhotoSettings(RealtimeMediaSource::PhotoSettingsHandler&& completion)
+{
+    m_source->getPhotoSettings(WTFMove(completion));
+}
+
 void MediaStreamTrackPrivate::applyConstraints(const MediaConstraints& constraints, RealtimeMediaSource::ApplyConstraintsHandler&& completionHandler)
 {
     m_source->applyConstraints(constraints, WTFMove(completionHandler));
diff --git a/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.h b/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.h
index b7017a9b65c4..e279fef28b07 100644
--- a/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.h
+++ b/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.h
@@ -111,6 +111,7 @@ class MediaStreamTrackPrivate final
     const RealtimeMediaSourceCapabilities& capabilities() const;
 
     void getPhotoCapabilities(RealtimeMediaSource::PhotoCapabilitiesHandler&&);
+    void getPhotoSettings(RealtimeMediaSource::PhotoSettingsHandler&&);
 
     void applyConstraints(const MediaConstraints&, RealtimeMediaSource::ApplyConstraintsHandler&&);
 
diff --git a/Source/WebCore/platform/mediastream/PhotoSettings.h b/Source/WebCore/platform/mediastream/PhotoSettings.h
new file mode 100644
index 000000000000..3e3a15ef41c8
--- /dev/null
+++ b/Source/WebCore/platform/mediastream/PhotoSettings.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2023 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(MEDIA_STREAM)
+
+#include 
+
+namespace WebCore {
+
+enum class FillLightMode : uint8_t;
+
+struct PhotoSettings {
+    std::optional fillLightMode;
+    std::optional imageHeight;
+    std::optional imageWidth;
+    std::optional redEyeReduction;
+};
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp b/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp
index b688267b0a00..5ac5bd5e9d2a 100644
--- a/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp
+++ b/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp
@@ -1460,6 +1460,11 @@ void RealtimeMediaSource::getPhotoCapabilities(PhotoCapabilitiesHandler&& comple
     completion(PhotoCapabilitiesOrError("Not supported"_s));
 }
 
+void RealtimeMediaSource::getPhotoSettings(PhotoSettingsHandler&& completion)
+{
+    completion(PhotoSettingsOrError("Not supported"_s));
+}
+
 RealtimeMediaSource::Observer::~Observer()
 {
 }
diff --git a/Source/WebCore/platform/mediastream/RealtimeMediaSource.h b/Source/WebCore/platform/mediastream/RealtimeMediaSource.h
index 286cade60155..2b07db63ae51 100644
--- a/Source/WebCore/platform/mediastream/RealtimeMediaSource.h
+++ b/Source/WebCore/platform/mediastream/RealtimeMediaSource.h
@@ -41,6 +41,7 @@
 #include "MediaConstraints.h"
 #include "MediaDeviceHashSalts.h"
 #include "PhotoCapabilities.h"
+#include "PhotoSettings.h"
 #include "PlatformLayer.h"
 #include "RealtimeMediaSourceCapabilities.h"
 #include "RealtimeMediaSourceFactory.h"
@@ -80,6 +81,7 @@ enum class VideoFrameRotation : uint16_t;
 struct CaptureSourceError;
 struct CaptureSourceOrError;
 struct PhotoCapabilitiesOrError;
+struct PhotoSettingsOrError;
 struct VideoFrameAdaptor;
 
 class WEBCORE_EXPORT RealtimeMediaSource
@@ -212,6 +214,9 @@ class WEBCORE_EXPORT RealtimeMediaSource
     using PhotoCapabilitiesHandler = CompletionHandler;
     virtual void getPhotoCapabilities(PhotoCapabilitiesHandler&&);
 
+    using PhotoSettingsHandler = CompletionHandler;
+    virtual void getPhotoSettings(PhotoSettingsHandler&&);
+
     struct ApplyConstraintsError {
         String badConstraint;
         String message;
@@ -416,6 +421,25 @@ struct PhotoCapabilitiesOrError {
     String errorMessage;
 };
 
+struct PhotoSettingsOrError {
+    PhotoSettingsOrError() = default;
+    PhotoSettingsOrError(std::optional&& settings, String&& errorMessage)
+        : settings(WTFMove(settings))
+        , errorMessage(WTFMove(errorMessage))
+    { }
+    PhotoSettingsOrError(PhotoSettings& settings)
+        : settings({ settings })
+    { }
+    explicit PhotoSettingsOrError(String&& errorMessage)
+        : errorMessage(WTFMove(errorMessage))
+    { }
+
+    operator bool() const { return settings.has_value(); }
+
+    std::optional settings;
+    String errorMessage;
+};
+
 String convertEnumerationToString(RealtimeMediaSource::Type);
 
 inline void RealtimeMediaSource::setName(const AtomString& name)
diff --git a/Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.h b/Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.h
index 21f55776067c..3b4bea5d1284 100644
--- a/Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.h
+++ b/Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.h
@@ -85,6 +85,7 @@ class AVVideoCaptureSource : public RealtimeVideoCaptureSource, private Orientat
     const RealtimeMediaSourceCapabilities& capabilities() final;
     const RealtimeMediaSourceSettings& settings() final;
     void getPhotoCapabilities(PhotoCapabilitiesHandler&&) final;
+    void getPhotoSettings(PhotoSettingsHandler&&) final;
     double facingModeFitnessScoreAdjustment() const final;
     void startProducingData() final;
     void stopProducingData() final;
@@ -147,6 +148,7 @@ class AVVideoCaptureSource : public RealtimeVideoCaptureSource, private Orientat
     std::optional m_currentSettings;
     std::optional m_capabilities;
     std::optional m_photoCapabilities;
+    std::optional m_photoSettings;
     RetainPtr m_objcObserver;
     RetainPtr m_session;
     RetainPtr m_device;
diff --git a/Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.mm b/Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.mm
index 31b66ccb79ef..9f8c1243d6e2 100644
--- a/Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.mm
+++ b/Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.mm
@@ -28,6 +28,7 @@
 
 #if ENABLE(MEDIA_STREAM) && USE(AVFOUNDATION)
 
+#import "FillLightMode.h"
 #import "ImageBuffer.h"
 #import "ImageTransferSessionVT.h"
 #import "IntRect.h"
@@ -467,6 +468,45 @@ static bool isZoomSupported(const Vector& presets)
     completion({ *m_photoCapabilities });
 }
 
+static FillLightMode toFillLightMode(AVCaptureTorchMode mode)
+{
+    switch (mode) {
+    case AVCaptureTorchModeOff:
+        return FillLightMode::Off;
+        break;
+    case AVCaptureTorchModeOn:
+        return FillLightMode::Flash;
+        break;
+    case AVCaptureTorchModeAuto:
+        return FillLightMode::Auto;
+        break;
+    }
+
+    ASSERT_NOT_REACHED();
+    return FillLightMode::Auto;
+}
+
+void AVVideoCaptureSource::getPhotoSettings(PhotoSettingsHandler&& completion)
+{
+    if (m_photoSettings) {
+        completion({ *m_photoSettings });
+        return;
+    }
+
+    PhotoSettings photoSettings;
+    auto settings = this->settings();
+
+    photoSettings.imageHeight = settings.height();
+    photoSettings.imageWidth = settings.width();
+
+    if ([device() hasTorch])
+        photoSettings.fillLightMode = { toFillLightMode([device() torchMode]) };
+
+    m_photoSettings = WTFMove(photoSettings);
+
+    completion({ *m_photoSettings });
+}
+
 NSMutableArray* AVVideoCaptureSource::cameraCaptureDeviceTypes()
 {
     ASSERT(isMainThread());
diff --git a/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp b/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp
index ed4af67cba09..87f404e65c6c 100644
--- a/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp
+++ b/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp
@@ -33,6 +33,7 @@
 
 #if ENABLE(MEDIA_STREAM)
 #include "CaptureDevice.h"
+#include "FillLightMode.h"
 #include "GraphicsContext.h"
 #include "ImageBuffer.h"
 #include "IntRect.h"
@@ -202,6 +203,29 @@ void MockRealtimeVideoSource::getPhotoCapabilities(PhotoCapabilitiesHandler&& co
     completion({ *m_photoCapabilities });
 }
 
+void MockRealtimeVideoSource::getPhotoSettings(PhotoSettingsHandler&& completion)
+{
+    if (m_photoSettings) {
+        completion({ *m_photoSettings });
+        return;
+    }
+
+    PhotoSettings photoSettings;
+    auto settings = this->settings();
+
+    photoSettings.imageHeight = settings.height();
+    photoSettings.imageWidth = settings.width();
+
+    if (std::get(m_device.properties).hasTorch) {
+        auto fillLightMode = torch() ? FillLightMode::Flash : FillLightMode::Off;
+        photoSettings.fillLightMode = { fillLightMode };
+    }
+
+    m_photoSettings = WTFMove(photoSettings);
+
+    completion({ *m_photoSettings });
+}
+
 static bool isZoomSupported(const Vector& presets)
 {
     return anyOf(presets, [](auto& preset) {
@@ -300,6 +324,8 @@ void MockRealtimeVideoSource::settingsDidChange(OptionSet m_capabilities;
     std::optional m_currentSettings;
     std::optional m_photoCapabilities;
+    std::optional m_photoSettings;
     RealtimeMediaSourceSupportedConstraints m_supportedConstraints;
     Color m_fillColor { Color::black };
     Color m_fillColorWithZoom { Color::red };
diff --git a/Source/WebKit/Scripts/webkit/messages.py b/Source/WebKit/Scripts/webkit/messages.py
index ce4cea2042f7..eef151643e5e 100644
--- a/Source/WebKit/Scripts/webkit/messages.py
+++ b/Source/WebKit/Scripts/webkit/messages.py
@@ -801,6 +801,7 @@ def headers_for_type(type):
         'WebCore::PathDataQuadCurve': [''],
         'WebCore::PixelFormat': [''],
         'WebCore::PhotoCapabilitiesOrError': [''],
+        'WebCore::PhotoSettingsOrError': [''],
         'WebCore::PlatformTextTrackData': [''],
         'WebCore::PlatformWheelEventPhase': [''],
         'WebCore::PlaybackSessionModel::PlaybackState': [''],
diff --git a/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in b/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in
index 053359a64dcf..7cadea1ba8b2 100644
--- a/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in
+++ b/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in
@@ -5877,11 +5877,25 @@ header: 
     std::optional> fillLightMode;
 };
 
+header: 
+[CustomHeader] struct WebCore::PhotoSettings {
+    std::optional fillLightMode;
+    std::optional imageHeight;
+    std::optional imageWidth;
+    std::optional redEyeReduction;
+};
+
 header: 
 [CustomHeader] struct WebCore::PhotoCapabilitiesOrError {
     std::optional capabilities;
     String errorMessage;
 };
+
+header: 
+[CustomHeader] struct WebCore::PhotoSettingsOrError {
+    std::optional settings;
+    String errorMessage;
+};
 #endif
 
 header: 
diff --git a/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.cpp b/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.cpp
index 5f1f1956d4aa..dadecf5a1fce 100644
--- a/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.cpp
+++ b/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.cpp
@@ -194,6 +194,11 @@ class UserMediaCaptureManagerProxy::SourceProxy
         m_source->getPhotoCapabilities(WTFMove(handler));
     }
 
+    void getPhotoSettings(GetPhotoSettingsCallback&& handler)
+    {
+        m_source->getPhotoSettings(WTFMove(handler));
+    }
+
 private:
     void sourceStopped() final {
         m_connection->send(Messages::UserMediaCaptureManager::SourceStopped(m_id, m_source->captureDidFail()), 0);
@@ -536,6 +541,16 @@ void UserMediaCaptureManagerProxy::getPhotoCapabilities(RealtimeMediaSourceIdent
     handler(PhotoCapabilitiesOrError("Device not available"_s));
 }
 
+void UserMediaCaptureManagerProxy::getPhotoSettings(RealtimeMediaSourceIdentifier sourceID, GetPhotoSettingsCallback&& handler)
+{
+    if (auto* proxy = m_proxies.get(sourceID)) {
+        proxy->getPhotoSettings(WTFMove(handler));
+        return;
+    }
+
+    handler(PhotoSettingsOrError("Device not available"_s));
+}
+
 void UserMediaCaptureManagerProxy::endProducingData(RealtimeMediaSourceIdentifier sourceID)
 {
     if (auto* proxy = m_proxies.get(sourceID))
diff --git a/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.h b/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.h
index 34cc6a3ee90a..c1ae2bedfad1 100644
--- a/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.h
+++ b/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.h
@@ -98,7 +98,10 @@ class UserMediaCaptureManagerProxy : private IPC::MessageReceiver {
     void setIsInBackground(WebCore::RealtimeMediaSourceIdentifier, bool);
 
     using GetPhotoCapabilitiesCallback = CompletionHandler;
-    void getPhotoCapabilities(WebCore::RealtimeMediaSourceIdentifier, GetPhotoCapabilitiesCallback&& handler);
+    void getPhotoCapabilities(WebCore::RealtimeMediaSourceIdentifier, GetPhotoCapabilitiesCallback&&);
+
+    using GetPhotoSettingsCallback = CompletionHandler;
+    void getPhotoSettings(WebCore::RealtimeMediaSourceIdentifier, GetPhotoSettingsCallback&&);
 
     WebCore::CaptureSourceOrError createMicrophoneSource(const WebCore::CaptureDevice&, WebCore::MediaDeviceHashSalts&&, const WebCore::MediaConstraints*, WebCore::PageIdentifier);
     WebCore::CaptureSourceOrError createCameraSource(const WebCore::CaptureDevice&, WebCore::MediaDeviceHashSalts&&, WebCore::PageIdentifier);
diff --git a/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.messages.in b/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.messages.in
index 50ab776789b7..0d603de2b213 100644
--- a/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.messages.in
+++ b/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.messages.in
@@ -30,6 +30,7 @@ messages -> UserMediaCaptureManagerProxy NotRefCounted {
     RemoveSource(WebCore::RealtimeMediaSourceIdentifier id)
     ApplyConstraints(WebCore::RealtimeMediaSourceIdentifier id, struct WebCore::MediaConstraints constraints)
     GetPhotoCapabilities(WebCore::RealtimeMediaSourceIdentifier sourceID) -> (struct WebCore::PhotoCapabilitiesOrError result) Async
+    GetPhotoSettings(WebCore::RealtimeMediaSourceIdentifier sourceID) -> (struct WebCore::PhotoSettingsOrError result) Async
     Clone(WebCore::RealtimeMediaSourceIdentifier clonedID, WebCore::RealtimeMediaSourceIdentifier cloneID, WebCore::PageIdentifier pageIdentifier)
     EndProducingData(WebCore::RealtimeMediaSourceIdentifier sourceID)
     SetShouldApplyRotation(WebCore::RealtimeMediaSourceIdentifier sourceID, bool shouldApplyRotation)
diff --git a/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSource.cpp b/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSource.cpp
index 4efa31682ff5..dcaf781ff7b7 100644
--- a/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSource.cpp
+++ b/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSource.cpp
@@ -85,6 +85,11 @@ void RemoteRealtimeMediaSource::getPhotoCapabilities(PhotoCapabilitiesHandler&&
     m_proxy.getPhotoCapabilities(WTFMove(callback));
 }
 
+void RemoteRealtimeMediaSource::getPhotoSettings(PhotoSettingsHandler&& callback)
+{
+    m_proxy.getPhotoSettings(WTFMove(callback));
+}
+
 void RemoteRealtimeMediaSource::configurationChanged(String&& persistentID, WebCore::RealtimeMediaSourceSettings&& settings, WebCore::RealtimeMediaSourceCapabilities&& capabilities)
 {
     setPersistentId(WTFMove(persistentID));
diff --git a/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSource.h b/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSource.h
index 28ada928de24..c97bbe7ca09d 100644
--- a/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSource.h
+++ b/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSource.h
@@ -74,6 +74,7 @@ class RemoteRealtimeMediaSource : public WebCore::RealtimeMediaSource
     const WebCore::RealtimeMediaSourceSettings& settings() final { return m_settings; }
     const WebCore::RealtimeMediaSourceCapabilities& capabilities() final { return m_capabilities; }
     void getPhotoCapabilities(PhotoCapabilitiesHandler&&) final;
+    void getPhotoSettings(PhotoSettingsHandler&&) final;
 
 private:
     // RealtimeMediaSource
diff --git a/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSourceProxy.cpp b/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSourceProxy.cpp
index 4f0519167185..a46238e3a5be 100644
--- a/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSourceProxy.cpp
+++ b/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSourceProxy.cpp
@@ -117,6 +117,11 @@ void RemoteRealtimeMediaSourceProxy::getPhotoCapabilities(WebCore::RealtimeMedia
     m_connection->sendWithAsyncReply(Messages::UserMediaCaptureManagerProxy::GetPhotoCapabilities(identifier()), WTFMove(handler));
 }
 
+void RemoteRealtimeMediaSourceProxy::getPhotoSettings(WebCore::RealtimeMediaSource::PhotoSettingsHandler&& handler)
+{
+    m_connection->sendWithAsyncReply(Messages::UserMediaCaptureManagerProxy::GetPhotoSettings(identifier()), WTFMove(handler));
+}
+
 void RemoteRealtimeMediaSourceProxy::applyConstraintsSucceeded()
 {
     auto callback = m_pendingApplyConstraintsCallbacks.takeFirst();
diff --git a/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSourceProxy.h b/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSourceProxy.h
index 806f8fc52f0d..92cfda607b2f 100644
--- a/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSourceProxy.h
+++ b/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSourceProxy.h
@@ -74,6 +74,7 @@ class RemoteRealtimeMediaSourceProxy {
     void endProducingData();
     void applyConstraints(const WebCore::MediaConstraints&, WebCore::RealtimeMediaSource::ApplyConstraintsHandler&&);
     void getPhotoCapabilities(WebCore::RealtimeMediaSource::PhotoCapabilitiesHandler&&);
+    void getPhotoSettings(WebCore::RealtimeMediaSource::PhotoSettingsHandler&&);
 
     void whenReady(CompletionHandler&&);
     void setAsReady();

From b11cf7dd7792e91eb11ea6340ef4674ce40ba177 Mon Sep 17 00:00:00 2001
From: Jean-Yves Avenard 
Date: Thu, 5 Oct 2023 15:40:50 +1100
Subject: [PATCH 16/16] convert getPhotoSettings to use NativePromise

---
 .../Modules/mediastream/MediaStreamTrack.cpp  |  7 +++---
 .../mediastream/MediaStreamTrackPrivate.cpp   |  5 ++--
 .../mediastream/MediaStreamTrackPrivate.h     |  2 +-
 .../mediastream/RealtimeMediaSource.cpp       |  5 ++--
 .../mediastream/RealtimeMediaSource.h         | 25 +++----------------
 .../mediastream/mac/AVVideoCaptureSource.h    |  2 +-
 .../mediastream/mac/AVVideoCaptureSource.mm   | 11 ++++----
 .../platform/mock/MockRealtimeVideoSource.cpp | 11 ++++----
 .../platform/mock/MockRealtimeVideoSource.h   |  2 +-
 Source/WebKit/Scripts/webkit/messages.py      |  1 -
 .../WebCoreArgumentCoders.serialization.in    |  7 ------
 .../Cocoa/UserMediaCaptureManagerProxy.cpp    | 11 +++++---
 .../Cocoa/UserMediaCaptureManagerProxy.h      |  2 +-
 .../UserMediaCaptureManagerProxy.messages.in  |  2 +-
 .../cocoa/RemoteRealtimeMediaSource.cpp       |  4 +--
 .../cocoa/RemoteRealtimeMediaSource.h         |  2 +-
 .../cocoa/RemoteRealtimeMediaSourceProxy.cpp  |  9 +++++--
 .../cocoa/RemoteRealtimeMediaSourceProxy.h    |  2 +-
 18 files changed, 46 insertions(+), 64 deletions(-)

diff --git a/Source/WebCore/Modules/mediastream/MediaStreamTrack.cpp b/Source/WebCore/Modules/mediastream/MediaStreamTrack.cpp
index 9f74482bebd2..2f44070603b7 100644
--- a/Source/WebCore/Modules/mediastream/MediaStreamTrack.cpp
+++ b/Source/WebCore/Modules/mediastream/MediaStreamTrack.cpp
@@ -59,6 +59,7 @@
 #include "WebAudioSourceProvider.h"
 #include 
 #include 
+#include 
 #include 
 
 namespace WebCore {
@@ -331,17 +332,17 @@ void MediaStreamTrack::getPhotoCapabilities(DOMPromiseDeferred>&& promise) const
 {
-    m_private->getPhotoSettings([protectedThis = Ref { *this }, promise = WTFMove(promise)](auto&& result) mutable {
+    m_private->getPhotoSettings()->whenSettled(RunLoop::main(), [protectedThis = Ref { *this }, promise = WTFMove(promise)] (RealtimeMediaSource::PhotoSettingsPromise::Result&& result) mutable {
         if (!result) {
             // https://w3c.github.io/mediacapture-image/#ref-for-dom-imagecapture-getphotosettings②
             // If the data cannot be gathered for any reason (for example, the MediaStreamTrack being ended
             // asynchronously), then reject p with a new DOMException whose name is OperationError, and
             // abort these steps.
-            promise.reject(Exception { OperationError, WTFMove(result.errorMessage) });
+            promise.reject(Exception { OperationError, WTFMove(result.error()) });
             return;
         }
 
-        promise.resolve(WTFMove(*result.settings));
+        promise.resolve(WTFMove(result.value()));
     });
 }
 
diff --git a/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.cpp b/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.cpp
index 661a5dd6998e..e0f404b05bf0 100644
--- a/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.cpp
+++ b/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.cpp
@@ -34,6 +34,7 @@
 #include "IntRect.h"
 #include "Logging.h"
 #include "PlatformMediaSessionManager.h"
+#include 
 #include 
 
 #if PLATFORM(COCOA)
@@ -188,9 +189,9 @@ void MediaStreamTrackPrivate::getPhotoCapabilities(RealtimeMediaSource::PhotoCap
     m_source->getPhotoCapabilities(WTFMove(completion));
 }
 
-void MediaStreamTrackPrivate::getPhotoSettings(RealtimeMediaSource::PhotoSettingsHandler&& completion)
+Ref MediaStreamTrackPrivate::getPhotoSettings()
 {
-    m_source->getPhotoSettings(WTFMove(completion));
+    return m_source->getPhotoSettings();
 }
 
 void MediaStreamTrackPrivate::applyConstraints(const MediaConstraints& constraints, RealtimeMediaSource::ApplyConstraintsHandler&& completionHandler)
diff --git a/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.h b/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.h
index e279fef28b07..7d35c42c29ab 100644
--- a/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.h
+++ b/Source/WebCore/platform/mediastream/MediaStreamTrackPrivate.h
@@ -111,7 +111,7 @@ class MediaStreamTrackPrivate final
     const RealtimeMediaSourceCapabilities& capabilities() const;
 
     void getPhotoCapabilities(RealtimeMediaSource::PhotoCapabilitiesHandler&&);
-    void getPhotoSettings(RealtimeMediaSource::PhotoSettingsHandler&&);
+    Ref getPhotoSettings();
 
     void applyConstraints(const MediaConstraints&, RealtimeMediaSource::ApplyConstraintsHandler&&);
 
diff --git a/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp b/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp
index 5ac5bd5e9d2a..d610c620c5fe 100644
--- a/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp
+++ b/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp
@@ -45,6 +45,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -1460,9 +1461,9 @@ void RealtimeMediaSource::getPhotoCapabilities(PhotoCapabilitiesHandler&& comple
     completion(PhotoCapabilitiesOrError("Not supported"_s));
 }
 
-void RealtimeMediaSource::getPhotoSettings(PhotoSettingsHandler&& completion)
+auto RealtimeMediaSource::getPhotoSettings() -> Ref
 {
-    completion(PhotoSettingsOrError("Not supported"_s));
+    return PhotoSettingsPromise::createAndReject("Not supported"_s);
 }
 
 RealtimeMediaSource::Observer::~Observer()
diff --git a/Source/WebCore/platform/mediastream/RealtimeMediaSource.h b/Source/WebCore/platform/mediastream/RealtimeMediaSource.h
index 2b07db63ae51..1504e07d52c5 100644
--- a/Source/WebCore/platform/mediastream/RealtimeMediaSource.h
+++ b/Source/WebCore/platform/mediastream/RealtimeMediaSource.h
@@ -49,6 +49,7 @@
 #include "VideoFrameTimeMetadata.h"
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -81,7 +82,6 @@ enum class VideoFrameRotation : uint16_t;
 struct CaptureSourceError;
 struct CaptureSourceOrError;
 struct PhotoCapabilitiesOrError;
-struct PhotoSettingsOrError;
 struct VideoFrameAdaptor;
 
 class WEBCORE_EXPORT RealtimeMediaSource
@@ -214,8 +214,8 @@ class WEBCORE_EXPORT RealtimeMediaSource
     using PhotoCapabilitiesHandler = CompletionHandler;
     virtual void getPhotoCapabilities(PhotoCapabilitiesHandler&&);
 
-    using PhotoSettingsHandler = CompletionHandler;
-    virtual void getPhotoSettings(PhotoSettingsHandler&&);
+    using PhotoSettingsPromise = NativePromise;
+    virtual Ref getPhotoSettings();
 
     struct ApplyConstraintsError {
         String badConstraint;
@@ -421,25 +421,6 @@ struct PhotoCapabilitiesOrError {
     String errorMessage;
 };
 
-struct PhotoSettingsOrError {
-    PhotoSettingsOrError() = default;
-    PhotoSettingsOrError(std::optional&& settings, String&& errorMessage)
-        : settings(WTFMove(settings))
-        , errorMessage(WTFMove(errorMessage))
-    { }
-    PhotoSettingsOrError(PhotoSettings& settings)
-        : settings({ settings })
-    { }
-    explicit PhotoSettingsOrError(String&& errorMessage)
-        : errorMessage(WTFMove(errorMessage))
-    { }
-
-    operator bool() const { return settings.has_value(); }
-
-    std::optional settings;
-    String errorMessage;
-};
-
 String convertEnumerationToString(RealtimeMediaSource::Type);
 
 inline void RealtimeMediaSource::setName(const AtomString& name)
diff --git a/Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.h b/Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.h
index 3b4bea5d1284..685055f14462 100644
--- a/Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.h
+++ b/Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.h
@@ -85,7 +85,7 @@ class AVVideoCaptureSource : public RealtimeVideoCaptureSource, private Orientat
     const RealtimeMediaSourceCapabilities& capabilities() final;
     const RealtimeMediaSourceSettings& settings() final;
     void getPhotoCapabilities(PhotoCapabilitiesHandler&&) final;
-    void getPhotoSettings(PhotoSettingsHandler&&) final;
+    Ref getPhotoSettings() final;
     double facingModeFitnessScoreAdjustment() const final;
     void startProducingData() final;
     void stopProducingData() final;
diff --git a/Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.mm b/Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.mm
index 9f8c1243d6e2..ff5a0905d6ed 100644
--- a/Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.mm
+++ b/Source/WebCore/platform/mediastream/mac/AVVideoCaptureSource.mm
@@ -47,6 +47,7 @@
 #import 
 #import 
 #import 
+#import 
 #import 
 
 #import "CoreVideoSoftLink.h"
@@ -486,12 +487,10 @@ static FillLightMode toFillLightMode(AVCaptureTorchMode mode)
     return FillLightMode::Auto;
 }
 
-void AVVideoCaptureSource::getPhotoSettings(PhotoSettingsHandler&& completion)
+auto AVVideoCaptureSource::getPhotoSettings() -> Ref
 {
-    if (m_photoSettings) {
-        completion({ *m_photoSettings });
-        return;
-    }
+    if (m_photoSettings)
+        return PhotoSettingsPromise::createAndResolve(*m_photoSettings);
 
     PhotoSettings photoSettings;
     auto settings = this->settings();
@@ -504,7 +503,7 @@ static FillLightMode toFillLightMode(AVCaptureTorchMode mode)
 
     m_photoSettings = WTFMove(photoSettings);
 
-    completion({ *m_photoSettings });
+    return PhotoSettingsPromise::createAndResolve(*m_photoSettings);
 }
 
 NSMutableArray* AVVideoCaptureSource::cameraCaptureDeviceTypes()
diff --git a/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp b/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp
index 87f404e65c6c..254733df46d7 100644
--- a/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp
+++ b/Source/WebCore/platform/mock/MockRealtimeVideoSource.cpp
@@ -45,6 +45,7 @@
 #include "RealtimeMediaSourceSettings.h"
 #include "VideoFrame.h"
 #include 
+#include 
 #include 
 #include 
 
@@ -203,12 +204,10 @@ void MockRealtimeVideoSource::getPhotoCapabilities(PhotoCapabilitiesHandler&& co
     completion({ *m_photoCapabilities });
 }
 
-void MockRealtimeVideoSource::getPhotoSettings(PhotoSettingsHandler&& completion)
+auto MockRealtimeVideoSource::getPhotoSettings() -> Ref
 {
-    if (m_photoSettings) {
-        completion({ *m_photoSettings });
-        return;
-    }
+    if (m_photoSettings)
+        return PhotoSettingsPromise::createAndResolve(*m_photoSettings);
 
     PhotoSettings photoSettings;
     auto settings = this->settings();
@@ -223,7 +222,7 @@ void MockRealtimeVideoSource::getPhotoSettings(PhotoSettingsHandler&& completion
 
     m_photoSettings = WTFMove(photoSettings);
 
-    completion({ *m_photoSettings });
+    return PhotoSettingsPromise::createAndResolve(*m_photoSettings);
 }
 
 static bool isZoomSupported(const Vector& presets)
diff --git a/Source/WebCore/platform/mock/MockRealtimeVideoSource.h b/Source/WebCore/platform/mock/MockRealtimeVideoSource.h
index cd6e8dc1da3a..aac69f4c6c8b 100644
--- a/Source/WebCore/platform/mock/MockRealtimeVideoSource.h
+++ b/Source/WebCore/platform/mock/MockRealtimeVideoSource.h
@@ -75,7 +75,7 @@ class MockRealtimeVideoSource : public RealtimeVideoCaptureSource, private Orien
     const RealtimeMediaSourceCapabilities& capabilities() final;
     const RealtimeMediaSourceSettings& settings() final;
     void getPhotoCapabilities(PhotoCapabilitiesHandler&&) final;
-    void getPhotoSettings(PhotoSettingsHandler&&) final;
+    Ref getPhotoSettings() final;
 
     void startProducingData() override;
     void stopProducingData() override;
diff --git a/Source/WebKit/Scripts/webkit/messages.py b/Source/WebKit/Scripts/webkit/messages.py
index eef151643e5e..ce4cea2042f7 100644
--- a/Source/WebKit/Scripts/webkit/messages.py
+++ b/Source/WebKit/Scripts/webkit/messages.py
@@ -801,7 +801,6 @@ def headers_for_type(type):
         'WebCore::PathDataQuadCurve': [''],
         'WebCore::PixelFormat': [''],
         'WebCore::PhotoCapabilitiesOrError': [''],
-        'WebCore::PhotoSettingsOrError': [''],
         'WebCore::PlatformTextTrackData': [''],
         'WebCore::PlatformWheelEventPhase': [''],
         'WebCore::PlaybackSessionModel::PlaybackState': [''],
diff --git a/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in b/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in
index 7cadea1ba8b2..15623d4cdfc4 100644
--- a/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in
+++ b/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in
@@ -5891,13 +5891,6 @@ header: 
     String errorMessage;
 };
 
-header: 
-[CustomHeader] struct WebCore::PhotoSettingsOrError {
-    std::optional settings;
-    String errorMessage;
-};
-#endif
-
 header: 
 enum class WebCore::WebGPU::TextureAspect : uint8_t {
     All,
diff --git a/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.cpp b/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.cpp
index dadecf5a1fce..18c999b7e05f 100644
--- a/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.cpp
+++ b/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.cpp
@@ -44,6 +44,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #define MESSAGE_CHECK(assertion) MESSAGE_CHECK_BASE(assertion, &m_connectionProxy->connection())
@@ -194,9 +195,9 @@ class UserMediaCaptureManagerProxy::SourceProxy
         m_source->getPhotoCapabilities(WTFMove(handler));
     }
 
-    void getPhotoSettings(GetPhotoSettingsCallback&& handler)
+    Ref getPhotoSettings()
     {
-        m_source->getPhotoSettings(WTFMove(handler));
+        return m_source->getPhotoSettings();
     }
 
 private:
@@ -544,11 +545,13 @@ void UserMediaCaptureManagerProxy::getPhotoCapabilities(RealtimeMediaSourceIdent
 void UserMediaCaptureManagerProxy::getPhotoSettings(RealtimeMediaSourceIdentifier sourceID, GetPhotoSettingsCallback&& handler)
 {
     if (auto* proxy = m_proxies.get(sourceID)) {
-        proxy->getPhotoSettings(WTFMove(handler));
+        proxy->getPhotoSettings()->whenSettled(RunLoop::main(), [handler = WTFMove(handler)] (RealtimeMediaSource::PhotoSettingsPromise::Result&& result) mutable {
+            handler(WTFMove(result));
+        });
         return;
     }
 
-    handler(PhotoSettingsOrError("Device not available"_s));
+    handler(Unexpected("Device not available"_s));
 }
 
 void UserMediaCaptureManagerProxy::endProducingData(RealtimeMediaSourceIdentifier sourceID)
diff --git a/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.h b/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.h
index c1ae2bedfad1..e5c67a731ef7 100644
--- a/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.h
+++ b/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.h
@@ -100,7 +100,7 @@ class UserMediaCaptureManagerProxy : private IPC::MessageReceiver {
     using GetPhotoCapabilitiesCallback = CompletionHandler;
     void getPhotoCapabilities(WebCore::RealtimeMediaSourceIdentifier, GetPhotoCapabilitiesCallback&&);
 
-    using GetPhotoSettingsCallback = CompletionHandler;
+    using GetPhotoSettingsCallback = CompletionHandler&&)>;
     void getPhotoSettings(WebCore::RealtimeMediaSourceIdentifier, GetPhotoSettingsCallback&&);
 
     WebCore::CaptureSourceOrError createMicrophoneSource(const WebCore::CaptureDevice&, WebCore::MediaDeviceHashSalts&&, const WebCore::MediaConstraints*, WebCore::PageIdentifier);
diff --git a/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.messages.in b/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.messages.in
index 0d603de2b213..0a76b4f88a2c 100644
--- a/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.messages.in
+++ b/Source/WebKit/UIProcess/Cocoa/UserMediaCaptureManagerProxy.messages.in
@@ -30,7 +30,7 @@ messages -> UserMediaCaptureManagerProxy NotRefCounted {
     RemoveSource(WebCore::RealtimeMediaSourceIdentifier id)
     ApplyConstraints(WebCore::RealtimeMediaSourceIdentifier id, struct WebCore::MediaConstraints constraints)
     GetPhotoCapabilities(WebCore::RealtimeMediaSourceIdentifier sourceID) -> (struct WebCore::PhotoCapabilitiesOrError result) Async
-    GetPhotoSettings(WebCore::RealtimeMediaSourceIdentifier sourceID) -> (struct WebCore::PhotoSettingsOrError result) Async
+    GetPhotoSettings(WebCore::RealtimeMediaSourceIdentifier sourceID) -> (Expected result) Async
     Clone(WebCore::RealtimeMediaSourceIdentifier clonedID, WebCore::RealtimeMediaSourceIdentifier cloneID, WebCore::PageIdentifier pageIdentifier)
     EndProducingData(WebCore::RealtimeMediaSourceIdentifier sourceID)
     SetShouldApplyRotation(WebCore::RealtimeMediaSourceIdentifier sourceID, bool shouldApplyRotation)
diff --git a/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSource.cpp b/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSource.cpp
index dcaf781ff7b7..82441f710179 100644
--- a/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSource.cpp
+++ b/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSource.cpp
@@ -85,9 +85,9 @@ void RemoteRealtimeMediaSource::getPhotoCapabilities(PhotoCapabilitiesHandler&&
     m_proxy.getPhotoCapabilities(WTFMove(callback));
 }
 
-void RemoteRealtimeMediaSource::getPhotoSettings(PhotoSettingsHandler&& callback)
+Ref RemoteRealtimeMediaSource::getPhotoSettings()
 {
-    m_proxy.getPhotoSettings(WTFMove(callback));
+    return m_proxy.getPhotoSettings();
 }
 
 void RemoteRealtimeMediaSource::configurationChanged(String&& persistentID, WebCore::RealtimeMediaSourceSettings&& settings, WebCore::RealtimeMediaSourceCapabilities&& capabilities)
diff --git a/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSource.h b/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSource.h
index c97bbe7ca09d..3af943413d54 100644
--- a/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSource.h
+++ b/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSource.h
@@ -74,7 +74,7 @@ class RemoteRealtimeMediaSource : public WebCore::RealtimeMediaSource
     const WebCore::RealtimeMediaSourceSettings& settings() final { return m_settings; }
     const WebCore::RealtimeMediaSourceCapabilities& capabilities() final { return m_capabilities; }
     void getPhotoCapabilities(PhotoCapabilitiesHandler&&) final;
-    void getPhotoSettings(PhotoSettingsHandler&&) final;
+    Ref getPhotoSettings() final;
 
 private:
     // RealtimeMediaSource
diff --git a/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSourceProxy.cpp b/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSourceProxy.cpp
index a46238e3a5be..f367d9e4cc01 100644
--- a/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSourceProxy.cpp
+++ b/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSourceProxy.cpp
@@ -39,6 +39,7 @@
 #include 
 #include 
 #include 
+#include 
 
 namespace WebKit {
 using namespace WebCore;
@@ -117,9 +118,13 @@ void RemoteRealtimeMediaSourceProxy::getPhotoCapabilities(WebCore::RealtimeMedia
     m_connection->sendWithAsyncReply(Messages::UserMediaCaptureManagerProxy::GetPhotoCapabilities(identifier()), WTFMove(handler));
 }
 
-void RemoteRealtimeMediaSourceProxy::getPhotoSettings(WebCore::RealtimeMediaSource::PhotoSettingsHandler&& handler)
+Ref RemoteRealtimeMediaSourceProxy::getPhotoSettings()
 {
-    m_connection->sendWithAsyncReply(Messages::UserMediaCaptureManagerProxy::GetPhotoSettings(identifier()), WTFMove(handler));
+    return m_connection->sendWithPromisedReply(Messages::UserMediaCaptureManagerProxy::GetPhotoSettings(identifier()))->whenSettled(RunLoop::main(), [](Messages::UserMediaCaptureManagerProxy::GetPhotoSettings::Promise::Result&& result) {
+        if (result)
+            return WebCore::RealtimeMediaSource::PhotoSettingsPromise::createAndResolveOrReject(WTFMove(result.value()));
+        return WebCore::RealtimeMediaSource::PhotoSettingsPromise::createAndReject(String("IPC Connection closed"_s));
+    });
 }
 
 void RemoteRealtimeMediaSourceProxy::applyConstraintsSucceeded()
diff --git a/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSourceProxy.h b/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSourceProxy.h
index 92cfda607b2f..1112d506f87b 100644
--- a/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSourceProxy.h
+++ b/Source/WebKit/WebProcess/cocoa/RemoteRealtimeMediaSourceProxy.h
@@ -74,7 +74,7 @@ class RemoteRealtimeMediaSourceProxy {
     void endProducingData();
     void applyConstraints(const WebCore::MediaConstraints&, WebCore::RealtimeMediaSource::ApplyConstraintsHandler&&);
     void getPhotoCapabilities(WebCore::RealtimeMediaSource::PhotoCapabilitiesHandler&&);
-    void getPhotoSettings(WebCore::RealtimeMediaSource::PhotoSettingsHandler&&);
+    Ref getPhotoSettings();
 
     void whenReady(CompletionHandler&&);
     void setAsReady();