[macOS] Add new screen and window capture backend
https://bugs.webkit.org/show_bug.cgi?id=234029
Source/WebCore:

rdar://problem/86347726

Reviewed by Jer Noble and Youenn Fablet.

New API test: GetDisplayMediaWindowAndScreen.mm

* SourcesCocoa.txt:
* WebCore.xcodeproj/project.pbxproj:
* en.lproj/Localizable.strings: Add strings for window and screen prompts.

* platform/mediastream/MediaConstraints.h:
(WebCore::StringConstraint::getExact const): Drive-by: fix logic inversion bug.
(WebCore::StringConstraint::getIdeal const): Ditto.

* platform/mediastream/RealtimeMediaSource.cpp:
(WebCore::RealtimeMediaSource::fitnessDistance): Assert if device ID constraint is
not a string.

* platform/mediastream/RealtimeMediaSourceCenter.h:
(WebCore::RealtimeMediaSourceCenter::useScreenCaptureKit const):
(WebCore::RealtimeMediaSourceCenter::setUseScreenCaptureKit):
(WebCore::RealtimeMediaSourceCenter::useMockCaptureDevices const):
(WebCore::RealtimeMediaSourceCenter::setUseMockCaptureDevices):

* platform/mediastream/cocoa/DisplayCaptureSourceCocoa.cpp:
(WebCore::DisplayCaptureSourceCocoa::create):
(WebCore::DisplayCaptureSourceCocoa::DisplayCaptureSourceCocoa):
(WebCore::DisplayCaptureSourceCocoa::Capturer::setObserver):
(WebCore::DisplayCaptureSourceCocoa::Capturer::capturerIsRunningChanged): Deleted.
* platform/mediastream/cocoa/DisplayCaptureSourceCocoa.h:
(WebCore::CapturerObserver::capturerIsRunningChanged):
(WebCore::CapturerObserver::capturerFailed):

* platform/mediastream/ios/ReplayKitCaptureSource.mm:
(WebCore::ReplayKitCaptureSource::captureStateDidChange):

* platform/mediastream/mac/DisplayCaptureManagerCocoa.cpp:
(WebCore::DisplayCaptureManagerCocoa::updateDisplayCaptureDevices): Use
ScreenCaptureKitCaptureSource when available.
(WebCore::DisplayCaptureManagerCocoa::updateWindowCaptureDevices): Ditto.
(WebCore::DisplayCaptureManagerCocoa::screenCaptureDeviceWithPersistentID): Ditto.
(WebCore::DisplayCaptureManagerCocoa::windowCaptureDeviceWithPersistentID): Ditto.

* platform/mediastream/mac/ScreenCaptureKitCaptureSource.h: Added.
* platform/mediastream/mac/ScreenCaptureKitCaptureSource.mm: Added.
(-[WebCoreScreenCaptureKitHelper initWithCallback:]):
(-[WebCoreScreenCaptureKitHelper disconnect]):
(-[WebCoreScreenCaptureKitHelper stream:didStopWithError:]):
(WebCore::usingOldAPI):
(WebCore::ScreenCaptureKitCaptureSource::isAvailable):
(WebCore::ScreenCaptureKitCaptureSource::create):
(WebCore::ScreenCaptureKitCaptureSource::ScreenCaptureKitCaptureSource):
(WebCore::ScreenCaptureKitCaptureSource::~ScreenCaptureKitCaptureSource):
(WebCore::ScreenCaptureKitCaptureSource::start):
(WebCore::ScreenCaptureKitCaptureSource::stop):
(WebCore::ScreenCaptureKitCaptureSource::streamFailedWithError):
(WebCore::ScreenCaptureKitCaptureSource::generateFrame):
(WebCore::ScreenCaptureKitCaptureSource::processSharableContent):
(WebCore::ScreenCaptureKitCaptureSource::findShareableContent):
(WebCore::ScreenCaptureKitCaptureSource::streamConfiguration):
(WebCore::ScreenCaptureKitCaptureSource::startContentStream):
(WebCore::ScreenCaptureKitCaptureSource::intrinsicSize const):
(WebCore::ScreenCaptureKitCaptureSource::updateStreamConfiguration):
(WebCore::ScreenCaptureKitCaptureSource::commitConfiguration):
(WebCore::ScreenCaptureKitCaptureSource::captureQueue):
(WebCore::ScreenCaptureKitCaptureSource::frameAvailableHandler):
(WebCore::ScreenCaptureKitCaptureSource::deviceType const):
(WebCore::ScreenCaptureKitCaptureSource::surfaceType const):
(WebCore::ScreenCaptureKitCaptureSource::screenCaptureDeviceWithPersistentID):
(WebCore::ScreenCaptureKitCaptureSource::screenCaptureDevices):
(WebCore::ScreenCaptureKitCaptureSource::windowCaptureDeviceWithPersistentID):
(WebCore::ScreenCaptureKitCaptureSource::windowCaptureDevices):
(WebCore::ScreenCaptureKitCaptureSource::forEachNSWindow):

* platform/mock/MockMediaDevice.h:
(WebCore::MockMediaDevice::captureDevice const): Make devices enabled by default.
Initialize screen and window devices with the correct type.

* platform/mock/MockRealtimeMediaSourceCenter.cpp:
(WebCore::defaultDevices): Fix window device types.
(WebCore::MockRealtimeMediaSourceCenter::displayDevices):
* platform/mock/MockRealtimeMediaSourceCenter.h:

Source/WebCore/PAL:

rdar://problem/86347726

Reviewed by Jer Noble and Youenn Fablet.

* PAL.xcodeproj/project.pbxproj:
* pal/mac/ScreenCaptureKitSoftLink.h: Added.
* pal/mac/ScreenCaptureKitSoftLink.mm: Added.

Source/WebKit:

rdar://problem/86347726

Reviewed by Jer Noble and Youenn Fablet.

* Shared/WebPreferencesDefaultValues.cpp:
(WebKit::defaultScreenCaptureKitEnabled):
* Shared/WebPreferencesDefaultValues.h:

* SourcesCocoa.txt:
* UIProcess/API/Cocoa/WKPreferences.mm: Add _useScreenCaptureKit private preference.
(-[WKPreferences _useScreenCaptureKit]):
(-[WKPreferences _setUseScreenCaptureKit:]):
* UIProcess/API/Cocoa/WKPreferencesPrivate.h:

* UIProcess/API/Cocoa/WKUIDelegatePrivate.h: Add private delegate for a
getDisplayMedia-specific prompt.

* UIProcess/API/Cocoa/WKWebViewPrivateForTesting.h:
* UIProcess/API/Cocoa/WKWebViewTesting.mm:
(-[WKWebView _setIndexOfGetDisplayMediaDeviceSelectedForTesting:]): Set the index
of the screen or window device to return for getDisplayMedia without prompting.

* UIProcess/Cocoa/UIDelegate.h:
* UIProcess/Cocoa/UIDelegate.mm:
(WebKit::UIDelegate::UIClient::promptForDisplayCapturePermission): Call new
screen/window capture delegate.
(WebKit::UIDelegate::UIClient::decidePolicyForUserMediaPermissionRequest):

* UIProcess/UserMediaPermissionRequestProxy.cpp:
(WebKit::UserMediaPermissionRequestProxy::create):
(WebKit::UserMediaPermissionRequestProxy::promptForGetDisplayMedia): Add parameter
specifying a window or screen capture prompt.
* UIProcess/UserMediaPermissionRequestProxy.h:
(WebKit::UserMediaPermissionRequestProxy::create):
(WebKit::UserMediaPermissionRequestProxy::manager const):

* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::setIndexOfGetDisplayMediaDeviceSelectedForTesting):
* UIProcess/WebPageProxy.h:

* UIProcess/mac/DisplayCaptureSessionManager.h: Added.
(WebKit::DisplayCaptureSessionManager::setIndexOfDeviceSelectedForTesting):
* UIProcess/mac/DisplayCaptureSessionManager.mm: Added.
(WebKit::getMockWindowList):
(WebKit::getCGWindowList):
(WebKit::getWindowList):
(WebKit::alertForWindowSelection):
(WebKit::DisplayCaptureSessionManager::alertForGetDisplayMedia):
(WebKit::DisplayCaptureSessionManager::isAvailable):
(WebKit::DisplayCaptureSessionManager::singleton):
(WebKit::DisplayCaptureSessionManager::DisplayCaptureSessionManager):
(WebKit::DisplayCaptureSessionManager::~DisplayCaptureSessionManager):
(WebKit::DisplayCaptureSessionManager::promptForGetDisplayMedia):
(WebKit::DisplayCaptureSessionManager::deviceSelectedForTesting):
(WebKit::DisplayCaptureSessionManager::showWindowPicker):
(WebKit::DisplayCaptureSessionManager::showScreenPicker):

* UIProcess/mac/UserMediaPermissionRequestProxyMac.h: Added.
* UIProcess/mac/UserMediaPermissionRequestProxyMac.mm: Added.
(WebKit::UserMediaPermissionRequestProxy::create):
(WebKit::UserMediaPermissionRequestProxyMac::UserMediaPermissionRequestProxyMac):
(WebKit::UserMediaPermissionRequestProxyMac::~UserMediaPermissionRequestProxyMac):
(WebKit::UserMediaPermissionRequestProxyMac::promptForGetDisplayMedia):
(WebKit::UserMediaPermissionRequestProxyMac::canPromptForGetDisplayMedia):
* WebKit.xcodeproj/project.pbxproj:

Source/WTF:

rdar://problem/86347726

Reviewed by Jer Noble and Youenn Fablet.

* Scripts/Preferences/WebPreferencesExperimental.yaml: Add UseScreenCaptureKit.
* wtf/PlatformEnableCocoa.h: Define ENABLE_SCREEN_CAPTURE_KIT.
* wtf/PlatformHave.h: Define HAVE_SCREEN_CAPTURE_KIT.
* wtf/cocoa/SoftLinking.h: Add softlink macros that take an API_AVAILABLE check.

Tools:

Reviewed by Jer Noble and Youenn Fablet.

* TestWebKitAPI/SourcesCocoa.txt:
* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKitCocoa/GetDisplayMediaWindowAndScreen.mm: Added.
(-[WindowAndScreenCaptureTestView haveStream:]):
(TestWebKitAPI::TEST):
* TestWebKitAPI/Tests/WebKitCocoa/WKWebViewUnderPageBackgroundColor.mm:
(TEST):
* TestWebKitAPI/Tests/WebKitCocoa/WebProcessTerminate.mm:
* TestWebKitAPI/cocoa/UserMediaCaptureUIDelegate.h:
* TestWebKitAPI/cocoa/UserMediaCaptureUIDelegate.mm:
(-[UserMediaCaptureUIDelegate init]):
(-[UserMediaCaptureUIDelegate setGetDisplayMediaDecision:]):
(-[UserMediaCaptureUIDelegate _webView:requestDisplayCapturePermissionForOrigin:initiatedByFrame:decisionHandler:]):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@288604 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WTF/ChangeLog b/Source/WTF/ChangeLog
index d2796067..356f420 100644
--- a/Source/WTF/ChangeLog
+++ b/Source/WTF/ChangeLog
@@ -1,3 +1,16 @@
+2022-01-25  Eric Carlson  <eric.carlson@apple.com>
+
+        [macOS] Add new screen and window capture backend
+        https://bugs.webkit.org/show_bug.cgi?id=234029
+        rdar://problem/86347726
+
+        Reviewed by Jer Noble and Youenn Fablet.
+
+        * Scripts/Preferences/WebPreferencesExperimental.yaml: Add UseScreenCaptureKit.
+        * wtf/PlatformEnableCocoa.h: Define ENABLE_SCREEN_CAPTURE_KIT.
+        * wtf/PlatformHave.h: Define HAVE_SCREEN_CAPTURE_KIT.
+        * wtf/cocoa/SoftLinking.h: Add softlink macros that take an API_AVAILABLE check.
+
 2022-01-25  Aditya Keerthi  <akeerthi@apple.com>
 
         Disable input-security CSS property
diff --git a/Source/WTF/Scripts/Preferences/WebPreferencesExperimental.yaml b/Source/WTF/Scripts/Preferences/WebPreferencesExperimental.yaml
index ba1e176..98a9fa6 100644
--- a/Source/WTF/Scripts/Preferences/WebPreferencesExperimental.yaml
+++ b/Source/WTF/Scripts/Preferences/WebPreferencesExperimental.yaml
@@ -1417,6 +1417,19 @@
     WebKit:
       default: defaultUseGPUProcessForWebGLEnabled()
 
+UseScreenCaptureKit:
+  type: bool
+  condition: HAVE(SCREEN_CAPTURE_KIT)
+  humanReadableName: "Use ScreenCaptureKit"
+  humanReadableDescription: "Use ScreenCaptureKit when available"
+  defaultValue:
+    WebKitLegacy:
+      default: false
+    WebKit:
+      default: WebKit::defaultScreenCaptureKitEnabled()
+    WebCore:
+      default: false
+
 UserGesturePromisePropagationEnabled:
   type: bool
   humanReadableName: "UserGesture Promise Propagation"
diff --git a/Source/WTF/wtf/PlatformEnableCocoa.h b/Source/WTF/wtf/PlatformEnableCocoa.h
index 695342e..e856592 100644
--- a/Source/WTF/wtf/PlatformEnableCocoa.h
+++ b/Source/WTF/wtf/PlatformEnableCocoa.h
@@ -737,6 +737,10 @@
 #define ENABLE_PREDEFINED_COLOR_SPACE_DISPLAY_P3 1
 #endif
 
+#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 130000)
+#define ENABLE_SCREEN_CAPTURE_KIT 1
+#endif
+
 #if PLATFORM(IOS_FAMILY) && HAVE(ASV_INLINE_PREVIEW) && !ENABLE(SEPARATED_MODEL)
 #define ENABLE_ARKIT_INLINE_PREVIEW_IOS 1
 #endif
diff --git a/Source/WTF/wtf/PlatformHave.h b/Source/WTF/wtf/PlatformHave.h
index c615d26..8b0d16b 100644
--- a/Source/WTF/wtf/PlatformHave.h
+++ b/Source/WTF/wtf/PlatformHave.h
@@ -1132,6 +1132,10 @@
 #undef HAVE_AV_DELEGATING_PLAYBACK_COORDINATOR
 #endif
 
+#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 120300
+#define HAVE_SCREEN_CAPTURE_KIT 1
+#endif
+
 #if ((PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 130000) \
     || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 160000))
 #define HAVE_SANDBOX_STATE_FLAGS 1
diff --git a/Source/WTF/wtf/cocoa/SoftLinking.h b/Source/WTF/wtf/cocoa/SoftLinking.h
index 2b91508..a9b3aa7 100644
--- a/Source/WTF/wtf/cocoa/SoftLinking.h
+++ b/Source/WTF/wtf/cocoa/SoftLinking.h
@@ -422,7 +422,14 @@
     } \
     }
 
-#define SOFT_LINK_CLASS_FOR_SOURCE_WITH_EXPORT_AND_IS_OPTIONAL(functionNamespace, framework, className, export, isOptional) \
+#define SOFT_LINK_CLASS_FOR_HEADER_WITH_AVAILABILITY(functionNamespace, className, availability) \
+    @class className; \
+    namespace functionNamespace { \
+    extern Class (*get##className##Class)(); \
+    className *alloc##className##Instance() availability; \
+    }
+
+#define SOFT_LINK_CLASS_FOR_SOURCE_INTERNAL(functionNamespace, framework, className, export, isOptional, availability) \
     @class className; \
     namespace functionNamespace { \
     static Class init##className(); \
@@ -446,11 +453,15 @@
         }); \
         return class##className; \
     } \
+    availability \
     }
 
 #define SOFT_LINK_IS_OPTIONAL true
 #define SOFT_LINK_IS_NOT_OPTIONAL false
 
+#define SOFT_LINK_CLASS_FOR_SOURCE_WITH_EXPORT_AND_IS_OPTIONAL(functionNamespace, framework, className, export, isOptional) \
+    SOFT_LINK_CLASS_FOR_SOURCE_INTERNAL(functionNamespace, framework, className, export, isOptional, )
+
 #define SOFT_LINK_CLASS_FOR_SOURCE_WITH_EXPORT(functionNamespace, framework, className, export) \
     SOFT_LINK_CLASS_FOR_SOURCE_WITH_EXPORT_AND_IS_OPTIONAL(functionNamespace, framework, className, export, SOFT_LINK_IS_NOT_OPTIONAL)
 
@@ -463,6 +474,16 @@
 #define SOFT_LINK_CLASS_FOR_SOURCE_OPTIONAL(functionNamespace, framework, className) \
     SOFT_LINK_CLASS_FOR_SOURCE_WITH_EXPORT_AND_IS_OPTIONAL(functionNamespace, framework, className, , SOFT_LINK_IS_OPTIONAL)
 
+#define SOFT_LINK_CLASS_ALLOC_FUNCTION(className, availability) \
+    className *alloc##className##Instance() availability; \
+    className *alloc##className##Instance() availability \
+    { \
+        return [get##className##Class() alloc]; \
+    } \
+
+#define SOFT_LINK_CLASS_FOR_SOURCE_OPTIONAL_WITH_EXPORT_AND_AVAILABILITY(functionNamespace, framework, className, export, availability) \
+    SOFT_LINK_CLASS_FOR_SOURCE_INTERNAL(functionNamespace, framework, className, export, SOFT_LINK_IS_OPTIONAL, SOFT_LINK_CLASS_ALLOC_FUNCTION(className, availability))
+
 #define SOFT_LINK_CONSTANT_FOR_HEADER(functionNamespace, framework, variableName, variableType) \
     namespace functionNamespace { \
     variableType get_##framework##_##variableName(); \
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 47237db..3e8f92f 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,90 @@
+2022-01-25  Eric Carlson  <eric.carlson@apple.com>
+
+        [macOS] Add new screen and window capture backend
+        https://bugs.webkit.org/show_bug.cgi?id=234029
+        rdar://problem/86347726
+
+        Reviewed by Jer Noble and Youenn Fablet.
+
+        New API test: GetDisplayMediaWindowAndScreen.mm
+
+        * SourcesCocoa.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * en.lproj/Localizable.strings: Add strings for window and screen prompts.
+
+        * platform/mediastream/MediaConstraints.h:
+        (WebCore::StringConstraint::getExact const): Drive-by: fix logic inversion bug.
+        (WebCore::StringConstraint::getIdeal const): Ditto.
+
+        * platform/mediastream/RealtimeMediaSource.cpp:
+        (WebCore::RealtimeMediaSource::fitnessDistance): Assert if device ID constraint is
+        not a string.
+
+        * platform/mediastream/RealtimeMediaSourceCenter.h:
+        (WebCore::RealtimeMediaSourceCenter::useScreenCaptureKit const):
+        (WebCore::RealtimeMediaSourceCenter::setUseScreenCaptureKit):
+        (WebCore::RealtimeMediaSourceCenter::useMockCaptureDevices const):
+        (WebCore::RealtimeMediaSourceCenter::setUseMockCaptureDevices):
+
+        * platform/mediastream/cocoa/DisplayCaptureSourceCocoa.cpp:
+        (WebCore::DisplayCaptureSourceCocoa::create):
+        (WebCore::DisplayCaptureSourceCocoa::DisplayCaptureSourceCocoa):
+        (WebCore::DisplayCaptureSourceCocoa::Capturer::setObserver):
+        (WebCore::DisplayCaptureSourceCocoa::Capturer::capturerIsRunningChanged): Deleted.
+        * platform/mediastream/cocoa/DisplayCaptureSourceCocoa.h:
+        (WebCore::CapturerObserver::capturerIsRunningChanged):
+        (WebCore::CapturerObserver::capturerFailed):
+
+        * platform/mediastream/ios/ReplayKitCaptureSource.mm:
+        (WebCore::ReplayKitCaptureSource::captureStateDidChange):
+
+        * platform/mediastream/mac/DisplayCaptureManagerCocoa.cpp:
+        (WebCore::DisplayCaptureManagerCocoa::updateDisplayCaptureDevices): Use
+        ScreenCaptureKitCaptureSource when available.
+        (WebCore::DisplayCaptureManagerCocoa::updateWindowCaptureDevices): Ditto.
+        (WebCore::DisplayCaptureManagerCocoa::screenCaptureDeviceWithPersistentID): Ditto.
+        (WebCore::DisplayCaptureManagerCocoa::windowCaptureDeviceWithPersistentID): Ditto.
+
+        * platform/mediastream/mac/ScreenCaptureKitCaptureSource.h: Added.
+        * platform/mediastream/mac/ScreenCaptureKitCaptureSource.mm: Added.
+        (-[WebCoreScreenCaptureKitHelper initWithCallback:]):
+        (-[WebCoreScreenCaptureKitHelper disconnect]):
+        (-[WebCoreScreenCaptureKitHelper stream:didStopWithError:]):
+        (WebCore::usingOldAPI):
+        (WebCore::ScreenCaptureKitCaptureSource::isAvailable):
+        (WebCore::ScreenCaptureKitCaptureSource::create):
+        (WebCore::ScreenCaptureKitCaptureSource::ScreenCaptureKitCaptureSource):
+        (WebCore::ScreenCaptureKitCaptureSource::~ScreenCaptureKitCaptureSource):
+        (WebCore::ScreenCaptureKitCaptureSource::start):
+        (WebCore::ScreenCaptureKitCaptureSource::stop):
+        (WebCore::ScreenCaptureKitCaptureSource::streamFailedWithError):
+        (WebCore::ScreenCaptureKitCaptureSource::generateFrame):
+        (WebCore::ScreenCaptureKitCaptureSource::processSharableContent):
+        (WebCore::ScreenCaptureKitCaptureSource::findShareableContent):
+        (WebCore::ScreenCaptureKitCaptureSource::streamConfiguration):
+        (WebCore::ScreenCaptureKitCaptureSource::startContentStream):
+        (WebCore::ScreenCaptureKitCaptureSource::intrinsicSize const):
+        (WebCore::ScreenCaptureKitCaptureSource::updateStreamConfiguration):
+        (WebCore::ScreenCaptureKitCaptureSource::commitConfiguration):
+        (WebCore::ScreenCaptureKitCaptureSource::captureQueue):
+        (WebCore::ScreenCaptureKitCaptureSource::frameAvailableHandler):
+        (WebCore::ScreenCaptureKitCaptureSource::deviceType const):
+        (WebCore::ScreenCaptureKitCaptureSource::surfaceType const):
+        (WebCore::ScreenCaptureKitCaptureSource::screenCaptureDeviceWithPersistentID):
+        (WebCore::ScreenCaptureKitCaptureSource::screenCaptureDevices):
+        (WebCore::ScreenCaptureKitCaptureSource::windowCaptureDeviceWithPersistentID):
+        (WebCore::ScreenCaptureKitCaptureSource::windowCaptureDevices):
+        (WebCore::ScreenCaptureKitCaptureSource::forEachNSWindow):
+
+        * platform/mock/MockMediaDevice.h:
+        (WebCore::MockMediaDevice::captureDevice const): Make devices enabled by default. 
+        Initialize screen and window devices with the correct type.
+
+        * platform/mock/MockRealtimeMediaSourceCenter.cpp:
+        (WebCore::defaultDevices): Fix window device types.
+        (WebCore::MockRealtimeMediaSourceCenter::displayDevices):
+        * platform/mock/MockRealtimeMediaSourceCenter.h:
+
 2022-01-25  Tim Horton  <timothy_horton@apple.com>
 
         Shadows are flattened to bitmaps in CGDisplayListImageBufferBackend
diff --git a/Source/WebCore/Headers.cmake b/Source/WebCore/Headers.cmake
index a5ea525..f43ad67 100644
--- a/Source/WebCore/Headers.cmake
+++ b/Source/WebCore/Headers.cmake
@@ -1672,6 +1672,7 @@
 
     platform/mediastream/CaptureDevice.h
     platform/mediastream/CaptureDeviceManager.h
+    platform/mediastream/DisplayCaptureManager.h
     platform/mediastream/MDNSRegisterError.h
     platform/mediastream/MediaConstraints.h
     platform/mediastream/MediaStreamPrivate.h
diff --git a/Source/WebCore/Modules/mediastream/UserMediaRequest.cpp b/Source/WebCore/Modules/mediastream/UserMediaRequest.cpp
index c39b8f0..527fbb4 100644
--- a/Source/WebCore/Modules/mediastream/UserMediaRequest.cpp
+++ b/Source/WebCore/Modules/mediastream/UserMediaRequest.cpp
@@ -112,6 +112,7 @@
 
     switch (m_request.type) {
     case MediaStreamRequest::Type::DisplayMedia:
+    case MediaStreamRequest::Type::DisplayMediaWithAudio:
         if (!isFeaturePolicyAllowedByDocumentAndAllOwners(FeaturePolicy::Type::DisplayCapture, document)) {
             deny(MediaAccessDenialReason::PermissionDenied);
             controller->logGetDisplayMediaDenial(document);
diff --git a/Source/WebCore/PAL/ChangeLog b/Source/WebCore/PAL/ChangeLog
index 05c5abf..619afe8 100644
--- a/Source/WebCore/PAL/ChangeLog
+++ b/Source/WebCore/PAL/ChangeLog
@@ -1,3 +1,15 @@
+2022-01-25  Eric Carlson  <eric.carlson@apple.com>
+
+        [macOS] Add new screen and window capture backend
+        https://bugs.webkit.org/show_bug.cgi?id=234029
+        rdar://problem/86347726
+
+        Reviewed by Jer Noble and Youenn Fablet.
+
+        * PAL.xcodeproj/project.pbxproj:
+        * pal/mac/ScreenCaptureKitSoftLink.h: Added.
+        * pal/mac/ScreenCaptureKitSoftLink.mm: Added.
+
 2022-01-24  Myles C. Maxfield  <mmaxfield@apple.com>
 
         REGRESSION(r282320): [Cocoa] User-installed fonts don't work in the GPU Process (in WKWebView)
@@ -8,7 +20,7 @@
 
         * pal/spi/cf/CoreTextSPI.h:
 
-2022-01-24  David Quesada  <david_quesada@apple.com>
+022-01-24  David Quesada  <david_quesada@apple.com>
 
         Simplify accesses to SystemVersion.plist
         https://bugs.webkit.org/show_bug.cgi?id=234306
diff --git a/Source/WebCore/PAL/PAL.xcodeproj/project.pbxproj b/Source/WebCore/PAL/PAL.xcodeproj/project.pbxproj
index 35588f7..8380ee0 100644
--- a/Source/WebCore/PAL/PAL.xcodeproj/project.pbxproj
+++ b/Source/WebCore/PAL/PAL.xcodeproj/project.pbxproj
@@ -25,6 +25,8 @@
 		071C00382707EDF000D027C7 /* ReplayKitSoftLink.h in Headers */ = {isa = PBXBuildFile; fileRef = 071C00362707EDF000D027C7 /* ReplayKitSoftLink.h */; };
 		07611DB6243FA5BF00D80704 /* UsageTrackingSoftLink.h in Headers */ = {isa = PBXBuildFile; fileRef = 07611DB4243FA5BE00D80704 /* UsageTrackingSoftLink.h */; };
 		07611DB7243FA5BF00D80704 /* UsageTrackingSoftLink.mm in Sources */ = {isa = PBXBuildFile; fileRef = 07611DB5243FA5BF00D80704 /* UsageTrackingSoftLink.mm */; };
+		07789181273B14FF00E408D1 /* ScreenCaptureKitSoftLink.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0778917F273B14FF00E408D1 /* ScreenCaptureKitSoftLink.mm */; };
+		07789182273B14FF00E408D1 /* ScreenCaptureKitSoftLink.h in Headers */ = {isa = PBXBuildFile; fileRef = 07789180273B14FF00E408D1 /* ScreenCaptureKitSoftLink.h */; };
 		077E87B1226A460200A2AFF0 /* AVFoundationSoftLink.mm in Sources */ = {isa = PBXBuildFile; fileRef = 077E87AF226A460200A2AFF0 /* AVFoundationSoftLink.mm */; };
 		077E87B2226A460300A2AFF0 /* AVFoundationSoftLink.h in Headers */ = {isa = PBXBuildFile; fileRef = 077E87B0226A460200A2AFF0 /* AVFoundationSoftLink.h */; };
 		079D1D9726950DD700883577 /* SystemStatusSoftLink.h in Headers */ = {isa = PBXBuildFile; fileRef = 079D1D9526950DD700883577 /* SystemStatusSoftLink.h */; };
@@ -432,6 +434,8 @@
 		071C00362707EDF000D027C7 /* ReplayKitSoftLink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ReplayKitSoftLink.h; sourceTree = "<group>"; };
 		07611DB4243FA5BE00D80704 /* UsageTrackingSoftLink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UsageTrackingSoftLink.h; sourceTree = "<group>"; };
 		07611DB5243FA5BF00D80704 /* UsageTrackingSoftLink.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = UsageTrackingSoftLink.mm; sourceTree = "<group>"; };
+		0778917F273B14FF00E408D1 /* ScreenCaptureKitSoftLink.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ScreenCaptureKitSoftLink.mm; sourceTree = "<group>"; };
+		07789180273B14FF00E408D1 /* ScreenCaptureKitSoftLink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScreenCaptureKitSoftLink.h; sourceTree = "<group>"; };
 		077E87AF226A460200A2AFF0 /* AVFoundationSoftLink.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AVFoundationSoftLink.mm; sourceTree = "<group>"; };
 		077E87B0226A460200A2AFF0 /* AVFoundationSoftLink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AVFoundationSoftLink.h; sourceTree = "<group>"; };
 		079D1D9526950DD700883577 /* SystemStatusSoftLink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SystemStatusSoftLink.h; sourceTree = "<group>"; };
@@ -1051,6 +1055,7 @@
 				0C7785841F45130F00F4EBB6 /* NSWindowSPI.h */,
 				0C7785851F45130F00F4EBB6 /* PIPSPI.h */,
 				0C7785871F45130F00F4EBB6 /* QuickLookMacSPI.h */,
+				A1175B481F6AFF8E00C4B9F0 /* SpeechSynthesisSPI.h */,
 				71B1141F26823ACD004D6701 /* SystemPreviewSPI.h */,
 				0C7785881F45130F00F4EBB6 /* TelephonyUtilitiesSPI.h */,
 			);
@@ -1419,6 +1424,8 @@
 				44E1A8AE21FA54DA00C3048E /* LookupSoftLink.mm */,
 				F4C85A4D2658551A005B89CC /* QuickLookUISoftLink.h */,
 				F4C85A4C26585519005B89CC /* QuickLookUISoftLink.mm */,
+				07789180273B14FF00E408D1 /* ScreenCaptureKitSoftLink.h */,
+				0778917F273B14FF00E408D1 /* ScreenCaptureKitSoftLink.mm */,
 			);
 			path = mac;
 			sourceTree = "<group>";
@@ -1669,6 +1676,7 @@
 				F4974EA3265EEA2200B49B8C /* RevealSoftLink.h in Headers */,
 				442956CD218A72DF0080DB54 /* RevealSPI.h in Headers */,
 				BC4DDD9F273EF56E00660EBB /* SceneKitSPI.h in Headers */,
+				07789182273B14FF00E408D1 /* ScreenCaptureKitSoftLink.h in Headers */,
 				570AB8F120AE2E8D00B8BE87 /* SecKeyProxySPI.h in Headers */,
 				0C2DA1581F3BEB4900DBC317 /* ServersSPI.h in Headers */,
 				A3C66CDD1F462D6A009E6EE9 /* SessionID.h in Headers */,
@@ -1946,6 +1954,7 @@
 				F4C85A4E2658551A005B89CC /* QuickLookUISoftLink.mm in Sources */,
 				071C00372707EDF000D027C7 /* ReplayKitSoftLink.mm in Sources */,
 				F4974EA4265EEA2200B49B8C /* RevealSoftLink.mm in Sources */,
+				07789181273B14FF00E408D1 /* ScreenCaptureKitSoftLink.mm in Sources */,
 				A3C66CDC1F462D6A009E6EE9 /* SessionID.cpp in Sources */,
 				A3AB6E521F3D1DC5009C14B1 /* SleepDisabler.cpp in Sources */,
 				A3AB6E601F3D1E39009C14B1 /* SleepDisablerCocoa.cpp in Sources */,
diff --git a/Source/WebCore/PAL/pal/mac/ScreenCaptureKitSoftLink.h b/Source/WebCore/PAL/pal/mac/ScreenCaptureKitSoftLink.h
new file mode 100644
index 0000000..71a04aa
--- /dev/null
+++ b/Source/WebCore/PAL/pal/mac/ScreenCaptureKitSoftLink.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2021-2022 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 HAVE(SCREEN_CAPTURE_KIT)
+
+#include <wtf/SoftLinking.h>
+
+SOFT_LINK_FRAMEWORK_FOR_HEADER(PAL, ScreenCaptureKit);
+
+SOFT_LINK_CLASS_FOR_HEADER_WITH_AVAILABILITY(PAL, SCWindow, API_AVAILABLE(macos(12.3)))
+SOFT_LINK_CLASS_FOR_HEADER_WITH_AVAILABILITY(PAL, SCDisplay, API_AVAILABLE(macos(12.3)))
+SOFT_LINK_CLASS_FOR_HEADER_WITH_AVAILABILITY(PAL, SCShareableContent, API_AVAILABLE(macos(12.3)))
+SOFT_LINK_CLASS_FOR_HEADER_WITH_AVAILABILITY(PAL, SCContentFilter, API_AVAILABLE(macos(12.3)))
+SOFT_LINK_CLASS_FOR_HEADER_WITH_AVAILABILITY(PAL, SCStreamConfiguration, API_AVAILABLE(macos(12.3)))
+SOFT_LINK_CLASS_FOR_HEADER_WITH_AVAILABILITY(PAL, SCStream, API_AVAILABLE(macos(12.3)))
+
+SOFT_LINK_CONSTANT_MAY_FAIL_FOR_HEADER(PAL, ScreenCaptureKit, SCStreamFrameInfoStatusKey, NSString *)
+#define SCStreamFrameInfoStatusKey get_ScreenCaptureKit_SCStreamFrameInfoStatusKey()
+
+#endif // HAVE(SCREEN_CAPTURE_KIT)
diff --git a/Source/WebCore/PAL/pal/mac/ScreenCaptureKitSoftLink.mm b/Source/WebCore/PAL/pal/mac/ScreenCaptureKitSoftLink.mm
new file mode 100644
index 0000000..2ae425b
--- /dev/null
+++ b/Source/WebCore/PAL/pal/mac/ScreenCaptureKitSoftLink.mm
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021-2022 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.
+ */
+
+#include "config.h"
+
+#if HAVE(SCREEN_CAPTURE_KIT)
+
+#import <wtf/SoftLinking.h>
+
+SOFT_LINK_FRAMEWORK_FOR_SOURCE_WITH_EXPORT(PAL, ScreenCaptureKit, PAL_EXPORT)
+
+SOFT_LINK_CLASS_FOR_SOURCE_OPTIONAL_WITH_EXPORT_AND_AVAILABILITY(PAL, ScreenCaptureKit, SCWindow, PAL_EXPORT, API_AVAILABLE(macos(12.3)))
+SOFT_LINK_CLASS_FOR_SOURCE_OPTIONAL_WITH_EXPORT_AND_AVAILABILITY(PAL, ScreenCaptureKit, SCDisplay, PAL_EXPORT, API_AVAILABLE(macos(12.3)))
+SOFT_LINK_CLASS_FOR_SOURCE_OPTIONAL_WITH_EXPORT_AND_AVAILABILITY(PAL, ScreenCaptureKit, SCShareableContent, PAL_EXPORT, API_AVAILABLE(macos(12.3)))
+SOFT_LINK_CLASS_FOR_SOURCE_OPTIONAL_WITH_EXPORT_AND_AVAILABILITY(PAL, ScreenCaptureKit, SCContentFilter, PAL_EXPORT, API_AVAILABLE(macos(12.3)))
+SOFT_LINK_CLASS_FOR_SOURCE_OPTIONAL_WITH_EXPORT_AND_AVAILABILITY(PAL, ScreenCaptureKit, SCStreamConfiguration, PAL_EXPORT, API_AVAILABLE(macos(12.3)))
+SOFT_LINK_CLASS_FOR_SOURCE_OPTIONAL_WITH_EXPORT_AND_AVAILABILITY(PAL, ScreenCaptureKit, SCStream, PAL_EXPORT, API_AVAILABLE(macos(12.3)))
+
+SOFT_LINK_CONSTANT_MAY_FAIL_FOR_SOURCE_WITH_EXPORT(PAL, ScreenCaptureKit, SCStreamFrameInfoStatusKey, NSString *, PAL_EXPORT)
+
+#endif // PLATFORM(MAC)
diff --git a/Source/WebCore/SourcesCocoa.txt b/Source/WebCore/SourcesCocoa.txt
index 3ad671b..dd404cf 100644
--- a/Source/WebCore/SourcesCocoa.txt
+++ b/Source/WebCore/SourcesCocoa.txt
@@ -559,6 +559,7 @@
 platform/mediastream/mac/RealtimeMediaSourceCenterMac.mm
 platform/mediastream/mac/RealtimeOutgoingAudioSourceCocoa.cpp
 platform/mediastream/mac/RealtimeOutgoingVideoSourceCocoa.cpp
+platform/mediastream/mac/ScreenCaptureKitCaptureSource.mm
 platform/mediastream/mac/WebAudioSourceProviderCocoa.mm
 platform/mock/MediaPlaybackTargetMock.cpp
 platform/mock/MediaPlaybackTargetPickerMock.cpp
diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj
index a58ebce..413426a 100644
--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj
+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj
@@ -94,6 +94,7 @@
 		0709D7931AE5557E004E42F8 /* WebMediaSessionManagerMac.h in Headers */ = {isa = PBXBuildFile; fileRef = 0709D7911AE5557E004E42F8 /* WebMediaSessionManagerMac.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0709D7951AE55A29004E42F8 /* WebMediaSessionManagerClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 0709D7941AE55A29004E42F8 /* WebMediaSessionManagerClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0709FC4E1025DEE30059CDBA /* AccessibilitySlider.h in Headers */ = {isa = PBXBuildFile; fileRef = 0709FC4D1025DEE30059CDBA /* AccessibilitySlider.h */; };
+		070BED98273F415D00583926 /* ScreenCaptureKitCaptureSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 070BED97273F415600583926 /* ScreenCaptureKitCaptureSource.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		070E09191875EEFC003A1D3C /* PlatformMediaSession.h in Headers */ = {isa = PBXBuildFile; fileRef = 070E09181875ED93003A1D3C /* PlatformMediaSession.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		070E2D0F26F250890014AAC3 /* InbandChapterTrackPrivateAVFObjC.mm in Sources */ = {isa = PBXBuildFile; fileRef = 070E2D0C26F15B180014AAC3 /* InbandChapterTrackPrivateAVFObjC.mm */; };
 		070E2D1026F250930014AAC3 /* InbandChapterTrackPrivateAVFObjC.h in Headers */ = {isa = PBXBuildFile; fileRef = 070E2D0E26F15B190014AAC3 /* InbandChapterTrackPrivateAVFObjC.h */; };
@@ -208,7 +209,7 @@
 		07B7116D1D899E63009F0FFB /* CaptureDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 07B7116A1D899E63009F0FFB /* CaptureDevice.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		07B7116F1D899E63009F0FFB /* CaptureDeviceManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 07B7116C1D899E63009F0FFB /* CaptureDeviceManager.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		07B93FFC23B94EC70036F8EA /* MIMETypeCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 07B93FF923B92AAA0036F8EA /* MIMETypeCache.h */; settings = {ATTRIBUTES = (Private, ); }; };
-		07BB1E7027176CD9001DF289 /* DisplayCaptureSourceCocoa.h in Headers */ = {isa = PBXBuildFile; fileRef = 07BB1E6F27176CCA001DF289 /* DisplayCaptureSourceCocoa.h */; };
+		07BB1E7027176CD9001DF289 /* DisplayCaptureSourceCocoa.h in Headers */ = {isa = PBXBuildFile; fileRef = 07BB1E6F27176CCA001DF289 /* DisplayCaptureSourceCocoa.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		07C046C41E42508B007201E7 /* CAAudioStreamDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = 073B87581E40DCFD0071C0EC /* CAAudioStreamDescription.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		07C046CB1E426413007201E7 /* AudioStreamDescription.h in Headers */ = {isa = PBXBuildFile; fileRef = 073B87561E40DCE50071C0EC /* AudioStreamDescription.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		07C1482E2612A21F00775828 /* MediaSessionCoordinatorState.h in Headers */ = {isa = PBXBuildFile; fileRef = 077BA58826126D660072F19F /* MediaSessionCoordinatorState.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -221,6 +222,7 @@
 		07D6A4F81BF2307D00174146 /* AudioTrackPrivateMediaStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 07D6A4F61BF2307D00174146 /* AudioTrackPrivateMediaStream.h */; };
 		07E3DFD11A9E786500764CA8 /* MediaPlaybackTarget.h in Headers */ = {isa = PBXBuildFile; fileRef = 07E3DFD01A9E786500764CA8 /* MediaPlaybackTarget.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		07E9E12E18F5E2760011A3A4 /* InbandMetadataTextTrackPrivateAVF.h in Headers */ = {isa = PBXBuildFile; fileRef = 07E9E12D18F5E2760011A3A4 /* InbandMetadataTextTrackPrivateAVF.h */; };
+		07ED19382762769400AF1EC5 /* DisplayCaptureManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 07ED19372762769400AF1EC5 /* DisplayCaptureManager.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		07EE76EC1BE96DB000F89133 /* MockRealtimeVideoSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 07EE76EA1BE96DB000F89133 /* MockRealtimeVideoSource.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		07EE76EF1BEA619800F89133 /* MockRealtimeVideoSourceMac.h in Headers */ = {isa = PBXBuildFile; fileRef = 07EE76ED1BEA619800F89133 /* MockRealtimeVideoSourceMac.h */; };
 		07F4E93320B3587F002E3803 /* AVAssetMIMETypeCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 07C8AD121D073D630087C5CE /* AVAssetMIMETypeCache.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -5941,6 +5943,8 @@
 		0709D7911AE5557E004E42F8 /* WebMediaSessionManagerMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebMediaSessionManagerMac.h; sourceTree = "<group>"; };
 		0709D7941AE55A29004E42F8 /* WebMediaSessionManagerClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebMediaSessionManagerClient.h; sourceTree = "<group>"; };
 		0709FC4D1025DEE30059CDBA /* AccessibilitySlider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AccessibilitySlider.h; sourceTree = "<group>"; };
+		070BED96273F415600583926 /* ScreenCaptureKitCaptureSource.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ScreenCaptureKitCaptureSource.mm; sourceTree = "<group>"; };
+		070BED97273F415600583926 /* ScreenCaptureKitCaptureSource.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ScreenCaptureKitCaptureSource.h; sourceTree = "<group>"; };
 		070DD8F50F01868000727DEB /* mediaControls.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mediaControls.css; sourceTree = "<group>"; };
 		070E09181875ED93003A1D3C /* PlatformMediaSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformMediaSession.h; sourceTree = "<group>"; };
 		070E091A1875EF71003A1D3C /* PlatformMediaSession.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PlatformMediaSession.cpp; sourceTree = "<group>"; };
@@ -6179,6 +6183,7 @@
 		07E3DFD01A9E786500764CA8 /* MediaPlaybackTarget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaPlaybackTarget.h; sourceTree = "<group>"; };
 		07E9E12D18F5E2760011A3A4 /* InbandMetadataTextTrackPrivateAVF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InbandMetadataTextTrackPrivateAVF.h; sourceTree = "<group>"; };
 		07E9E12F18F62B370011A3A4 /* InbandMetadataTextTrackPrivateAVF.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InbandMetadataTextTrackPrivateAVF.cpp; sourceTree = "<group>"; };
+		07ED19372762769400AF1EC5 /* DisplayCaptureManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DisplayCaptureManager.h; sourceTree = "<group>"; };
 		07EE76E91BE96DB000F89133 /* MockRealtimeVideoSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MockRealtimeVideoSource.cpp; sourceTree = "<group>"; };
 		07EE76EA1BE96DB000F89133 /* MockRealtimeVideoSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MockRealtimeVideoSource.h; sourceTree = "<group>"; };
 		07EE76ED1BEA619800F89133 /* MockRealtimeVideoSourceMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MockRealtimeVideoSourceMac.h; sourceTree = "<group>"; };
@@ -18582,6 +18587,7 @@
 				07B7116A1D899E63009F0FFB /* CaptureDevice.h */,
 				07B7116B1D899E63009F0FFB /* CaptureDeviceManager.cpp */,
 				07B7116C1D899E63009F0FFB /* CaptureDeviceManager.h */,
+				07ED19372762769400AF1EC5 /* DisplayCaptureManager.h */,
 				5EBB89301C7777E100C65D41 /* IceCandidate.h */,
 				41C14BC826DF79D600685BF5 /* MDNSRegisterError.h */,
 				1BE5BFC11D515715001666D9 /* MediaConstraints.cpp */,
@@ -18693,6 +18699,8 @@
 				5CDD833C1E4324BB00621B83 /* RealtimeOutgoingVideoSourceCocoa.h */,
 				419242472127B7CC00634FCF /* RealtimeOutgoingVideoSourceCocoa.mm */,
 				41D1938F2152C561006F14CA /* RealtimeVideoUtilities.h */,
+				070BED97273F415600583926 /* ScreenCaptureKitCaptureSource.h */,
+				070BED96273F415600583926 /* ScreenCaptureKitCaptureSource.mm */,
 				07D6373E1BB0B11300256CE9 /* WebAudioSourceProviderCocoa.h */,
 				07D6373F1BB0B11300256CE9 /* WebAudioSourceProviderCocoa.mm */,
 			);
@@ -34193,6 +34201,7 @@
 				835D54C51F4DE53800E60671 /* DirectoryFileListCreator.h in Headers */,
 				F47A09D120A93A9700240FAE /* DisabledAdaptations.h in Headers */,
 				7EDAAFC919A2CCDC0034DFD1 /* DiskCacheMonitorCocoa.h in Headers */,
+				07ED19382762769400AF1EC5 /* DisplayCaptureManager.h in Headers */,
 				07BB1E7027176CD9001DF289 /* DisplayCaptureSourceCocoa.h in Headers */,
 				7BFF59F42757726700773D39 /* DisplayConfigurationMonitor.h in Headers */,
 				0FE5FBD31C3DD51E0007A2CA /* DisplayList.h in Headers */,
@@ -37007,6 +37016,7 @@
 				9BD0BF9312A42BF50072FD43 /* ScopedEventQueue.h in Headers */,
 				7B7311FB25C092B7003B2796 /* ScopedHighPerformanceGPURequest.h in Headers */,
 				BCEC01BE0C274DAC009F4EC9 /* Screen.h in Headers */,
+				070BED98273F415D00583926 /* ScreenCaptureKitCaptureSource.h in Headers */,
 				C1E1D236203DF15400584665 /* ScreenProperties.h in Headers */,
 				A84D82C111D3474800972990 /* ScriptableDocumentParser.h in Headers */,
 				462E4C502616A811003A2C67 /* ScriptBuffer.h in Headers */,
diff --git a/Source/WebCore/en.lproj/Localizable.strings b/Source/WebCore/en.lproj/Localizable.strings
index ac74532..3eee88f 100644
--- a/Source/WebCore/en.lproj/Localizable.strings
+++ b/Source/WebCore/en.lproj/Localizable.strings
@@ -145,6 +145,12 @@
 /* Undo action name */
 "Align Right (Undo action name)" = "Align Right";
 
+/* Allow screen button title in window and screen sharing prompt */
+"Allow Observing a Screen" = "Allow Observing a Screen";
+
+/* Allow window button title in window and screen sharing prompt */
+"Allow Observing a Window" = "Allow Observing a Window";
+
 /* Button title in Storage Access API prompt */
 "Allow (cross-site cookie and website data access)" = "Allow";
 
@@ -163,12 +169,18 @@
 /* Allow button title in user media prompt */
 "Allow (usermedia)" = "Allow";
 
+/* Allow button title in window sharing prompt */
+"Allow (window sharing)" = "Allow";
+
 /* Message for requesting cross-site cookie and website data access. */
 "Allow “%@” and “%@” to use cookies and website data while browsing “%@”?" = "Allow “%@” and “%@” to use cookies and website data while browsing “%@”?";
 
 /* Message for spechrecognition prompt */
 "Allow “%@” to capture your audio and use it for speech recognition?" = "Allow “%@” to capture your audio and use it for speech recognition?";
 
+/* Message for window and screen sharing prompt */
+"Allow “%@” to observe one of your windows or screens?" = "Allow “%@” to observe one of your windows or screens?";
+
 /* Message for screen sharing prompt */
 "Allow “%@” to observe your screen?" = "Allow “%@” to observe your screen?";
 
@@ -268,6 +280,9 @@
 /* Label for the check out with Apple Pay button. */
 "Check out with Apple Pay" = "Check out with Apple Pay";
 
+/* Message for window sharing prompt */
+"Choose a window to share" = "Choose a window to share";
+
 /* title for a single file chooser button used in HTML forms */
 "Choose File" = "Choose File";
 
@@ -397,6 +412,12 @@
 /* Disallow button title in user media prompt */
 "Don’t Allow (usermedia)" = "Don’t Allow";
 
+/* Disallow button title in window and screen sharing prompt */
+"Don’t Allow (window and screen sharing)" = "Don’t Allow";
+
+/* Disallow button title in window sharing prompt */
+"Don’t Allow (window sharing)" = "Don’t Allow";
+
 /* Download Audio To Disk context menu item */
 "Download Audio" = "Download Audio";
 
@@ -1162,6 +1183,9 @@
 /* Unwanted software warning title */
 "Website With Harmful Software Warning" = "Website With Harmful Software Warning";
 
+/* Label for window sharing menu */
+"Window: " = "Window: ";
+
 /* Year label in date picker */
 "YEAR (Date picker for extra zoom mode)" = "YEAR";
 
diff --git a/Source/WebCore/platform/mediastream/DisplayCaptureManager.h b/Source/WebCore/platform/mediastream/DisplayCaptureManager.h
new file mode 100644
index 0000000..6ddc420
--- /dev/null
+++ b/Source/WebCore/platform/mediastream/DisplayCaptureManager.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021-2022 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. ``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
+ * 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 "CaptureDeviceManager.h"
+
+namespace WebCore {
+
+class DisplayCaptureManager : public CaptureDeviceManager {
+public:
+
+    struct WindowCaptureDevice {
+        CaptureDevice m_device;
+        String m_application;
+    };
+
+    virtual void windowDevices(Vector<WindowCaptureDevice>&) { }
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(MEDIA_STREAM)
diff --git a/Source/WebCore/platform/mediastream/MediaConstraints.h b/Source/WebCore/platform/mediastream/MediaConstraints.h
index ab7d493..4c31e46 100644
--- a/Source/WebCore/platform/mediastream/MediaConstraints.h
+++ b/Source/WebCore/platform/mediastream/MediaConstraints.h
@@ -573,7 +573,7 @@
 
     bool getExact(Vector<String>& exact) const
     {
-        if (!m_exact.isEmpty())
+        if (m_exact.isEmpty())
             return false;
 
         exact = m_exact;
@@ -582,7 +582,7 @@
 
     bool getIdeal(Vector<String>& ideal) const
     {
-        if (!m_ideal.isEmpty())
+        if (m_ideal.isEmpty())
             return false;
 
         ideal = m_ideal;
diff --git a/Source/WebCore/platform/mediastream/MediaStreamRequest.h b/Source/WebCore/platform/mediastream/MediaStreamRequest.h
index 6850adb..a4d4b52 100644
--- a/Source/WebCore/platform/mediastream/MediaStreamRequest.h
+++ b/Source/WebCore/platform/mediastream/MediaStreamRequest.h
@@ -34,7 +34,7 @@
 namespace WebCore {
 
 struct MediaStreamRequest {
-    enum class Type { UserMedia, DisplayMedia };
+    enum class Type { UserMedia, DisplayMedia, DisplayMediaWithAudio };
     Type type { Type::UserMedia };
     MediaConstraints audioConstraints;
     MediaConstraints videoConstraints;
@@ -66,7 +66,7 @@
 namespace WebCore {
 
 struct MediaStreamRequest {
-    enum class Type { UserMedia, DisplayMedia };
+    enum class Type { UserMedia, DisplayMedia, DisplayMediaWithAudio };
     Type type;
 };
 
@@ -80,7 +80,8 @@
     using values = EnumValues<
         WebCore::MediaStreamRequest::Type,
         WebCore::MediaStreamRequest::Type::UserMedia,
-        WebCore::MediaStreamRequest::Type::DisplayMedia
+        WebCore::MediaStreamRequest::Type::DisplayMedia,
+        WebCore::MediaStreamRequest::Type::DisplayMediaWithAudio
     >;
 };
 
diff --git a/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp b/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp
index 1dd1e5f..256d3cf 100644
--- a/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp
+++ b/Source/WebCore/platform/mediastream/RealtimeMediaSource.cpp
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2012 Google Inc. All rights reserved.
- * Copyright (C) 2013-2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2022 Apple Inc. All rights reserved.
  * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies).
  * Copyright (C) 2015 Ericsson AB. All rights reserved.
  *
@@ -489,6 +489,7 @@
     }
 
     case MediaConstraintType::DeviceId:
+        ASSERT(constraint.isString());
         ASSERT(!m_hashedID.isEmpty());
         return downcast<StringConstraint>(constraint).fitnessDistance(m_hashedID);
         break;
diff --git a/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp b/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp
index f92ae17..9452632 100644
--- a/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp
+++ b/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.cpp
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2011 Ericsson AB. All rights reserved.
  * Copyright (C) 2012 Google Inc. All rights reserved.
- * Copyright (C) 2013-2018 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2022 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -35,7 +35,7 @@
 
 #if ENABLE(MEDIA_STREAM)
 
-#include "CaptureDeviceManager.h"
+#include "DisplayCaptureManager.h"
 #include "Logging.h"
 #include "MediaStreamPrivate.h"
 #include <wtf/CallbackAggregator.h>
@@ -261,7 +261,7 @@
 void RealtimeMediaSourceCenter::validateRequestConstraints(ValidConstraintsHandler&& validHandler, InvalidConstraintsHandler&& invalidHandler, const MediaStreamRequest& request, String&& deviceIdentifierHashSalt)
 {
     bool shouldEnumerateCamera = request.videoConstraints.isValid;
-    bool shouldEnumerateDisplay = request.type == MediaStreamRequest::Type::DisplayMedia;
+    bool shouldEnumerateDisplay = (request.type == MediaStreamRequest::Type::DisplayMedia || request.type == MediaStreamRequest::Type::DisplayMediaWithAudio);
     bool shouldEnumerateMicrophone = request.audioConstraints.isValid;
     bool shouldEnumerateSpeakers = false;
     enumerateDevices(shouldEnumerateCamera, shouldEnumerateDisplay, shouldEnumerateMicrophone, shouldEnumerateSpeakers, [this, validHandler = WTFMove(validHandler), invalidHandler = WTFMove(invalidHandler), request, deviceIdentifierHashSalt = WTFMove(deviceIdentifierHashSalt)]() mutable {
@@ -282,7 +282,7 @@
     Vector<DeviceInfo> videoDeviceInfo;
     String firstInvalidConstraint;
 
-    if (request.type == MediaStreamRequest::Type::DisplayMedia)
+    if (request.type == MediaStreamRequest::Type::DisplayMedia || request.type == MediaStreamRequest::Type::DisplayMediaWithAudio)
         getDisplayMediaDevices(request, String { deviceIdentifierHashSalt }, videoDeviceInfo, firstInvalidConstraint);
     else
         getUserMediaDevices(request, String { deviceIdentifierHashSalt }, audioDeviceInfo, videoDeviceInfo, firstInvalidConstraint);
diff --git a/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h b/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h
index eebd834..fc9141a 100644
--- a/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h
+++ b/Source/WebCore/platform/mediastream/RealtimeMediaSourceCenter.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2011 Ericsson AB. All rights reserved.
  * Copyright (C) 2012 Google Inc. All rights reserved.
- * Copyright (C) 2013-2018 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2022 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -110,6 +110,11 @@
     OSObjectPtr<tcc_identity_t> identity() const { return m_identity; }
 #endif
 
+#if HAVE(SCREEN_CAPTURE_KIT)
+    bool useScreenCaptureKit() const;
+    void setUseScreenCaptureKit(bool);
+#endif
+
 private:
     RealtimeMediaSourceCenter();
     friend class NeverDestroyed<RealtimeMediaSourceCenter>;
@@ -144,8 +149,25 @@
 #if ENABLE(APP_PRIVACY_REPORT)
     OSObjectPtr<tcc_identity_t> m_identity;
 #endif
+
+#if HAVE(SCREEN_CAPTURE_KIT)
+    bool m_useScreenCaptureKit { false };
+#endif
+    bool m_useMockCaptureDevices { false };
 };
 
+#if HAVE(SCREEN_CAPTURE_KIT)
+inline bool RealtimeMediaSourceCenter::useScreenCaptureKit() const
+{
+    return m_useScreenCaptureKit;
+}
+
+inline void RealtimeMediaSourceCenter::setUseScreenCaptureKit(bool useScreenCaptureKit)
+{
+    m_useScreenCaptureKit = useScreenCaptureKit;
+}
+#endif
+
 } // namespace WebCore
 
 #endif // ENABLE(MEDIA_STREAM)
diff --git a/Source/WebCore/platform/mediastream/RealtimeMediaSourceFactory.h b/Source/WebCore/platform/mediastream/RealtimeMediaSourceFactory.h
index 99d945a..ba0d903 100644
--- a/Source/WebCore/platform/mediastream/RealtimeMediaSourceFactory.h
+++ b/Source/WebCore/platform/mediastream/RealtimeMediaSourceFactory.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 Apple Inc. All rights reserved.
+ * Copyright (C) 2018-2022 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -35,6 +35,7 @@
 
 class CaptureDevice;
 class CaptureDeviceManager;
+class DisplayCaptureManager;
 class RealtimeMediaSource;
 
 struct CaptureSourceOrError;
@@ -95,7 +96,7 @@
 public:
     virtual ~DisplayCaptureFactory() = default;
     virtual CaptureSourceOrError createDisplayCaptureSource(const CaptureDevice&, String&&, const MediaConstraints*) = 0;
-    virtual CaptureDeviceManager& displayCaptureDeviceManager() = 0;
+    virtual DisplayCaptureManager& displayCaptureDeviceManager() = 0;
 
 protected:
     DisplayCaptureFactory() = default;
diff --git a/Source/WebCore/platform/mediastream/cocoa/DisplayCaptureSourceCocoa.cpp b/Source/WebCore/platform/mediastream/cocoa/DisplayCaptureSourceCocoa.cpp
index c9b9242..2c85266 100644
--- a/Source/WebCore/platform/mediastream/cocoa/DisplayCaptureSourceCocoa.cpp
+++ b/Source/WebCore/platform/mediastream/cocoa/DisplayCaptureSourceCocoa.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017-2021 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2022 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,7 +29,6 @@
 #if ENABLE(MEDIA_STREAM) && PLATFORM(COCOA)
 
 #include "CGDisplayStreamScreenCaptureSource.h"
-#include "CoreVideoSoftLink.h"
 #include "ImageTransferSessionVT.h"
 #include "Logging.h"
 #include "MediaSampleAVFObjC.h"
@@ -40,7 +39,6 @@
 #include "Timer.h"
 #include <IOSurface/IOSurfaceRef.h>
 #include <pal/avfoundation/MediaTimeAVFoundation.h>
-#include <pal/cf/CoreMediaSoftLink.h>
 #include <pal/spi/cf/CoreAudioSPI.h>
 #include <pal/spi/cg/CoreGraphicsSPI.h>
 #include <pal/spi/cocoa/IOSurfaceSPI.h>
@@ -52,6 +50,13 @@
 #include "ReplayKitCaptureSource.h"
 #endif
 
+#if HAVE(SCREEN_CAPTURE_KIT)
+#include "ScreenCaptureKitCaptureSource.h"
+#endif
+
+#include "CoreVideoSoftLink.h"
+#include <pal/cf/CoreMediaSoftLink.h>
+
 namespace WebCore {
 
 CaptureSourceOrError DisplayCaptureSourceCocoa::create(const CaptureDevice& device, String&& hashSalt, const MediaConstraints* constraints)
@@ -61,9 +66,18 @@
 #if PLATFORM(IOS)
         return create(ReplayKitCaptureSource::create(device.persistentId()), device, WTFMove(hashSalt), constraints);
 #else
+#if HAVE(SCREEN_CAPTURE_KIT)
+        if (ScreenCaptureKitCaptureSource::isAvailable())
+            return create(ScreenCaptureKitCaptureSource::create(device, constraints), device, WTFMove(hashSalt), constraints);
+#endif
         return create(CGDisplayStreamScreenCaptureSource::create(device.persistentId()), device, WTFMove(hashSalt), constraints);
 #endif
     case CaptureDevice::DeviceType::Window:
+#if HAVE(SCREEN_CAPTURE_KIT)
+        if (ScreenCaptureKitCaptureSource::isAvailable())
+            return create(ScreenCaptureKitCaptureSource::create(device, constraints), device, WTFMove(hashSalt), constraints);
+#endif
+        break;
     case CaptureDevice::DeviceType::Microphone:
     case CaptureDevice::DeviceType::Speaker:
     case CaptureDevice::DeviceType::Camera:
@@ -94,9 +108,8 @@
     : RealtimeMediaSource(Type::Video, WTFMove(name), WTFMove(deviceID), WTFMove(hashSalt))
     , m_capturer(WTFMove(capturer))
     , m_timer(RunLoop::current(), this, &DisplayCaptureSourceCocoa::emitFrame)
-    , m_capturerIsRunningObserver([weakThis = WeakPtr { *this }] (bool isRunning) { if (weakThis) weakThis->notifyMutedChange(!isRunning); })
 {
-    m_capturer->setIsRunningObserver(&m_capturerIsRunningObserver);
+    m_capturer->setObserver(this);
 }
 
 DisplayCaptureSourceCocoa::~DisplayCaptureSourceCocoa()
@@ -303,10 +316,9 @@
     return LogWebRTC;
 }
 
-void DisplayCaptureSourceCocoa::Capturer::capturerIsRunningChanged(bool running)
+void DisplayCaptureSourceCocoa::Capturer::setObserver(CapturerObserver* observer)
 {
-    if (m_observer)
-        (*m_observer)(running);
+    m_observer = WeakPtr { observer };
 }
 
 } // namespace WebCore
diff --git a/Source/WebCore/platform/mediastream/cocoa/DisplayCaptureSourceCocoa.h b/Source/WebCore/platform/mediastream/cocoa/DisplayCaptureSourceCocoa.h
index b1d0aab..8f4ebea 100644
--- a/Source/WebCore/platform/mediastream/cocoa/DisplayCaptureSourceCocoa.h
+++ b/Source/WebCore/platform/mediastream/cocoa/DisplayCaptureSourceCocoa.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017-2021 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2022 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -51,13 +51,24 @@
 class ImageTransferSessionVT;
 class PixelBufferConformerCV;
 
-class DisplayCaptureSourceCocoa final : public RealtimeMediaSource, public CanMakeWeakPtr<DisplayCaptureSourceCocoa> {
+class CapturerObserver : public CanMakeWeakPtr<CapturerObserver> {
+public:
+    virtual ~CapturerObserver() = default;
+
+    virtual void capturerIsRunningChanged(bool) { }
+    virtual void capturerFailed() { };
+};
+
+class DisplayCaptureSourceCocoa final
+    : public RealtimeMediaSource
+    , public CapturerObserver {
 public:
     using DisplayFrameType = std::variant<RefPtr<NativeImage>, RetainPtr<IOSurfaceRef>, RetainPtr<CMSampleBufferRef>>;
 
     class Capturer : public LoggerHelper {
         WTF_MAKE_FAST_ALLOCATED;
     public:
+
         virtual ~Capturer() = default;
 
         virtual bool start() = 0;
@@ -74,15 +85,23 @@
         const void* logIdentifier() const final { return m_logIdentifier; }
         WTFLogChannel& logChannel() const final;
 
-        using IsRunningObserver = WTF::Observer<void(bool)>;
-        void setIsRunningObserver(IsRunningObserver* observer) { m_observer = observer; };
+        void setObserver(CapturerObserver*);
 
     protected:
         Capturer() = default;
-        void capturerIsRunningChanged(bool);
+        void isRunningChanged(bool running)
+        {
+            if (m_observer)
+                m_observer->capturerIsRunningChanged(running);
+        }
+        void captureFailed()
+        {
+            if (m_observer)
+                m_observer->capturerFailed();
+        }
 
     private:
-        WeakPtr<IsRunningObserver> m_observer;
+        WeakPtr<CapturerObserver> m_observer;
         RefPtr<const Logger> m_logger;
         const void* m_logIdentifier;
     };
@@ -110,6 +129,10 @@
     const char* logClassName() const final { return "DisplayCaptureSourceCocoa"; }
     void setLogger(const Logger&, const void*) final;
 
+    // CapturerObserver
+    void capturerIsRunningChanged(bool isRunning) final { notifyMutedChange(!isRunning); }
+    void capturerFailed() final { captureFailed(); }
+
     void emitFrame();
 
     UniqueRef<Capturer> m_capturer;
@@ -123,7 +146,6 @@
     RunLoop::Timer<DisplayCaptureSourceCocoa> m_timer;
 
     std::unique_ptr<ImageTransferSessionVT> m_imageTransferSession;
-    WTF::Observer<void(bool)> m_capturerIsRunningObserver;
 };
 
 } // namespace WebCore
diff --git a/Source/WebCore/platform/mediastream/gstreamer/GStreamerCaptureDeviceManager.h b/Source/WebCore/platform/mediastream/gstreamer/GStreamerCaptureDeviceManager.h
index e500122..9ee48bb 100644
--- a/Source/WebCore/platform/mediastream/gstreamer/GStreamerCaptureDeviceManager.h
+++ b/Source/WebCore/platform/mediastream/gstreamer/GStreamerCaptureDeviceManager.h
@@ -23,7 +23,7 @@
 
 #if ENABLE(MEDIA_STREAM) && USE(GSTREAMER)
 
-#include "CaptureDeviceManager.h"
+#include "DisplayCaptureManager.h"
 #include "GRefPtrGStreamer.h"
 #include "GStreamerCaptureDevice.h"
 #include "RealtimeMediaSourceFactory.h"
@@ -66,7 +66,7 @@
     GStreamerVideoCaptureDeviceManager() = default;
 };
 
-class GStreamerDisplayCaptureDeviceManager final : public CaptureDeviceManager {
+class GStreamerDisplayCaptureDeviceManager final : public DisplayCaptureManager {
     friend class NeverDestroyed<GStreamerDisplayCaptureDeviceManager>;
 public:
     static GStreamerDisplayCaptureDeviceManager& singleton();
diff --git a/Source/WebCore/platform/mediastream/gstreamer/GStreamerVideoCaptureSource.cpp b/Source/WebCore/platform/mediastream/gstreamer/GStreamerVideoCaptureSource.cpp
index 3034115..e13d53b 100644
--- a/Source/WebCore/platform/mediastream/gstreamer/GStreamerVideoCaptureSource.cpp
+++ b/Source/WebCore/platform/mediastream/gstreamer/GStreamerVideoCaptureSource.cpp
@@ -25,6 +25,7 @@
 #if ENABLE(MEDIA_STREAM) && USE(GSTREAMER)
 #include "GStreamerVideoCaptureSource.h"
 
+#include "DisplayCaptureManager.h"
 #include "GStreamerCaptureDeviceManager.h"
 #include "MediaSampleGStreamer.h"
 
@@ -77,7 +78,7 @@
         return manager.createDisplayCaptureSource(device, WTFMove(hashSalt), constraints);
     }
 private:
-    CaptureDeviceManager& displayCaptureDeviceManager() final { return GStreamerDisplayCaptureDeviceManager::singleton(); }
+    DisplayCaptureManager& displayCaptureDeviceManager() final { return GStreamerDisplayCaptureDeviceManager::singleton(); }
 };
 
 CaptureSourceOrError GStreamerVideoCaptureSource::create(String&& deviceID, String&& hashSalt, const MediaConstraints* constraints)
diff --git a/Source/WebCore/platform/mediastream/ios/ReplayKitCaptureSource.mm b/Source/WebCore/platform/mediastream/ios/ReplayKitCaptureSource.mm
index 55f635b..8024586 100644
--- a/Source/WebCore/platform/mediastream/ios/ReplayKitCaptureSource.mm
+++ b/Source/WebCore/platform/mediastream/ios/ReplayKitCaptureSource.mm
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 Apple Inc. All rights reserved.
+ * Copyright (C) 2021-2022 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -189,7 +189,7 @@
 
         m_isRunning = isRecording && !m_interrupted;
         ALWAYS_LOG_IF(loggerPtr(), identifier, m_isRunning);
-        capturerIsRunningChanged(m_isRunning);
+        isRunningChanged(m_isRunning);
     });
 }
 
diff --git a/Source/WebCore/platform/mediastream/mac/DisplayCaptureManagerCocoa.cpp b/Source/WebCore/platform/mediastream/mac/DisplayCaptureManagerCocoa.cpp
index 197c66f..2adc937 100644
--- a/Source/WebCore/platform/mediastream/mac/DisplayCaptureManagerCocoa.cpp
+++ b/Source/WebCore/platform/mediastream/mac/DisplayCaptureManagerCocoa.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017-2021 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2022 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -25,6 +25,7 @@
 
 #include "config.h"
 #include "DisplayCaptureManagerCocoa.h"
+#include "RealtimeMediaSourceCenter.h"
 
 #if ENABLE(MEDIA_STREAM)
 
@@ -40,6 +41,10 @@
 #include "ReplayKitCaptureSource.h"
 #endif
 
+#if HAVE(SCREEN_CAPTURE_KIT)
+#include "ScreenCaptureKitCaptureSource.h"
+#endif
+
 namespace WebCore {
 
 DisplayCaptureManagerCocoa& DisplayCaptureManagerCocoa::singleton()
@@ -61,7 +66,16 @@
 void DisplayCaptureManagerCocoa::updateDisplayCaptureDevices()
 {
 #if PLATFORM(MAC)
+
+#if HAVE(SCREEN_CAPTURE_KIT)
+    if (ScreenCaptureKitCaptureSource::isAvailable()) {
+        ScreenCaptureKitCaptureSource::screenCaptureDevices(m_devices);
+        return;
+    }
+#endif
+
     CGDisplayStreamScreenCaptureSource::screenCaptureDevices(m_devices);
+
 #elif PLATFORM(IOS)
     ReplayKitCaptureSource::screenCaptureDevices(m_devices);
 #endif
@@ -69,12 +83,23 @@
 
 void DisplayCaptureManagerCocoa::updateWindowCaptureDevices()
 {
+#if HAVE(SCREEN_CAPTURE_KIT)
+    if (ScreenCaptureKitCaptureSource::isAvailable())
+        ScreenCaptureKitCaptureSource::windowCaptureDevices(m_devices);
+#endif
 }
 
 std::optional<CaptureDevice> DisplayCaptureManagerCocoa::screenCaptureDeviceWithPersistentID(const String& deviceID)
 {
 #if PLATFORM(MAC)
+
+#if HAVE(SCREEN_CAPTURE_KIT)
+    if (ScreenCaptureKitCaptureSource::isAvailable())
+        return ScreenCaptureKitCaptureSource::screenCaptureDeviceWithPersistentID(deviceID);
+#endif
+
     return CGDisplayStreamScreenCaptureSource::screenCaptureDeviceWithPersistentID(deviceID);
+
 #else
     UNUSED_PARAM(deviceID);
     return std::nullopt;
@@ -84,6 +109,12 @@
 std::optional<CaptureDevice> DisplayCaptureManagerCocoa::windowCaptureDeviceWithPersistentID(const String& deviceID)
 {
     UNUSED_PARAM(deviceID);
+
+#if HAVE(SCREEN_CAPTURE_KIT)
+    if (ScreenCaptureKitCaptureSource::isAvailable())
+        return ScreenCaptureKitCaptureSource::windowCaptureDeviceWithPersistentID(deviceID);
+#endif
+
     return std::nullopt;
 }
 
@@ -109,6 +140,16 @@
     return std::nullopt;
 }
 
+void DisplayCaptureManagerCocoa::windowDevices(Vector<DisplayCaptureManager::WindowCaptureDevice>& windowDevices)
+{
+#if HAVE(SCREEN_CAPTURE_KIT)
+    if (ScreenCaptureKitCaptureSource::isAvailable())
+        return ScreenCaptureKitCaptureSource::windowDevices(windowDevices);
+#else
+    UNUSED_PARAM(windowDevices);
+#endif
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(MEDIA_STREAM)
diff --git a/Source/WebCore/platform/mediastream/mac/DisplayCaptureManagerCocoa.h b/Source/WebCore/platform/mediastream/mac/DisplayCaptureManagerCocoa.h
index 28fff40..336a993 100644
--- a/Source/WebCore/platform/mediastream/mac/DisplayCaptureManagerCocoa.h
+++ b/Source/WebCore/platform/mediastream/mac/DisplayCaptureManagerCocoa.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2017-2022 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,11 +27,11 @@
 
 #if ENABLE(MEDIA_STREAM)
 
-#include "CaptureDeviceManager.h"
+#include "DisplayCaptureManager.h"
 
 namespace WebCore {
 
-class DisplayCaptureManagerCocoa final : public CaptureDeviceManager {
+class DisplayCaptureManagerCocoa final : public DisplayCaptureManager {
 public:
     static DisplayCaptureManagerCocoa& singleton();
 
@@ -49,6 +49,8 @@
     std::optional<CaptureDevice> screenCaptureDeviceWithPersistentID(const String&);
     std::optional<CaptureDevice> windowCaptureDeviceWithPersistentID(const String&);
 
+    void windowDevices(Vector<WindowCaptureDevice>&) final;
+
     Vector<CaptureDevice> m_devices;
 };
 
diff --git a/Source/WebCore/platform/mediastream/mac/RealtimeMediaSourceCenterMac.cpp b/Source/WebCore/platform/mediastream/mac/RealtimeMediaSourceCenterMac.cpp
index e555bb8..f367da1 100644
--- a/Source/WebCore/platform/mediastream/mac/RealtimeMediaSourceCenterMac.cpp
+++ b/Source/WebCore/platform/mediastream/mac/RealtimeMediaSourceCenterMac.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2021 Apple, Inc. All rights reserved.
+ * Copyright (C) 2013-2022 Apple, Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -62,7 +62,7 @@
         return DisplayCaptureSourceCocoa::create(device, WTFMove(hashSalt), constraints);
     }
 private:
-    CaptureDeviceManager& displayCaptureDeviceManager() { return DisplayCaptureManagerCocoa::singleton(); }
+    DisplayCaptureManager& displayCaptureDeviceManager() { return DisplayCaptureManagerCocoa::singleton(); }
 };
 
 AudioCaptureFactory& RealtimeMediaSourceCenter::defaultAudioCaptureFactory()
diff --git a/Source/WebCore/platform/mediastream/mac/ScreenCaptureKitCaptureSource.h b/Source/WebCore/platform/mediastream/mac/ScreenCaptureKitCaptureSource.h
new file mode 100644
index 0000000..c15b5de
--- /dev/null
+++ b/Source/WebCore/platform/mediastream/mac/ScreenCaptureKitCaptureSource.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2021-2022 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. ``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
+ * 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 HAVE(SCREEN_CAPTURE_KIT)
+
+#include "DisplayCaptureManager.h"
+#include "DisplayCaptureSourceCocoa.h"
+#include <wtf/BlockPtr.h>
+#include <wtf/Forward.h>
+#include <wtf/RetainPtr.h>
+
+OBJC_CLASS NSDictionary;
+OBJC_CLASS NSError;
+OBJC_CLASS SCDisplay;
+OBJC_CLASS SCShareableContent;
+OBJC_CLASS SCStream;
+OBJC_CLASS SCContentFilter;
+OBJC_CLASS SCStreamConfiguration;
+OBJC_CLASS SCWindow;
+OBJC_CLASS WebCoreScreenCaptureKitHelper;
+using CMSampleBufferRef = struct opaqueCMSampleBuffer*;
+
+typedef struct __IOSurface* IOSurfaceRef;
+
+namespace WebCore {
+
+class ScreenCaptureKitCaptureSource final
+    : public DisplayCaptureSourceCocoa::Capturer
+    , public CanMakeWeakPtr<ScreenCaptureKitCaptureSource> {
+public:
+    static Expected<UniqueRef<DisplayCaptureSourceCocoa::Capturer>, String> create(const CaptureDevice&, const MediaConstraints*);
+
+    explicit ScreenCaptureKitCaptureSource(const CaptureDevice&, uint32_t);
+    virtual ~ScreenCaptureKitCaptureSource();
+
+    WEBCORE_EXPORT static bool isAvailable();
+    WEBCORE_EXPORT static void setEnabled(bool);
+
+    static std::optional<CaptureDevice> screenCaptureDeviceWithPersistentID(const String&);
+    WEBCORE_EXPORT static void screenCaptureDevices(Vector<CaptureDevice>&);
+
+    static void windowCaptureDevices(Vector<CaptureDevice>&);
+    static std::optional<CaptureDevice> windowCaptureDeviceWithPersistentID(const String&);
+    WEBCORE_EXPORT static void windowDevices(Vector<DisplayCaptureManager::WindowCaptureDevice>&);
+
+    void streamFailedWithError(RetainPtr<NSError>&&, const String&);
+
+private:
+
+    // DisplayCaptureSourceCocoa::Capturer
+    bool start() final;
+    void stop() final;
+    DisplayCaptureSourceCocoa::DisplayFrameType generateFrame() final;
+    CaptureDevice::DeviceType deviceType() const final;
+    RealtimeMediaSourceSettings::DisplaySurfaceType surfaceType() const final;
+    void commitConfiguration(const RealtimeMediaSourceSettings&) final;
+    IntSize intrinsicSize() const final;
+
+    // LoggerHelper
+    const char* logClassName() const final { return "ScreenCaptureKitCaptureSource"; }
+
+    void startContentStream();
+    void processSharableContent(RetainPtr<SCShareableContent>&&, RetainPtr<NSError>&&);
+    void findShareableContent();
+    RetainPtr<SCStreamConfiguration> streamConfiguration();
+    void updateStreamConfiguration();
+
+    using SCContentStreamUpdateCallback = void (^)(SCStream *, CMSampleBufferRef);
+    SCContentStreamUpdateCallback frameAvailableHandler();
+
+    using Content = std::variant<RetainPtr<SCWindow>, RetainPtr<SCDisplay>>;
+    std::optional<Content> m_content;
+
+    RetainPtr<WebCoreScreenCaptureKitHelper> m_captureHelper;
+    RetainPtr<CMSampleBufferRef> m_currentFrame;
+    RetainPtr<SCContentFilter> m_contentFilter;
+    RetainPtr<SCStream> m_contentStream;
+    RetainPtr<SCStreamConfiguration> m_streamConfiguration;
+    OSObjectPtr<dispatch_queue_t> m_captureQueue;
+    BlockPtr<void(SCStream *, CMSampleBufferRef)> m_frameAvailableHandler;
+    CaptureDevice m_captureDevice;
+    uint32_t m_deviceID { 0 };
+    std::optional<IntSize> m_intrinsicSize;
+
+    uint32_t m_width { 0 };
+    uint32_t m_height { 0 };
+    float m_frameRate { 0 };
+    bool m_isRunning { false };
+    static bool m_enabled;
+};
+
+} // namespace WebCore
+
+#endif // HAVE(SCREEN_CAPTURE_KIT)
diff --git a/Source/WebCore/platform/mediastream/mac/ScreenCaptureKitCaptureSource.mm b/Source/WebCore/platform/mediastream/mac/ScreenCaptureKitCaptureSource.mm
new file mode 100644
index 0000000..5530851
--- /dev/null
+++ b/Source/WebCore/platform/mediastream/mac/ScreenCaptureKitCaptureSource.mm
@@ -0,0 +1,553 @@
+/*
+ * Copyright (C) 2021-2022 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. ``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
+ * 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.
+ */
+
+#include "config.h"
+#include "ScreenCaptureKitCaptureSource.h"
+
+#if HAVE(SCREEN_CAPTURE_KIT)
+
+#import "DisplayCaptureManager.h"
+#import "Logging.h"
+#import "PlatformMediaSessionManager.h"
+#import "PlatformScreen.h"
+#import "RealtimeMediaSourceCenter.h"
+#import "RealtimeVideoUtilities.h"
+#import <ScreenCaptureKit/ScreenCaptureKit.h>
+#import <wtf/BlockObjCExceptions.h>
+#import <wtf/BlockPtr.h>
+#import <wtf/NeverDestroyed.h>
+#import <wtf/UUID.h>
+#import <wtf/text/StringToIntegerConversion.h>
+
+#import <pal/mac/ScreenCaptureKitSoftLink.h>
+
+typedef NS_ENUM(NSInteger, WKSCFrameStatus) {
+    WKSCFrameStatusFrameComplete,
+    WKSCFrameStatusFrameIdle,
+    WKSCFrameStatusFrameBlank,
+    WKSCFrameStatusFrameSuspended,
+    WKSCFrameStatusFrameStarted,
+    WKSCFrameStatusFrameStopped
+};
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunguarded-availability-new"
+
+@interface SCStream (SCStream_Deprecated)
+- (void)startCaptureWithCFrameHandler:(SCStreamBufferFrameAvailableHandler)frameHandler completionHandler:(void (^)(NSError *error))completionHandler;
+@end
+
+using namespace WebCore;
+@interface WebCoreScreenCaptureKitHelper : NSObject<SCStreamDelegate> {
+    WeakPtr<ScreenCaptureKitCaptureSource> _callback;
+}
+
+- (instancetype)initWithCallback:(WeakPtr<ScreenCaptureKitCaptureSource>&&)callback;
+- (void)disconnect;
+- (void)stream:(SCStream *)stream didStopWithError:(NSError *)error;
+@end
+
+@implementation WebCoreScreenCaptureKitHelper
+- (instancetype)initWithCallback:(WeakPtr<ScreenCaptureKitCaptureSource>&&)callback
+{
+    self = [super init];
+    if (!self)
+        return self;
+
+    return self;
+}
+
+- (void)disconnect
+{
+    _callback = nullptr;
+}
+
+- (void)stream:(SCStream *)stream didStopWithError:(NSError *)error
+{
+    callOnMainRunLoop([strongSelf = RetainPtr { self }, error = RetainPtr { error }]() mutable {
+        if (!strongSelf->_callback)
+            return;
+
+        strongSelf->_callback->streamFailedWithError(WTFMove(error), "-[SCStreamDelegate stream:didStopWithError:] called"_s);
+    });
+}
+@end
+
+#pragma clang diagnostic pop
+
+namespace WebCore {
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunguarded-availability-new"
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+static void forEachNSWindow(const Function<bool(NSDictionary *, unsigned, const String&)>&);
+
+bool ScreenCaptureKitCaptureSource::m_enabled;
+
+void ScreenCaptureKitCaptureSource::setEnabled(bool enabled)
+{
+    m_enabled = enabled;
+}
+
+bool ScreenCaptureKitCaptureSource::isAvailable()
+{
+    return m_enabled && PAL::isScreenCaptureKitFrameworkAvailable();
+}
+
+Expected<UniqueRef<DisplayCaptureSourceCocoa::Capturer>, String> ScreenCaptureKitCaptureSource::create(const CaptureDevice& device, const MediaConstraints*)
+{
+    ASSERT(device.type() == CaptureDevice::DeviceType::Screen || device.type() == CaptureDevice::DeviceType::Window);
+
+    auto deviceID = parseInteger<uint32_t>(device.persistentId());
+    if (!deviceID)
+        return makeUnexpected("Invalid display device ID"_s);
+
+    return UniqueRef<DisplayCaptureSourceCocoa::Capturer>(makeUniqueRef<ScreenCaptureKitCaptureSource>(device, deviceID.value()));
+}
+
+ScreenCaptureKitCaptureSource::ScreenCaptureKitCaptureSource(const CaptureDevice& device, uint32_t deviceID)
+    : DisplayCaptureSourceCocoa::Capturer()
+    , m_captureDevice(device)
+    , m_deviceID(deviceID)
+{
+}
+
+ScreenCaptureKitCaptureSource::~ScreenCaptureKitCaptureSource()
+{
+}
+
+bool ScreenCaptureKitCaptureSource::start()
+{
+    ASSERT(isAvailable());
+
+    ALWAYS_LOG_IF(loggerPtr(), LOGIDENTIFIER);
+
+    if (m_isRunning)
+        return true;
+
+    m_isRunning = true;
+    startContentStream();
+
+    return m_isRunning;
+}
+
+void ScreenCaptureKitCaptureSource::stop()
+{
+    if (!m_isRunning)
+        return;
+
+    ALWAYS_LOG_IF(loggerPtr(), LOGIDENTIFIER);
+
+    m_isRunning = false;
+
+    if (m_contentStream) {
+        [m_contentStream stopWithCompletionHandler:makeBlockPtr([weakThis = WeakPtr { *this }] (NSError *error) mutable {
+            if (!error)
+                return;
+
+            callOnMainRunLoop([weakThis = WTFMove(weakThis), error = RetainPtr { error }]() mutable {
+                if (weakThis)
+                    weakThis->streamFailedWithError(WTFMove(error), "-[SCStream stopWithCompletionHandler:] failed"_s);
+            });
+        }).get()];
+    }
+}
+
+void ScreenCaptureKitCaptureSource::streamFailedWithError(RetainPtr<NSError>&& error, const String& message)
+{
+    ASSERT(isMainThread());
+
+    ERROR_LOG_IF(loggerPtr() && error, LOGIDENTIFIER, message, " with error '", [[error localizedDescription] UTF8String], "'");
+    ERROR_LOG_IF(loggerPtr() && !error, LOGIDENTIFIER, message);
+
+    captureFailed();
+}
+
+DisplayCaptureSourceCocoa::DisplayFrameType ScreenCaptureKitCaptureSource::generateFrame()
+{
+    return m_currentFrame;
+}
+
+void ScreenCaptureKitCaptureSource::processSharableContent(RetainPtr<SCShareableContent>&& shareableContent, RetainPtr<NSError>&& error)
+{
+    ASSERT(isMainRunLoop());
+
+    if (error) {
+        streamFailedWithError(WTFMove(error), "-[SCStream getShareableContentWithCompletionHandler:] failed"_s);
+        return;
+    }
+
+    if (m_captureDevice.type() == CaptureDevice::DeviceType::Screen) {
+        [[shareableContent displays] enumerateObjectsUsingBlock:makeBlockPtr([&] (SCDisplay *display, NSUInteger, BOOL *stop) {
+            if (display.displayID == m_deviceID) {
+                m_content = display;
+                *stop = YES;
+            }
+        }).get()];
+    } else if (m_captureDevice.type() == CaptureDevice::DeviceType::Window) {
+        [[shareableContent windows] enumerateObjectsUsingBlock:makeBlockPtr([&] (SCWindow *window, NSUInteger, BOOL *stop) {
+            if (window.windowID == m_deviceID) {
+                m_content = window;
+                *stop = YES;
+            }
+        }).get()];
+    } else {
+        ASSERT_NOT_REACHED();
+        return;
+    }
+
+    if (!m_content) {
+        streamFailedWithError(nil, "capture device not found"_s);
+        return;
+    }
+
+    startContentStream();
+}
+
+void ScreenCaptureKitCaptureSource::findShareableContent()
+{
+    ASSERT(!m_content);
+
+    [PAL::getSCShareableContentClass() getShareableContentWithCompletionHandler:makeBlockPtr([weakThis = WeakPtr { *this }] (SCShareableContent *shareableContent, NSError *error) mutable {
+        callOnMainRunLoop([weakThis = WTFMove(weakThis), shareableContent = RetainPtr { shareableContent }, error = RetainPtr { error }]() mutable {
+            if (weakThis)
+                weakThis->processSharableContent(WTFMove(shareableContent), WTFMove(error));
+        });
+    }).get()];
+}
+
+RetainPtr<SCStreamConfiguration> ScreenCaptureKitCaptureSource::streamConfiguration()
+{
+    if (m_streamConfiguration)
+        return m_streamConfiguration;
+
+    m_streamConfiguration = adoptNS([PAL::allocSCStreamConfigurationInstance() init]);
+    [m_streamConfiguration setPixelFormat:preferedPixelBufferFormat()];
+    [m_streamConfiguration setShowsCursor:YES];
+    [m_streamConfiguration setQueueDepth:6];
+    [m_streamConfiguration setColorSpaceName:kCGColorSpaceLinearSRGB];
+    [m_streamConfiguration setColorMatrix:kCGDisplayStreamYCbCrMatrix_SMPTE_240M_1995];
+
+    if (m_frameRate)
+        [m_streamConfiguration setMinimumFrameTime:1 / m_frameRate];
+
+    if (m_width && m_height) {
+        [m_streamConfiguration setWidth:m_width];
+        [m_streamConfiguration setHeight:m_height];
+    }
+
+    return m_streamConfiguration;
+}
+
+void ScreenCaptureKitCaptureSource::startContentStream()
+{
+    if (m_contentStream)
+        return;
+
+    if (!m_content) {
+        findShareableContent();
+        return;
+    }
+
+    m_contentFilter = switchOn(m_content.value(),
+        [] (const RetainPtr<SCDisplay> display) -> RetainPtr<SCContentFilter> {
+            return adoptNS([PAL::allocSCContentFilterInstance() initWithDisplay:display.get() excludingWindows:nil]);
+        },
+        [] (const RetainPtr<SCWindow> window)  -> RetainPtr<SCContentFilter> {
+            return adoptNS([PAL::allocSCContentFilterInstance() initWithDesktopIndependentWindow:window.get()]);
+        }
+    );
+
+    if (!m_contentFilter) {
+        streamFailedWithError(nil, "Failed to allocate SCContentFilter"_s);
+        return;
+    }
+
+    if (!m_captureHelper)
+        m_captureHelper = ([[WebCoreScreenCaptureKitHelper alloc] initWithCallback:this]);
+
+    m_contentStream = adoptNS([PAL::allocSCStreamInstance() initWithFilter:m_contentFilter.get() captureOutputProperties:streamConfiguration().get() delegate:m_captureHelper.get()]);
+    if (!m_contentStream) {
+        streamFailedWithError(nil, "Failed to allocate SLContentStream"_s);
+        return;
+    }
+
+    auto completionHandler = makeBlockPtr([weakThis = WeakPtr { *this }] (NSError *error) mutable {
+        if (!error)
+            return;
+
+        callOnMainRunLoop([weakThis = WTFMove(weakThis), error = RetainPtr { error }]() mutable {
+            if (weakThis)
+                weakThis->streamFailedWithError(WTFMove(error), "-[SCStream startCaptureWithFrameHandler:completionHandler:] failed"_s);
+        });
+    });
+
+    [m_contentStream startCaptureWithFrameHandler:frameAvailableHandler() completionHandler:completionHandler.get()];
+
+    m_isRunning = true;
+}
+
+IntSize ScreenCaptureKitCaptureSource::intrinsicSize() const
+{
+    if (m_intrinsicSize)
+        return m_intrinsicSize.value();
+
+    if (m_captureDevice.type() == CaptureDevice::DeviceType::Screen) {
+        auto displayMode = adoptCF(CGDisplayCopyDisplayMode(m_deviceID));
+        auto screenWidth = CGDisplayModeGetPixelsWide(displayMode.get());
+        auto screenHeight = CGDisplayModeGetPixelsHigh(displayMode.get());
+
+        return { Checked<int>(screenWidth), Checked<int>(screenHeight) };
+    }
+
+    CGRect bounds = CGRectZero;
+    forEachNSWindow([&] (NSDictionary *windowInfo, unsigned windowID, const String&) mutable {
+        if (windowID != m_deviceID)
+            return false;
+
+        NSDictionary *boundsDict = windowInfo[(__bridge NSString *)kCGWindowBounds];
+        if (![boundsDict isKindOfClass:NSDictionary.class])
+            return false;
+
+        CGRectMakeWithDictionaryRepresentation((CFDictionaryRef)boundsDict, &bounds);
+        return true;
+    });
+
+    return { static_cast<int>(bounds.size.width), static_cast<int>(bounds.size.height) };
+}
+
+void ScreenCaptureKitCaptureSource::updateStreamConfiguration()
+{
+    ASSERT(m_contentStream);
+
+    [m_contentStream updateStreamConfiguration:streamConfiguration().get() completionHandler:makeBlockPtr([weakThis = WeakPtr { *this }] (NSError *error) mutable {
+        if (!error)
+            return;
+
+        callOnMainRunLoop([weakThis = WTFMove(weakThis), error = RetainPtr { error }]() mutable {
+            if (weakThis)
+                weakThis->streamFailedWithError(WTFMove(error), "-[SCStream updateStreamConfiguration:] failed"_s);
+        });
+    }).get()];
+
+}
+
+void ScreenCaptureKitCaptureSource::commitConfiguration(const RealtimeMediaSourceSettings& settings)
+{
+    if (m_width == settings.width() && m_height == settings.height() && m_frameRate == settings.frameRate())
+        return;
+
+    m_width = settings.width();
+    m_height = settings.height();
+    m_frameRate = settings.frameRate();
+
+    if (m_contentStream) {
+        m_streamConfiguration = nullptr;
+        updateStreamConfiguration();
+    }
+}
+
+ScreenCaptureKitCaptureSource::SCContentStreamUpdateCallback ScreenCaptureKitCaptureSource::frameAvailableHandler()
+{
+    if (m_frameAvailableHandler)
+        return m_frameAvailableHandler.get();
+
+    m_frameAvailableHandler = makeBlockPtr([weakThis = WeakPtr { *this }] (SCStream *, CMSampleBufferRef sampleBuffer) mutable {
+        if (!weakThis)
+            return;
+
+        if (!sampleBuffer) {
+            RunLoop::main().dispatch([weakThis = WTFMove(weakThis), sampleBuffer = retainPtr(sampleBuffer)]() mutable {
+                if (weakThis)
+                    RELEASE_LOG_ERROR(WebRTC, "ScreenCaptureKitCaptureSource::frameAvailableHandler: NULL sample buffer!");
+            });
+            return;
+        }
+
+        auto attachments = (__bridge NSArray *)PAL::CMSampleBufferGetSampleAttachmentsArray(sampleBuffer, false);
+        WKSCFrameStatus status = WKSCFrameStatusFrameStopped;
+        [attachments enumerateObjectsUsingBlock:makeBlockPtr([&] (NSDictionary *attachment, NSUInteger, BOOL *stop) {
+            auto statusNumber = (NSNumber *)attachment[PAL::SCStreamFrameInfoStatusKey];
+            if (!statusNumber)
+                return;
+
+            status = (WKSCFrameStatus)[statusNumber integerValue];
+            *stop = YES;
+        }).get()];
+
+        switch (status) {
+        case WKSCFrameStatusFrameStarted:
+        case WKSCFrameStatusFrameComplete:
+            break;
+        case WKSCFrameStatusFrameIdle:
+        case WKSCFrameStatusFrameBlank:
+        case WKSCFrameStatusFrameSuspended:
+        case WKSCFrameStatusFrameStopped:
+            return;
+        }
+
+        RunLoop::main().dispatch([weakThis = WTFMove(weakThis), sampleBuffer = retainPtr(sampleBuffer)]() mutable {
+            if (!weakThis)
+                return;
+
+            weakThis->m_intrinsicSize = IntSize(PAL::CMVideoFormatDescriptionGetPresentationDimensions(PAL::CMSampleBufferGetFormatDescription(sampleBuffer.get()), true, true));
+            weakThis->m_currentFrame = WTFMove(sampleBuffer);
+        });
+    });
+
+    return m_frameAvailableHandler.get();
+}
+
+CaptureDevice::DeviceType ScreenCaptureKitCaptureSource::deviceType() const
+{
+    return m_captureDevice.type();
+}
+
+RealtimeMediaSourceSettings::DisplaySurfaceType ScreenCaptureKitCaptureSource::surfaceType() const
+{
+    return m_captureDevice.type() == CaptureDevice::DeviceType::Screen ? RealtimeMediaSourceSettings::DisplaySurfaceType::Monitor : RealtimeMediaSourceSettings::DisplaySurfaceType::Window;
+}
+
+std::optional<CaptureDevice> ScreenCaptureKitCaptureSource::screenCaptureDeviceWithPersistentID(const String& displayIDString)
+{
+    if (!isAvailable()) {
+        RELEASE_LOG_ERROR(WebRTC, "ScreenCaptureKitCaptureSource::screenCaptureDeviceWithPersistentID: screen capture unavailable");
+        return std::nullopt;
+    }
+
+    auto displayID = parseInteger<uint32_t>(displayIDString);
+    if (!displayID) {
+        RELEASE_LOG_ERROR(WebRTC, "ScreenCaptureKitCaptureSource::screenCaptureDeviceWithPersistentID: invalid display ID");
+        return std::nullopt;
+    }
+
+    return CaptureDevice(String::number(displayID.value()), CaptureDevice::DeviceType::Screen, "ScreenCaptureDevice"_s, emptyString(), true);
+}
+
+void ScreenCaptureKitCaptureSource::screenCaptureDevices(Vector<CaptureDevice>& displays)
+{
+    if (!isAvailable())
+        return;
+
+    uint32_t displayCount = 0;
+    auto err = CGGetActiveDisplayList(0, nullptr, &displayCount);
+    if (err) {
+        RELEASE_LOG_ERROR(WebRTC, "ScreenCaptureKitCaptureSource::screenCaptureDevices - CGGetActiveDisplayList() returned error %d when trying to get display count", (int)err);
+        return;
+    }
+
+    if (!displayCount) {
+        RELEASE_LOG_ERROR(WebRTC, "CGGetActiveDisplayList() returned a display count of 0");
+        return;
+    }
+
+    Vector<CGDirectDisplayID> activeDisplays(displayCount);
+    err = CGGetActiveDisplayList(displayCount, activeDisplays.data(), &displayCount);
+    if (err) {
+        RELEASE_LOG_ERROR(WebRTC, "ScreenCaptureKitCaptureSource::screenCaptureDevices - CGGetActiveDisplayList() returned error %d when trying to get the active display list", (int)err);
+        return;
+    }
+
+    int count = 0;
+    for (auto displayID : activeDisplays) {
+        CaptureDevice displayDevice(String::number(displayID), CaptureDevice::DeviceType::Screen, makeString("Screen ", String::number(count++)));
+        displayDevice.setEnabled(CGDisplayIDToOpenGLDisplayMask(displayID));
+        displays.append(WTFMove(displayDevice));
+    }
+}
+
+std::optional<CaptureDevice> ScreenCaptureKitCaptureSource::windowCaptureDeviceWithPersistentID(const String& windowIDString)
+{
+    auto windowID = parseInteger<uint32_t>(windowIDString);
+    if (!windowID) {
+        RELEASE_LOG_ERROR(WebRTC, "ScreenCaptureKitCaptureSource::windowCaptureDeviceWithPersistentID: invalid window ID");
+        return std::nullopt;
+    }
+
+    std::optional<CaptureDevice> device;
+    forEachNSWindow([&] (NSDictionary *, unsigned id, const String& windowTitle) mutable {
+        if (id != windowID.value())
+            return false;
+
+        device = CaptureDevice(String::number(windowID.value()), CaptureDevice::DeviceType::Window, windowTitle, emptyString(), true);
+        return true;
+    });
+
+    return device;
+}
+
+void ScreenCaptureKitCaptureSource::windowCaptureDevices(Vector<CaptureDevice>& windows)
+{
+    if (!isAvailable())
+        return;
+
+    forEachNSWindow([&] (NSDictionary *, unsigned windowID, const String& windowTitle) mutable {
+        windows.append({ String::number(windowID), CaptureDevice::DeviceType::Window, windowTitle, emptyString(), true });
+        return false;
+    });
+}
+
+void ScreenCaptureKitCaptureSource::windowDevices(Vector<DisplayCaptureManager::WindowCaptureDevice>& devices)
+{
+    if (!isAvailable())
+        return;
+
+    forEachNSWindow([&] (NSDictionary *windowInfo, unsigned windowID, const String& windowTitle) mutable {
+        auto *applicationName = (__bridge NSString *)(windowInfo[(__bridge NSString *)kCGWindowOwnerName]);
+        devices.append({ { String::number(windowID), CaptureDevice::DeviceType::Window, windowTitle, emptyString(), true }, applicationName });
+        return false;
+    });
+}
+
+void forEachNSWindow(const Function<bool(NSDictionary *info, unsigned windowID, const String& title)>& predicate)
+{
+    RetainPtr<NSArray> windowList = adoptNS((__bridge NSArray *)CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, kCGNullWindowID));
+    if (!windowList)
+        return;
+
+    [windowList enumerateObjectsUsingBlock:makeBlockPtr([&] (NSDictionary *windowInfo, NSUInteger, BOOL *stop) {
+        *stop = NO;
+
+        // Menus, the dock, etc have layers greater than 0, skip them.
+        int windowLayer = [(NSNumber *)windowInfo[(__bridge NSString *)kCGWindowLayer] integerValue];
+        if (windowLayer)
+            return;
+
+        // Skip windows that aren't on screen
+        if (![(NSNumber *)windowInfo[(__bridge NSString *)kCGWindowIsOnscreen] integerValue])
+            return;
+
+        auto *windowTitle = (__bridge NSString *)(windowInfo[(__bridge NSString *)kCGWindowName]);
+        auto windowID = (CGWindowID)[(NSNumber *)windowInfo[(__bridge NSString *)kCGWindowNumber] integerValue];
+        if (predicate(windowInfo, windowID, windowTitle))
+            *stop = YES;
+    }).get()];
+}
+#pragma clang diagnostic pop
+
+} // namespace WebCore
+
+#endif // HAVE(SCREEN_CAPTURE_KIT)
diff --git a/Source/WebCore/platform/mock/MockMediaDevice.h b/Source/WebCore/platform/mock/MockMediaDevice.h
index cf5abeb..85ace7f 100644
--- a/Source/WebCore/platform/mock/MockMediaDevice.h
+++ b/Source/WebCore/platform/mock/MockMediaDevice.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 Apple Inc. All rights reserved.
+ * Copyright (C) 2018-2022 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -168,14 +168,14 @@
     CaptureDevice captureDevice() const
     {
         if (isMicrophone())
-            return CaptureDevice { persistentId, CaptureDevice::DeviceType::Microphone, label, persistentId };
+            return CaptureDevice { persistentId, CaptureDevice::DeviceType::Microphone, label, persistentId, true };
         if (isSpeaker())
-            return CaptureDevice { persistentId, CaptureDevice::DeviceType::Speaker, label, speakerProperties()->relatedMicrophoneId };
+            return CaptureDevice { persistentId, CaptureDevice::DeviceType::Speaker, label, speakerProperties()->relatedMicrophoneId, true };
         if (isCamera())
-            return CaptureDevice { persistentId, CaptureDevice::DeviceType::Camera, label, persistentId };
+            return CaptureDevice { persistentId, CaptureDevice::DeviceType::Camera, label, persistentId, true };
 
         ASSERT(isDisplay());
-        return CaptureDevice { persistentId, CaptureDevice::DeviceType::Screen, label, persistentId };
+        return CaptureDevice { persistentId, std::get<MockDisplayProperties>(properties).type, label, emptyString(), true };
     }
 
     CaptureDevice::DeviceType type() const
diff --git a/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp b/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp
index 7a08fc6..5c834e3 100644
--- a/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp
+++ b/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.cpp
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2013 Google Inc. All rights reserved.
- * Copyright (C) 2013-2021 Apple Inc.  All rights reserved.
+ * Copyright (C) 2013-2022 Apple Inc.  All rights reserved.
  * Copyright (C) 2013 Nokia Corporation and/or its subsidiary(-ies).
  *
  * Redistribution and use in source and binary forms, with or without
@@ -94,8 +94,8 @@
         MockMediaDevice { "SCREEN-1"_s, "Mock screen device 1"_s, MockDisplayProperties { CaptureDevice::DeviceType::Screen, Color::lightGray, { 1920, 1080 } } },
         MockMediaDevice { "SCREEN-2"_s, "Mock screen device 2"_s, MockDisplayProperties { CaptureDevice::DeviceType::Screen, Color::yellow, { 3840, 2160 } } },
 
-        MockMediaDevice { "WINDOW-2"_s, "Mock window 1"_s, MockDisplayProperties { CaptureDevice::DeviceType::Screen, SRGBA<uint8_t> { 255, 241, 181 }, { 640, 480 } } },
-        MockMediaDevice { "WINDOW-2"_s, "Mock window 2"_s, MockDisplayProperties { CaptureDevice::DeviceType::Screen, SRGBA<uint8_t> { 255, 208, 181 }, { 1280, 600 } } },
+        MockMediaDevice { "WINDOW-1"_s, "Mock window device 1"_s, MockDisplayProperties { CaptureDevice::DeviceType::Window, SRGBA<uint8_t> { 255, 241, 181 }, { 640, 480 } } },
+        MockMediaDevice { "WINDOW-2"_s, "Mock window device 2"_s, MockDisplayProperties { CaptureDevice::DeviceType::Window, SRGBA<uint8_t> { 255, 208, 181 }, { 1280, 600 } } },
     };
 }
 
@@ -203,8 +203,9 @@
 
         return { };
     }
+
 private:
-    CaptureDeviceManager& displayCaptureDeviceManager() final { return MockRealtimeMediaSourceCenter::singleton().displayCaptureDeviceManager(); }
+    DisplayCaptureManager& displayCaptureDeviceManager() final { return MockRealtimeMediaSourceCenter::singleton().displayCaptureDeviceManager(); }
 };
 
 class MockRealtimeAudioSourceFactory final : public AudioCaptureFactory {
@@ -436,7 +437,7 @@
         Vector<CaptureDevice> displayDevices;
         for (const auto& device : devices()) {
             if (device.isDisplay())
-                displayDevices.append(captureDeviceWithPersistentID(CaptureDevice::DeviceType::Screen, device.persistentId).value());
+                displayDevices.append(device.captureDevice());
         }
         return displayDevices;
     }();
@@ -461,6 +462,17 @@
     return factory.get();
 }
 
+void MockRealtimeMediaSourceCenter::MockDisplayCaptureDeviceManager::windowDevices(Vector<DisplayCaptureManager::WindowCaptureDevice>& windowDevices)
+{
+    auto devices = MockRealtimeMediaSourceCenter::displayDevices();
+    for (auto device : devices) {
+        if (!device.enabled() || device.type() != CaptureDevice::DeviceType::Window)
+            continue;
+
+        windowDevices.append({ WTFMove(device), "Mock Application"_s });
+    }
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(MEDIA_STREAM)
diff --git a/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.h b/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.h
index ffb7e8e..7fac899 100644
--- a/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.h
+++ b/Source/WebCore/platform/mock/MockRealtimeMediaSourceCenter.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2013 Google Inc. All rights reserved.
- * Copyright (C) 2013-2108 Apple Inc.  All rights reserved.
+ * Copyright (C) 2013-2022 Apple Inc.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -28,7 +28,7 @@
 
 #if ENABLE(MEDIA_STREAM)
 
-#include "CaptureDeviceManager.h"
+#include "DisplayCaptureManager.h"
 #include "MockMediaDevice.h"
 #include "MockRealtimeAudioSource.h"
 #include "MockRealtimeVideoSource.h"
@@ -56,14 +56,14 @@
     static Vector<CaptureDevice>& microphoneDevices();
     static Vector<CaptureDevice>& speakerDevices();
     static Vector<CaptureDevice>& videoDevices();
-    static Vector<CaptureDevice>& displayDevices();
+    WEBCORE_EXPORT static Vector<CaptureDevice>& displayDevices();
 
     static std::optional<MockMediaDevice> mockDeviceWithPersistentID(const String&);
     static std::optional<CaptureDevice> captureDeviceWithPersistentID(CaptureDevice::DeviceType, const String&);
 
     CaptureDeviceManager& audioCaptureDeviceManager() { return m_audioCaptureDeviceManager; }
     CaptureDeviceManager& videoCaptureDeviceManager() { return m_videoCaptureDeviceManager; }
-    CaptureDeviceManager& displayCaptureDeviceManager() { return m_displayCaptureDeviceManager; }
+    DisplayCaptureManager& displayCaptureDeviceManager() { return m_displayCaptureDeviceManager; }
 
 private:
     MockRealtimeMediaSourceCenter() = default;
@@ -83,10 +83,11 @@
         const Vector<CaptureDevice>& captureDevices() final { return MockRealtimeMediaSourceCenter::videoDevices(); }
         std::optional<CaptureDevice> captureDeviceWithPersistentID(CaptureDevice::DeviceType type, const String& id) final { return MockRealtimeMediaSourceCenter::captureDeviceWithPersistentID(type, id); }
     };
-    class MockDisplayCaptureDeviceManager final : public CaptureDeviceManager {
+    class MockDisplayCaptureDeviceManager final : public DisplayCaptureManager {
     private:
         const Vector<CaptureDevice>& captureDevices() final { return MockRealtimeMediaSourceCenter::displayDevices(); }
         std::optional<CaptureDevice> captureDeviceWithPersistentID(CaptureDevice::DeviceType type, const String& id) final { return MockRealtimeMediaSourceCenter::captureDeviceWithPersistentID(type, id); }
+        void windowDevices(Vector<DisplayCaptureManager::WindowCaptureDevice>&) final;
     };
 
     MockAudioCaptureDeviceManager m_audioCaptureDeviceManager;
diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog
index daed51a..79a5a7d 100644
--- a/Source/WebKit/ChangeLog
+++ b/Source/WebKit/ChangeLog
@@ -1,3 +1,73 @@
+2022-01-25  Eric Carlson  <eric.carlson@apple.com>
+
+        [macOS] Add new screen and window capture backend
+        https://bugs.webkit.org/show_bug.cgi?id=234029
+        rdar://problem/86347726
+
+        Reviewed by Jer Noble and Youenn Fablet.
+
+        * Shared/WebPreferencesDefaultValues.cpp:
+        (WebKit::defaultScreenCaptureKitEnabled):
+        * Shared/WebPreferencesDefaultValues.h:
+
+        * SourcesCocoa.txt:
+        * UIProcess/API/Cocoa/WKPreferences.mm: Add _useScreenCaptureKit private preference.
+        (-[WKPreferences _useScreenCaptureKit]):
+        (-[WKPreferences _setUseScreenCaptureKit:]):
+        * UIProcess/API/Cocoa/WKPreferencesPrivate.h:
+
+        * UIProcess/API/Cocoa/WKUIDelegatePrivate.h: Add private delegate for a 
+        getDisplayMedia-specific prompt.
+        
+        * UIProcess/API/Cocoa/WKWebViewPrivateForTesting.h:
+        * UIProcess/API/Cocoa/WKWebViewTesting.mm:
+        (-[WKWebView _setIndexOfGetDisplayMediaDeviceSelectedForTesting:]): Set the index
+        of the screen or window device to return for getDisplayMedia without prompting.
+
+        * UIProcess/Cocoa/UIDelegate.h:
+        * UIProcess/Cocoa/UIDelegate.mm:
+        (WebKit::UIDelegate::UIClient::promptForDisplayCapturePermission): Call new 
+        screen/window capture delegate.
+        (WebKit::UIDelegate::UIClient::decidePolicyForUserMediaPermissionRequest):
+
+        * UIProcess/UserMediaPermissionRequestProxy.cpp:
+        (WebKit::UserMediaPermissionRequestProxy::create):
+        (WebKit::UserMediaPermissionRequestProxy::promptForGetDisplayMedia): Add parameter
+        specifying a window or screen capture prompt.
+        * UIProcess/UserMediaPermissionRequestProxy.h:
+        (WebKit::UserMediaPermissionRequestProxy::create):
+        (WebKit::UserMediaPermissionRequestProxy::manager const):
+
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::setIndexOfGetDisplayMediaDeviceSelectedForTesting):
+        * UIProcess/WebPageProxy.h:
+
+        * UIProcess/mac/DisplayCaptureSessionManager.h: Added.
+        (WebKit::DisplayCaptureSessionManager::setIndexOfDeviceSelectedForTesting):
+        * UIProcess/mac/DisplayCaptureSessionManager.mm: Added.
+        (WebKit::getMockWindowList):
+        (WebKit::getCGWindowList):
+        (WebKit::getWindowList):
+        (WebKit::alertForWindowSelection):
+        (WebKit::DisplayCaptureSessionManager::alertForGetDisplayMedia):
+        (WebKit::DisplayCaptureSessionManager::isAvailable):
+        (WebKit::DisplayCaptureSessionManager::singleton):
+        (WebKit::DisplayCaptureSessionManager::DisplayCaptureSessionManager):
+        (WebKit::DisplayCaptureSessionManager::~DisplayCaptureSessionManager):
+        (WebKit::DisplayCaptureSessionManager::promptForGetDisplayMedia):
+        (WebKit::DisplayCaptureSessionManager::deviceSelectedForTesting):
+        (WebKit::DisplayCaptureSessionManager::showWindowPicker):
+        (WebKit::DisplayCaptureSessionManager::showScreenPicker):
+
+        * UIProcess/mac/UserMediaPermissionRequestProxyMac.h: Added.
+        * UIProcess/mac/UserMediaPermissionRequestProxyMac.mm: Added.
+        (WebKit::UserMediaPermissionRequestProxy::create):
+        (WebKit::UserMediaPermissionRequestProxyMac::UserMediaPermissionRequestProxyMac):
+        (WebKit::UserMediaPermissionRequestProxyMac::~UserMediaPermissionRequestProxyMac):
+        (WebKit::UserMediaPermissionRequestProxyMac::promptForGetDisplayMedia):
+        (WebKit::UserMediaPermissionRequestProxyMac::canPromptForGetDisplayMedia):
+        * WebKit.xcodeproj/project.pbxproj:
+
 2022-01-25  Tim Horton  <timothy_horton@apple.com>
 
         Shadows are flattened to bitmaps in CGDisplayListImageBufferBackend
diff --git a/Source/WebKit/Shared/WebPreferencesDefaultValues.cpp b/Source/WebKit/Shared/WebPreferencesDefaultValues.cpp
index fa0df4d..e0ba73d 100644
--- a/Source/WebKit/Shared/WebPreferencesDefaultValues.cpp
+++ b/Source/WebKit/Shared/WebPreferencesDefaultValues.cpp
@@ -343,4 +343,16 @@
 }
 #endif
 
+#if HAVE(SCREEN_CAPTURE_KIT)
+bool defaultScreenCaptureKitEnabled()
+{
+#if ENABLE(SCREEN_CAPTURE_KIT)
+    return true;
+#else
+    return false;
+#endif
+}
+#endif // HAVE(SCREEN_CAPTURE_KIT)
+
+
 } // namespace WebKit
diff --git a/Source/WebKit/Shared/WebPreferencesDefaultValues.h b/Source/WebKit/Shared/WebPreferencesDefaultValues.h
index 2cedc4b..ad745a4 100644
--- a/Source/WebKit/Shared/WebPreferencesDefaultValues.h
+++ b/Source/WebKit/Shared/WebPreferencesDefaultValues.h
@@ -115,4 +115,8 @@
 bool defaultMediaSessionCoordinatorEnabled();
 #endif
 
+#if HAVE(SCREEN_CAPTURE_KIT)
+bool defaultScreenCaptureKitEnabled();
+#endif
+
 } // namespace WebKit
diff --git a/Source/WebKit/SourcesCocoa.txt b/Source/WebKit/SourcesCocoa.txt
index 1a9ffb1..7bfee08 100644
--- a/Source/WebKit/SourcesCocoa.txt
+++ b/Source/WebKit/SourcesCocoa.txt
@@ -518,6 +518,7 @@
 UIProcess/Launcher/cocoa/ProcessLauncherCocoa.mm
 
 UIProcess/mac/CorrectionPanel.mm
+UIProcess/mac/DisplayCaptureSessionManager.mm
 UIProcess/mac/DisplayLink.cpp
 UIProcess/mac/HighPerformanceGPUManager.mm
 UIProcess/mac/LegacySessionStateCoding.cpp
@@ -526,6 +527,7 @@
 UIProcess/mac/ServicesController.mm
 UIProcess/mac/TextCheckerMac.mm
 UIProcess/mac/TiledCoreAnimationDrawingAreaProxy.mm
+UIProcess/mac/UserMediaPermissionRequestProxyMac.mm
 UIProcess/mac/ViewGestureControllerMac.mm
 UIProcess/mac/ViewSnapshotStoreMac.mm
 UIProcess/mac/WebColorPickerMac.mm
diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm b/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm
index c50ffd7..eab0c59 100644
--- a/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm
+++ b/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm
@@ -700,6 +700,16 @@
     _preferences->setMediaCaptureRequiresSecureConnection(requiresSecureConnection);
 }
 
+- (BOOL)_useScreenCaptureKit
+{
+    return _preferences->useScreenCaptureKit();
+}
+
+- (void)_setUseScreenCaptureKit:(BOOL)useScreenCaptureKit
+{
+    _preferences->setUseScreenCaptureKit(useScreenCaptureKit);
+}
+
 - (double)_inactiveMediaCaptureSteamRepromptIntervalInMinutes
 {
     return _preferences->inactiveMediaCaptureSteamRepromptIntervalInMinutes();
diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h b/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h
index b160258..22bd11c 100644
--- a/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h
+++ b/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h
@@ -122,6 +122,7 @@
 @property (nonatomic, setter=_setMockCaptureDevicesEnabled:) BOOL _mockCaptureDevicesEnabled WK_API_AVAILABLE(macos(10.13), ios(11.0));
 @property (nonatomic, setter=_setMockCaptureDevicesPromptEnabled:) BOOL _mockCaptureDevicesPromptEnabled WK_API_AVAILABLE(macos(10.13.4), ios(11.3));
 @property (nonatomic, setter=_setMediaCaptureRequiresSecureConnection:) BOOL _mediaCaptureRequiresSecureConnection WK_API_AVAILABLE(macos(10.13), ios(11.0));
+@property (nonatomic, setter=_setUseScreenCaptureKit:) BOOL _useScreenCaptureKit WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 @property (nonatomic, setter=_setEnumeratingAllNetworkInterfacesEnabled:) BOOL _enumeratingAllNetworkInterfacesEnabled WK_API_AVAILABLE(macos(10.13), ios(11.0));
 @property (nonatomic, setter=_setICECandidateFilteringEnabled:) BOOL _iceCandidateFilteringEnabled WK_API_AVAILABLE(macos(10.13.4), ios(11.3));
 @property (nonatomic, setter=_setWebRTCLegacyAPIEnabled:) BOOL _webRTCLegacyAPIEnabled WK_API_AVAILABLE(macos(10.13), ios(11.0));
diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegatePrivate.h b/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegatePrivate.h
index 9c43213..d6a7ab6 100644
--- a/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegatePrivate.h
+++ b/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegatePrivate.h
@@ -111,6 +111,12 @@
     _WKModalContainerDecisionHideAndDisallow,
 } WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 
+typedef NS_ENUM(NSInteger, WKDisplayCapturePermissionDecision) {
+    WKDisplayCapturePermissionDecisionDeny,
+    WKDisplayCapturePermissionDecisionScreenPrompt,
+    WKDisplayCapturePermissionDecisionWindowPrompt,
+} WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
+
 @protocol WKUIDelegatePrivate <WKUIDelegate>
 
 #ifdef FOUNDATION_HAS_DIRECTIONAL_GEOMETRY
@@ -147,6 +153,7 @@
 - (void)_webView:(WKWebView *)webView imageOrMediaDocumentSizeChanged:(CGSize)size WK_API_AVAILABLE(macos(10.12), ios(10.0));
 - (NSDictionary *)_dataDetectionContextForWebView:(WKWebView *)webView WK_API_AVAILABLE(macos(10.12), ios(10.0));
 - (void)_webView:(WKWebView *)webView includeSensitiveMediaDeviceDetails:(void (^)(BOOL includeSensitiveDetails))decisionHandler WK_API_AVAILABLE(macos(10.15), ios(13.0));
+- (void)_webView:(WKWebView *)webView requestDisplayCapturePermissionForOrigin:(WKSecurityOrigin *)securityOrigin initiatedByFrame:(WKFrameInfo *)frame withSystemAudio:(BOOL)withSystemAudio decisionHandler:(void (^)(WKDisplayCapturePermissionDecision decision))decisionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 - (void)_webView:(WKWebView *)webView requestUserMediaAuthorizationForDevices:(_WKCaptureDevices)devices url:(NSURL *)url mainFrameURL:(NSURL *)mainFrameURL decisionHandler:(void (^)(BOOL authorized))decisionHandler WK_API_AVAILABLE(macos(10.13), ios(11.0));
 - (void)_webView:(WKWebView *)webView checkUserMediaPermissionForURL:(NSURL *)url mainFrameURL:(NSURL *)mainFrameURL frameIdentifier:(NSUInteger)frameIdentifier decisionHandler:(void (^)(NSString *salt, BOOL authorized))decisionHandler WK_API_AVAILABLE(macos(10.12.3), ios(10.3));
 - (void)_webView:(WKWebView *)webView mediaCaptureStateDidChange:(_WKMediaCaptureStateDeprecated)state WK_API_AVAILABLE(macos(10.13), ios(11.0));
diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivateForTesting.h b/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivateForTesting.h
index 4ee8060..168ff51 100644
--- a/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivateForTesting.h
+++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebViewPrivateForTesting.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2019-2021 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -66,6 +66,8 @@
 @property (nonatomic, setter=_setMediaCaptureReportingDelayForTesting:) double _mediaCaptureReportingDelayForTesting WK_API_AVAILABLE(macos(12.0), ios(15.0));
 @property (nonatomic, readonly) BOOL _wirelessVideoPlaybackDisabled;
 
+- (void)_setIndexOfGetDisplayMediaDeviceSelectedForTesting:(nullable NSNumber *)index;
+
 - (BOOL)_beginBackSwipeForTesting;
 - (BOOL)_completeBackSwipeForTesting;
 - (void)_resetNavigationGestureStateForTesting;
diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKWebViewTesting.mm b/Source/WebKit/UIProcess/API/Cocoa/WKWebViewTesting.mm
index 77958b9..e862c87 100644
--- a/Source/WebKit/UIProcess/API/Cocoa/WKWebViewTesting.mm
+++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebViewTesting.mm
@@ -260,6 +260,20 @@
 #endif
 }
 
+- (void)_setIndexOfGetDisplayMediaDeviceSelectedForTesting:(NSNumber *)nsIndex
+{
+#if HAVE(SCREEN_CAPTURE_KIT)
+    if (!_page)
+        return;
+
+    std::optional<unsigned> index;
+    if (nsIndex)
+        index = nsIndex.unsignedIntValue;
+
+    _page->setIndexOfGetDisplayMediaDeviceSelectedForTesting(index);
+#endif
+}
+
 - (double)_mediaCaptureReportingDelayForTesting
 {
     return _page->mediaCaptureReportingDelay().value();
diff --git a/Source/WebKit/UIProcess/Cocoa/UIDelegate.h b/Source/WebKit/UIProcess/Cocoa/UIDelegate.h
index 9a033db..3d1e64c 100644
--- a/Source/WebKit/UIProcess/Cocoa/UIDelegate.h
+++ b/Source/WebKit/UIProcess/Cocoa/UIDelegate.h
@@ -145,6 +145,7 @@
         void decidePolicyForUserMediaPermissionRequest(WebPageProxy&, WebFrameProxy&, API::SecurityOrigin&, API::SecurityOrigin&, UserMediaPermissionRequestProxy&) final;
         void checkUserMediaPermissionForOrigin(WebPageProxy&, WebFrameProxy&, API::SecurityOrigin&, API::SecurityOrigin&, UserMediaPermissionCheckProxy&) final;
         void mediaCaptureStateDidChange(WebCore::MediaProducerMediaStateFlags) final;
+        void promptForDisplayCapturePermission(WebPageProxy&, WebFrameProxy&, API::SecurityOrigin&, API::SecurityOrigin&, UserMediaPermissionRequestProxy&);
         void printFrame(WebPageProxy&, WebFrameProxy&, const WebCore::FloatSize& pdfFirstPageSize, CompletionHandler<void()>&&) final;
 #if PLATFORM(IOS_FAMILY)
 #if HAVE(APP_LINKS)
diff --git a/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm b/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm
index ddfc67d..f9d6313 100644
--- a/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm
+++ b/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm
@@ -1136,6 +1136,43 @@
     [privateUIDelegate _webView:m_uiDelegate->m_webView.get().get() didChangeFontAttributes:fontAttributes.createDictionary().get()];
 }
 
+void UIDelegate::UIClient::promptForDisplayCapturePermission(WebPageProxy& page, WebFrameProxy& frame, API::SecurityOrigin& userMediaOrigin, API::SecurityOrigin& topLevelOrigin, UserMediaPermissionRequestProxy& request)
+{
+    auto delegate = (id <WKUIDelegatePrivate>)m_uiDelegate->m_delegate.get();
+
+    ASSERT([delegate respondsToSelector:@selector(_webView:requestDisplayCapturePermissionForOrigin:initiatedByFrame:withSystemAudio:decisionHandler:)]);
+    ASSERT(request.canPromptForGetDisplayMedia());
+
+    auto checker = CompletionHandlerCallChecker::create(delegate, @selector(_webView:requestDisplayCapturePermissionForOrigin:initiatedByFrame:withSystemAudio:decisionHandler:));
+    auto decisionHandler = makeBlockPtr([protectedRequest = Ref { request }, checker = WTFMove(checker)](WKDisplayCapturePermissionDecision decision) {
+        if (checker->completionHandlerHasBeenCalled())
+            return;
+        checker->didCallCompletionHandler();
+
+        switch (decision) {
+        case WKDisplayCapturePermissionDecisionScreenPrompt:
+            protectedRequest->promptForGetDisplayMedia(UserMediaPermissionRequestProxy::UserMediaDisplayCapturePromptType::Screen);
+            break;
+        case WKDisplayCapturePermissionDecisionWindowPrompt: {
+            protectedRequest->promptForGetDisplayMedia(UserMediaPermissionRequestProxy::UserMediaDisplayCapturePromptType::Window);
+            break;
+        }
+        case WKDisplayCapturePermissionDecisionDeny:
+            protectedRequest->deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied);
+            break;
+        }
+    });
+
+    std::optional<WebCore::FrameIdentifier> mainFrameID;
+    if (auto* mainFrame = frame.page() ? frame.page()->mainFrame() : nullptr)
+        mainFrameID = mainFrame->frameID();
+    FrameInfoData frameInfo { frame.isMainFrame(), { }, userMediaOrigin.securityOrigin(), { }, frame.frameID(), mainFrameID };
+    RetainPtr<WKFrameInfo> frameInfoWrapper = wrapper(API::FrameInfo::create(WTFMove(frameInfo), frame.page()));
+
+    BOOL requestSystemAudio = !!request.requiresDisplayCaptureWithAudio();
+    [delegate _webView:m_uiDelegate->m_webView.get().get() requestDisplayCapturePermissionForOrigin:wrapper(topLevelOrigin) initiatedByFrame:frameInfoWrapper.get() withSystemAudio:requestSystemAudio decisionHandler:decisionHandler.get()];
+
+}
 void UIDelegate::UIClient::decidePolicyForUserMediaPermissionRequest(WebPageProxy& page, WebFrameProxy& frame, API::SecurityOrigin& userMediaOrigin, API::SecurityOrigin& topLevelOrigin, UserMediaPermissionRequestProxy& request)
 {
 #if ENABLE(MEDIA_STREAM)
@@ -1150,17 +1187,13 @@
 
     bool respondsToRequestMediaCapturePermission = [delegate respondsToSelector:@selector(webView:requestMediaCapturePermissionForOrigin:initiatedByFrame:type:decisionHandler:)];
     bool respondsToRequestUserMediaAuthorizationForDevices = [delegate respondsToSelector:@selector(_webView:requestUserMediaAuthorizationForDevices:url:mainFrameURL:decisionHandler:)];
+    bool respondsToRequestDisplayCapturePermissionForOrigin = [delegate respondsToSelector:@selector(_webView:requestDisplayCapturePermissionForOrigin:initiatedByFrame:withSystemAudio:decisionHandler:)];
 
-    if (!respondsToRequestMediaCapturePermission && !respondsToRequestUserMediaAuthorizationForDevices) {
+    if (!respondsToRequestMediaCapturePermission && !respondsToRequestUserMediaAuthorizationForDevices && !respondsToRequestDisplayCapturePermissionForOrigin) {
         request.doDefaultAction();
         return;
     }
 
-    if (request.requiresDisplayCapture() && request.canPromptForGetDisplayMedia()) {
-        request.promptForGetDisplayMedia();
-        return;
-    }
-
     // FIXME: Provide a specific delegate for display capture.
     if (!request.requiresDisplayCapture() && respondsToRequestMediaCapturePermission) {
         auto checker = CompletionHandlerCallChecker::create(delegate, @selector(webView:requestMediaCapturePermissionForOrigin:initiatedByFrame:type:decisionHandler:));
@@ -1198,6 +1231,20 @@
         return;
     }
 
+    if (request.requiresDisplayCapture() && request.canPromptForGetDisplayMedia()) {
+        if (respondsToRequestDisplayCapturePermissionForOrigin)
+            promptForDisplayCapturePermission(page, frame, userMediaOrigin, topLevelOrigin, request);
+        else
+            request.promptForGetDisplayMedia();
+
+        return;
+    }
+
+    if (!respondsToRequestUserMediaAuthorizationForDevices) {
+        request.doDefaultAction();
+        return;
+    }
+
     URL requestFrameURL { frame.url() };
     URL mainFrameURL { frame.page()->mainFrame()->url() };
 
diff --git a/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp b/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp
index 518c3b2..e0b5e29 100644
--- a/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp
+++ b/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp
@@ -45,6 +45,10 @@
 #include "GPUProcessProxy.h"
 #endif
 
+#if HAVE(SCREEN_CAPTURE_KIT)
+#include <WebCore/ScreenCaptureKitCaptureSource.h>
+#endif
+
 namespace WebKit {
 using namespace WebCore;
 
@@ -421,7 +425,7 @@
 #if ENABLE(MEDIA_STREAM)
 UserMediaPermissionRequestManagerProxy::RequestAction UserMediaPermissionRequestManagerProxy::getRequestAction(const UserMediaPermissionRequestProxy& request)
 {
-    bool requestingScreenCapture = request.requestType() == MediaStreamRequest::Type::DisplayMedia;
+    bool requestingScreenCapture = request.requestType() == MediaStreamRequest::Type::DisplayMedia || request.requestType() == MediaStreamRequest::Type::DisplayMediaWithAudio;
     bool requestingCamera = !requestingScreenCapture && request.hasVideoDevice();
     bool requestingMicrophone = request.hasAudioDevice();
 
@@ -431,7 +435,7 @@
     if (!request.isUserGesturePriviledged() && wasRequestDenied(request, requestingMicrophone, requestingCamera, requestingScreenCapture))
         return RequestAction::Deny;
 
-    if (request.requestType() == MediaStreamRequest::Type::DisplayMedia)
+    if (requestingScreenCapture)
         return RequestAction::Prompt;
 
     return searchForGrantedRequest(request.frameID(), request.userMediaDocumentSecurityOrigin(), request.topLevelDocumentSecurityOrigin(), requestingMicrophone, requestingCamera) ? RequestAction::Grant : RequestAction::Prompt;
@@ -580,7 +584,7 @@
     }
 
     if (action == RequestAction::Grant) {
-        ASSERT(m_currentUserMediaRequest->requestType() != MediaStreamRequest::Type::DisplayMedia);
+        ASSERT(m_currentUserMediaRequest->requestType() != MediaStreamRequest::Type::DisplayMedia && m_currentUserMediaRequest->requestType() != MediaStreamRequest::Type::DisplayMediaWithAudio);
 
         if (m_page.isViewVisible())
             grantRequest(*m_currentUserMediaRequest);
@@ -861,6 +865,10 @@
         m_page.process().processPool().ensureGPUProcess().setUseMockCaptureDevices(mockDevicesEnabled);
 #endif
 
+#if HAVE(SCREEN_CAPTURE_KIT)
+    WebCore::ScreenCaptureKitCaptureSource::setEnabled(m_page.preferences().useScreenCaptureKit());
+#endif
+
     if (MockRealtimeMediaSourceCenter::mockRealtimeMediaSourceCenterEnabled() == mockDevicesEnabled)
         return;
     MockRealtimeMediaSourceCenter::setMockRealtimeMediaSourceCenterEnabled(mockDevicesEnabled);
diff --git a/Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.cpp b/Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.cpp
index f3bf4a7..acd30bb 100644
--- a/Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.cpp
+++ b/Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.cpp
@@ -31,6 +31,13 @@
 namespace WebKit {
 using namespace WebCore;
 
+#if !PLATFORM(COCOA)
+Ref<UserMediaPermissionRequestProxy> UserMediaPermissionRequestProxy::create(UserMediaPermissionRequestManagerProxy& manager, WebCore::UserMediaRequestIdentifier userMediaID, WebCore::FrameIdentifier mainFrameID, WebCore::FrameIdentifier frameID, Ref<WebCore::SecurityOrigin>&& userMediaDocumentOrigin, Ref<WebCore::SecurityOrigin>&& topLevelDocumentOrigin, Vector<WebCore::CaptureDevice>&& audioDevices, Vector<WebCore::CaptureDevice>&& videoDevices, WebCore::MediaStreamRequest&& request, CompletionHandler<void(bool)>&& decisionCompletionHandler)
+{
+    return adoptRef(*new UserMediaPermissionRequestProxy(manager, userMediaID, mainFrameID, frameID, WTFMove(userMediaDocumentOrigin), WTFMove(topLevelDocumentOrigin), WTFMove(audioDevices), WTFMove(videoDevices), WTFMove(request), WTFMove(decisionCompletionHandler)));
+}
+#endif
+
 UserMediaPermissionRequestProxy::UserMediaPermissionRequestProxy(UserMediaPermissionRequestManagerProxy& manager, UserMediaRequestIdentifier userMediaID, FrameIdentifier mainFrameID, FrameIdentifier frameID, Ref<WebCore::SecurityOrigin>&& userMediaDocumentOrigin, Ref<WebCore::SecurityOrigin>&& topLevelDocumentOrigin, Vector<WebCore::CaptureDevice>&& audioDevices, Vector<WebCore::CaptureDevice>&& videoDevices, WebCore::MediaStreamRequest&& request, CompletionHandler<void(bool)>&& decisionCompletionHandler)
     : m_manager(&manager)
     , m_userMediaID(userMediaID)
@@ -140,11 +147,11 @@
     return values[static_cast<size_t>(enumerationValue)];
 }
 
-void UserMediaPermissionRequestProxy::promptForGetDisplayMedia()
+void UserMediaPermissionRequestProxy::promptForGetDisplayMedia(UserMediaDisplayCapturePromptType promptType)
 {
 #if ENABLE(MEDIA_STREAM) && PLATFORM(COCOA)
-    ASSERT(m_manager && canPromptForGetDisplayMedia());
-    if (!m_manager || !canPromptForGetDisplayMedia()) {
+    ASSERT(m_manager && canPromptForGetDisplayMedia() && promptType != UserMediaDisplayCapturePromptType::UserChoose);
+    if (!m_manager || !canPromptForGetDisplayMedia() || promptType != UserMediaDisplayCapturePromptType::UserChoose) {
         deny(UserMediaAccessDenialReason::PermissionDenied);
         return;
     }
diff --git a/Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.h b/Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.h
index df412ab..d7fb889 100644
--- a/Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.h
+++ b/Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.h
@@ -38,16 +38,18 @@
 
 class UserMediaPermissionRequestProxy : public API::ObjectImpl<API::Object::Type::UserMediaPermissionRequest> {
 public:
-    static Ref<UserMediaPermissionRequestProxy> create(UserMediaPermissionRequestManagerProxy& manager, WebCore::UserMediaRequestIdentifier userMediaID, WebCore::FrameIdentifier mainFrameID, WebCore::FrameIdentifier frameID, Ref<WebCore::SecurityOrigin>&& userMediaDocumentOrigin, Ref<WebCore::SecurityOrigin>&& topLevelDocumentOrigin, Vector<WebCore::CaptureDevice>&& audioDevices, Vector<WebCore::CaptureDevice>&& videoDevices, WebCore::MediaStreamRequest&& request, CompletionHandler<void(bool)>&& decisionCompletionHandler = { })
-    {
-        return adoptRef(*new UserMediaPermissionRequestProxy(manager, userMediaID, mainFrameID, frameID, WTFMove(userMediaDocumentOrigin), WTFMove(topLevelDocumentOrigin), WTFMove(audioDevices), WTFMove(videoDevices), WTFMove(request), WTFMove(decisionCompletionHandler)));
-    }
+    static Ref<UserMediaPermissionRequestProxy> create(UserMediaPermissionRequestManagerProxy&, WebCore::UserMediaRequestIdentifier, WebCore::FrameIdentifier, WebCore::FrameIdentifier, Ref<WebCore::SecurityOrigin>&&, Ref<WebCore::SecurityOrigin>&&, Vector<WebCore::CaptureDevice>&&, Vector<WebCore::CaptureDevice>&&, WebCore::MediaStreamRequest&&, CompletionHandler<void(bool)>&& = { });
+
+    ~UserMediaPermissionRequestProxy() = default;
 
     void allow(const String& audioDeviceUID, const String& videoDeviceUID);
     void allow();
     void promptForGetUserMedia();
-    void promptForGetDisplayMedia();
-    bool canPromptForGetDisplayMedia();
+
+    enum class UserMediaDisplayCapturePromptType { Window, Screen, UserChoose };
+    virtual void promptForGetDisplayMedia(UserMediaDisplayCapturePromptType = UserMediaDisplayCapturePromptType::UserChoose);
+    virtual bool canPromptForGetDisplayMedia();
+
     void doDefaultAction();
     enum class UserMediaAccessDenialReason { NoConstraints, UserMediaDisabled, NoCaptureDevices, InvalidConstraint, HardwareError, PermissionDenied, OtherFailure };
     void deny(UserMediaAccessDenialReason = UserMediaAccessDenialReason::UserMediaDisabled);
@@ -57,7 +59,8 @@
 
     bool requiresAudioCapture() const { return m_eligibleAudioDevices.size(); }
     bool requiresVideoCapture() const { return !requiresDisplayCapture() && m_eligibleVideoDevices.size(); }
-    bool requiresDisplayCapture() const { return m_request.type == WebCore::MediaStreamRequest::Type::DisplayMedia && m_eligibleVideoDevices.size(); }
+    bool requiresDisplayCapture() const { return (m_request.type == WebCore::MediaStreamRequest::Type::DisplayMedia || m_request.type == WebCore::MediaStreamRequest::Type::DisplayMediaWithAudio) && m_eligibleVideoDevices.size(); }
+    bool requiresDisplayCaptureWithAudio() const { return m_request.type == WebCore::MediaStreamRequest::Type::DisplayMediaWithAudio && m_eligibleVideoDevices.size(); }
 
     void setEligibleVideoDeviceUIDs(Vector<WebCore::CaptureDevice>&& devices) { m_eligibleVideoDevices = WTFMove(devices); }
     void setEligibleAudioDeviceUIDs(Vector<WebCore::CaptureDevice>&& devices) { m_eligibleAudioDevices = WTFMove(devices); }
@@ -95,9 +98,12 @@
 
     CompletionHandler<void(bool)> decisionCompletionHandler() { return std::exchange(m_decisionCompletionHandler, { }); }
 
-private:
+protected:
     UserMediaPermissionRequestProxy(UserMediaPermissionRequestManagerProxy&, WebCore::UserMediaRequestIdentifier, WebCore::FrameIdentifier mainFrameID, WebCore::FrameIdentifier, Ref<WebCore::SecurityOrigin>&& userMediaDocumentOrigin, Ref<WebCore::SecurityOrigin>&& topLevelDocumentOrigin, Vector<WebCore::CaptureDevice>&& audioDevices, Vector<WebCore::CaptureDevice>&& videoDevices, WebCore::MediaStreamRequest&&, CompletionHandler<void(bool)>&&);
 
+    UserMediaPermissionRequestManagerProxy* manager() const { return m_manager; }
+
+private:
     UserMediaPermissionRequestManagerProxy* m_manager;
     WebCore::UserMediaRequestIdentifier m_userMediaID;
     WebCore::FrameIdentifier m_mainFrameID;
diff --git a/Source/WebKit/UIProcess/WebPageProxy.cpp b/Source/WebKit/UIProcess/WebPageProxy.cpp
index f4b310f..5042d88 100644
--- a/Source/WebKit/UIProcess/WebPageProxy.cpp
+++ b/Source/WebKit/UIProcess/WebPageProxy.cpp
@@ -174,6 +174,7 @@
 #include <WebCore/PlatformEvent.h>
 #include <WebCore/PrivateClickMeasurement.h>
 #include <WebCore/PublicSuffix.h>
+#include <WebCore/RealtimeMediaSourceCenter.h>
 #include <WebCore/RenderEmbeddedObject.h>
 #include <WebCore/ResourceLoadStatistics.h>
 #include <WebCore/RuntimeApplicationChecks.h>
@@ -311,6 +312,10 @@
 #include <WebCore/HighlightVisibility.h>
 #endif
 
+#if HAVE(SCREEN_CAPTURE_KIT)
+#import "DisplayCaptureSessionManager.h"
+#endif
+
 #define MESSAGE_CHECK(process, assertion) MESSAGE_CHECK_BASE(assertion, process->connection())
 #define MESSAGE_CHECK_URL(process, url) MESSAGE_CHECK_BASE(checkURLReceivedFromCurrentOrPreviousWebProcess(process, url), process->connection())
 #define MESSAGE_CHECK_COMPLETION(process, assertion, completion) MESSAGE_CHECK_COMPLETION_BASE(assertion, process->connection(), completion)
@@ -8585,6 +8590,7 @@
         return *m_userMediaPermissionRequestManager;
 
     m_userMediaPermissionRequestManager = makeUnique<UserMediaPermissionRequestManagerProxy>(*this);
+
     return *m_userMediaPermissionRequestManager;
 }
 
@@ -10923,6 +10929,13 @@
 
 #endif
 
+#if HAVE(SCREEN_CAPTURE_KIT)
+void WebPageProxy::setIndexOfGetDisplayMediaDeviceSelectedForTesting(std::optional<unsigned> index)
+{
+    DisplayCaptureSessionManager::singleton().setIndexOfDeviceSelectedForTesting(index);
+}
+#endif
+
 #if ENABLE(ARKIT_INLINE_PREVIEW)
 void WebPageProxy::modelElementGetCamera(ModelIdentifier modelIdentifier, CompletionHandler<void(Expected<WebCore::HTMLModelElementCamera, ResourceError>)>&& completionHandler)
 {
diff --git a/Source/WebKit/UIProcess/WebPageProxy.h b/Source/WebKit/UIProcess/WebPageProxy.h
index 8c6599d..0c86060 100644
--- a/Source/WebKit/UIProcess/WebPageProxy.h
+++ b/Source/WebKit/UIProcess/WebPageProxy.h
@@ -1964,6 +1964,10 @@
     WebCore::CaptureSourceOrError createRealtimeMediaSourceForSpeechRecognition();
 #endif
 
+#if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM)
+    void setIndexOfGetDisplayMediaDeviceSelectedForTesting(std::optional<unsigned>);
+#endif
+
 #if PLATFORM(MAC)
     void changeUniversalAccessZoomFocus(const WebCore::IntRect&, const WebCore::IntRect&);
 
diff --git a/Source/WebKit/UIProcess/mac/DisplayCaptureSessionManager.h b/Source/WebKit/UIProcess/mac/DisplayCaptureSessionManager.h
new file mode 100644
index 0000000..60d93b3
--- /dev/null
+++ b/Source/WebKit/UIProcess/mac/DisplayCaptureSessionManager.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2021 Apple Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted, provided that the following conditions
+ * are required to be 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. AND 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 PLATFORM(COCOA) && ENABLE(MEDIA_STREAM)
+
+#include "UserMediaPermissionRequestProxy.h"
+#include <WebCore/SecurityOriginData.h>
+#include <wtf/CompletionHandler.h>
+#include <wtf/WeakPtr.h>
+
+namespace WebCore {
+class SecurityOrigin;
+}
+
+namespace WebKit {
+
+class DisplayCaptureSessionManager {
+public:
+    static DisplayCaptureSessionManager& singleton();
+    static bool isAvailable();
+
+    DisplayCaptureSessionManager();
+    ~DisplayCaptureSessionManager();
+
+    void promptForGetDisplayMedia(UserMediaPermissionRequestProxy::UserMediaDisplayCapturePromptType, WebPageProxy&, const WebCore::SecurityOriginData&, CompletionHandler<void(std::optional<WebCore::CaptureDevice>)>&&);
+    void setIndexOfDeviceSelectedForTesting(std::optional<unsigned> index) { m_indexOfDeviceSelectedForTesting = index; }
+
+private:
+
+#if HAVE(SCREEN_CAPTURE_KIT)
+    enum class CaptureSessionType { None, Screen, Window };
+    void alertForGetDisplayMedia(WebPageProxy&, const WebCore::SecurityOriginData&, CompletionHandler<void(DisplayCaptureSessionManager::CaptureSessionType)>&&);
+    void showWindowPicker(WebPageProxy&, const WebCore::SecurityOriginData&, CompletionHandler<void(std::optional<WebCore::CaptureDevice>)>&&);
+    void showScreenPicker(WebPageProxy&, const WebCore::SecurityOriginData&, CompletionHandler<void(std::optional<WebCore::CaptureDevice>)>&&);
+    std::optional<WebCore::CaptureDevice> deviceSelectedForTesting(WebCore::CaptureDevice::DeviceType);
+#endif
+
+    std::optional<unsigned> m_indexOfDeviceSelectedForTesting;
+};
+
+} // namespace WebKit
+
+#endif // PLATFORM(COCOA) && ENABLE(MEDIA_STREAM)
diff --git a/Source/WebKit/UIProcess/mac/DisplayCaptureSessionManager.mm b/Source/WebKit/UIProcess/mac/DisplayCaptureSessionManager.mm
new file mode 100644
index 0000000..799f6f1
--- /dev/null
+++ b/Source/WebKit/UIProcess/mac/DisplayCaptureSessionManager.mm
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#import "config.h"
+#import "DisplayCaptureSessionManager.h"
+
+#if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM)
+
+#import "Logging.h"
+#import "MediaPermissionUtilities.h"
+#import "WKWebViewInternal.h"
+#import "WebPageProxy.h"
+#import <WebCore/CaptureDeviceManager.h>
+#import <WebCore/LocalizedStrings.h>
+#import <WebCore/MockRealtimeMediaSourceCenter.h>
+#import <WebCore/ScreenCaptureKitCaptureSource.h>
+#import <WebCore/SecurityOriginData.h>
+#import <wtf/BlockPtr.h>
+#import <wtf/MainThread.h>
+#import <wtf/NeverDestroyed.h>
+#import <wtf/URLHelpers.h>
+#import <wtf/cocoa/TypeCastsCocoa.h>
+#import <wtf/text/StringToIntegerConversion.h>
+
+namespace WebKit {
+
+#if HAVE(SCREEN_CAPTURE_KIT)
+
+static void alertForWindowSelection(WebPageProxy& page, const WebCore::SecurityOriginData& origin, CompletionHandler<void(std::optional<String>, std::optional<String>)>&& completionHandler)
+{
+    auto webView = page.cocoaView();
+    if (!webView) {
+        completionHandler(std::nullopt, std::nullopt);
+        return;
+    }
+
+    Vector<DisplayCaptureManager::WindowCaptureDevice> windowInfo;
+    RealtimeMediaSourceCenter::singleton().displayCaptureFactory().displayCaptureDeviceManager().windowDevices(windowInfo);
+    if (windowInfo.isEmpty()) {
+        completionHandler(std::nullopt, std::nullopt);
+        return;
+    }
+
+    std::sort(windowInfo.begin(), windowInfo.end(), [](auto& a, auto& b) {
+        if (a.m_application != b.m_application)
+            return codePointCompareLessThan(a.m_application, b.m_application);
+
+        return codePointCompareLessThan(a.m_device.label(), b.m_device.label());
+    });
+
+    auto alert = adoptNS([[NSAlert alloc] init]);
+    [alert setMessageText:WEB_UI_NSSTRING(@"Choose a window to share", Message for window sharing prompt)];
+
+    auto popupButton = adoptNS([[NSPopUpButton alloc] initWithFrame:NSMakeRect(10, 0, 290, 36) pullsDown:NO]);
+    auto menu = [popupButton menu];
+    menu.autoenablesItems = NO;
+    String currentApplication;
+    unsigned infoIndex = 0;
+    for (auto& info : windowInfo) {
+        if (info.m_application != currentApplication)    {
+            auto applicationItem = adoptNS([[NSMenuItem alloc] initWithTitle:info.m_application action:nil keyEquivalent:@""]);
+            [applicationItem setEnabled:NO];
+            [menu addItem:applicationItem.get()];
+            currentApplication = info.m_application;
+        }
+
+        auto title = info.m_device.label();
+        auto windowItem = adoptNS([[NSMenuItem alloc] initWithTitle:(!title.isEmpty() ? title : info.m_application) action:nil keyEquivalent:@""]);
+        [windowItem setIndentationLevel:1];
+        [windowItem setRepresentedObject:@(infoIndex++)];
+        [menu addItem:windowItem.get()];
+    }
+    [popupButton selectItem:nil];
+
+    auto menuLabel = adoptNS([[NSTextView alloc] init]);
+    [menuLabel setString:WEB_UI_NSSTRING(@"Window: ", "Label for window sharing menu")];
+    [menuLabel setDrawsBackground:NO];
+    [menuLabel setSelectable:NO];
+    [menuLabel setEditable:NO];
+
+    auto accessoryView = adoptNS([[NSView alloc] initWithFrame:NSMakeRect(0, 0, 300, 40)]);
+    [accessoryView addSubview:popupButton.get()];
+    [accessoryView addSubview:menuLabel.get()];
+    [alert setAccessoryView:accessoryView.get()];
+
+    NSButton *button = [alert addButtonWithTitle:WEB_UI_NSSTRING(@"Allow (window sharing)", "Allow button title in window sharing prompt")];
+    button.keyEquivalent = @"";
+    button = [alert addButtonWithTitle:WEB_UI_NSSTRING(@"Don’t Allow (window sharing)", "Disallow button title in window sharing prompt")];
+    button.keyEquivalent = @"\E";
+
+    [alert beginSheetModalForWindow:[webView window] completionHandler:[popupButton = WTFMove(popupButton), windowInfo, completionBlock = makeBlockPtr(WTFMove(completionHandler))](NSModalResponse returnCode) {
+        if (returnCode != NSAlertFirstButtonReturn) {
+            completionBlock(std::nullopt, std::nullopt);
+            return;
+        }
+
+        NSNumber *infoIndex = [[popupButton selectedItem] representedObject];
+        if (!infoIndex || [infoIndex unsignedIntegerValue] > windowInfo.size()) {
+            completionBlock(std::nullopt, std::nullopt);
+            return;
+        }
+
+        auto info = windowInfo[[infoIndex unsignedIntegerValue]];
+        completionBlock(info.m_device.persistentId(), info.m_device.label());
+    }];
+}
+
+void DisplayCaptureSessionManager::alertForGetDisplayMedia(WebPageProxy& page, const WebCore::SecurityOriginData& origin, CompletionHandler<void(DisplayCaptureSessionManager::CaptureSessionType)>&& completionHandler)
+{
+
+    auto webView = page.cocoaView();
+    if (!webView) {
+        completionHandler(DisplayCaptureSessionManager::CaptureSessionType::None);
+        return;
+    }
+
+    NSString *visibleOrigin = applicationVisibleNameFromOrigin(origin);
+    if (!visibleOrigin)
+        visibleOrigin = applicationVisibleName();
+
+    NSString *alertTitle = [NSString stringWithFormat:WEB_UI_NSSTRING(@"Allow “%@” to observe one of your windows or screens?", "Message for window and screen sharing prompt"), visibleOrigin];
+    auto *allowWindowButtonString = WEB_UI_NSSTRING(@"Allow Observing a Window", "Allow window button title in window and screen sharing prompt");
+    auto *allowScreenButtonString = WEB_UI_NSSTRING(@"Allow Observing a Screen", "Allow screen button title in window and screen sharing prompt");
+    auto *doNotAllowButtonString = WEB_UI_NSSTRING(@"Don’t Allow (window and screen sharing)", "Disallow button title in window and screen sharing prompt");
+
+    auto alert = adoptNS([[NSAlert alloc] init]);
+    [alert setMessageText:alertTitle];
+
+    auto *button = [alert addButtonWithTitle:allowWindowButtonString];
+    button.keyEquivalent = @"";
+
+    button = [alert addButtonWithTitle:allowScreenButtonString];
+    button.keyEquivalent = @"";
+
+    button = [alert addButtonWithTitle:doNotAllowButtonString];
+    button.keyEquivalent = @"\E";
+
+    [alert beginSheetModalForWindow:[webView window] completionHandler:[completionBlock = makeBlockPtr(WTFMove(completionHandler))](NSModalResponse returnCode) {
+        DisplayCaptureSessionManager::CaptureSessionType result = DisplayCaptureSessionManager::CaptureSessionType::None;
+        switch (returnCode) {
+        case NSAlertFirstButtonReturn:
+            result = DisplayCaptureSessionManager::CaptureSessionType::Window;
+            break;
+        case NSAlertSecondButtonReturn:
+            result = DisplayCaptureSessionManager::CaptureSessionType::Screen;
+            break;
+        case NSAlertThirdButtonReturn:
+            result = DisplayCaptureSessionManager::CaptureSessionType::None;
+            break;
+        }
+
+        completionBlock(result);
+    }];
+}
+
+std::optional<CaptureDevice> DisplayCaptureSessionManager::deviceSelectedForTesting(CaptureDevice::DeviceType deviceType)
+{
+    ASSERT(m_indexOfDeviceSelectedForTesting);
+
+    unsigned index = 0;
+    for (auto& device : RealtimeMediaSourceCenter::singleton().displayCaptureFactory().displayCaptureDeviceManager().captureDevices()) {
+        if (device.enabled() && device.type() == deviceType) {
+            if (index == m_indexOfDeviceSelectedForTesting.value())
+                return { device };
+            ++index;
+        }
+    }
+
+    return std::nullopt;
+}
+
+void DisplayCaptureSessionManager::showWindowPicker(WebPageProxy& page, const WebCore::SecurityOriginData& origin, CompletionHandler<void(std::optional<CaptureDevice>)>&& completionHandler)
+{
+    if (m_indexOfDeviceSelectedForTesting) {
+        completionHandler(deviceSelectedForTesting(CaptureDevice::DeviceType::Window));
+        return;
+    }
+
+    alertForWindowSelection(page, origin, [completionHandler = WTFMove(completionHandler)] (std::optional<String> windowID, std::optional<String> windowTitle) mutable {
+
+        if (!windowID || !windowTitle) {
+            completionHandler(std::nullopt);
+            return;
+        }
+
+        CaptureDevice device = { windowID.value(), CaptureDevice::DeviceType::Window, windowTitle.value(), emptyString(), true };
+        completionHandler({ device });
+    });
+}
+
+void DisplayCaptureSessionManager::showScreenPicker(WebPageProxy&, const WebCore::SecurityOriginData&, CompletionHandler<void(std::optional<CaptureDevice>)>&& completionHandler)
+{
+    if (m_indexOfDeviceSelectedForTesting) {
+        completionHandler(deviceSelectedForTesting(CaptureDevice::DeviceType::Screen));
+        return;
+    }
+
+    callOnMainRunLoop([completionHandler = WTFMove(completionHandler)] () mutable {
+        for (auto& device : RealtimeMediaSourceCenter::singleton().displayCaptureFactory().displayCaptureDeviceManager().captureDevices()) {
+            if (device.enabled() && device.type() == CaptureDevice::DeviceType::Screen) {
+                completionHandler({ device });
+                return;
+            }
+        }
+
+        completionHandler(std::nullopt);
+    });
+}
+#endif
+
+bool DisplayCaptureSessionManager::isAvailable()
+{
+#if HAVE(SCREEN_CAPTURE_KIT)
+    return ScreenCaptureKitCaptureSource::isAvailable();
+#else
+    return false;
+#endif
+}
+
+DisplayCaptureSessionManager& DisplayCaptureSessionManager::singleton()
+{
+    ASSERT(isMainRunLoop());
+    static NeverDestroyed<DisplayCaptureSessionManager> manager;
+    return manager;
+}
+
+DisplayCaptureSessionManager::DisplayCaptureSessionManager()
+{
+}
+
+DisplayCaptureSessionManager::~DisplayCaptureSessionManager()
+{
+}
+
+void DisplayCaptureSessionManager::promptForGetDisplayMedia(UserMediaPermissionRequestProxy::UserMediaDisplayCapturePromptType promptType, WebPageProxy& page, const WebCore::SecurityOriginData& origin, CompletionHandler<void(std::optional<CaptureDevice>)>&& completionHandler)
+{
+    ASSERT(isAvailable());
+
+#if HAVE(SCREEN_CAPTURE_KIT)
+    if (!isAvailable() || !completionHandler) {
+        completionHandler(std::nullopt);
+        return;
+    }
+
+    if (promptType == UserMediaPermissionRequestProxy::UserMediaDisplayCapturePromptType::Screen) {
+        showScreenPicker(page, origin, WTFMove(completionHandler));
+        return;
+    }
+
+    if (promptType == UserMediaPermissionRequestProxy::UserMediaDisplayCapturePromptType::Window) {
+        showWindowPicker(page, origin, WTFMove(completionHandler));
+        return;
+    }
+
+    alertForGetDisplayMedia(page, origin, [this, page = Ref { page }, origin, completionHandler = WTFMove(completionHandler)] (DisplayCaptureSessionManager::CaptureSessionType sessionType) mutable {
+        if (sessionType == CaptureSessionType::None) {
+            completionHandler(std::nullopt);
+            return;
+        }
+
+        if (sessionType == CaptureSessionType::Screen)
+            showScreenPicker(page, origin, WTFMove(completionHandler));
+        else
+            showWindowPicker(page, origin, WTFMove(completionHandler));
+    });
+#else
+    completionHandler(std::nullopt);
+#endif
+
+}
+} // namespace WebKit
+
+#endif // PLATFORM(COCOA) && ENABLE(MEDIA_STREAM)
diff --git a/Source/WebKit/UIProcess/mac/UserMediaPermissionRequestProxyMac.h b/Source/WebKit/UIProcess/mac/UserMediaPermissionRequestProxyMac.h
new file mode 100644
index 0000000..88b5106
--- /dev/null
+++ b/Source/WebKit/UIProcess/mac/UserMediaPermissionRequestProxyMac.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 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. ``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
+ * 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
+
+#include "UserMediaPermissionRequestProxy.h"
+#include <WebCore/SecurityOrigin.h>
+
+namespace WebKit {
+
+class UserMediaPermissionRequestProxyMac final : public UserMediaPermissionRequestProxy {
+public:
+    ~UserMediaPermissionRequestProxyMac() final;
+
+    UserMediaPermissionRequestProxyMac(UserMediaPermissionRequestManagerProxy&, WebCore::UserMediaRequestIdentifier, WebCore::FrameIdentifier mainFrameID, WebCore::FrameIdentifier, Ref<WebCore::SecurityOrigin>&& userMediaDocumentOrigin, Ref<WebCore::SecurityOrigin>&& topLevelDocumentOrigin, Vector<WebCore::CaptureDevice>&& audioDevices, Vector<WebCore::CaptureDevice>&& videoDevices, WebCore::MediaStreamRequest&&, CompletionHandler<void(bool)>&&);
+
+    void promptForGetDisplayMedia(UserMediaDisplayCapturePromptType) final;
+    bool canPromptForGetDisplayMedia() final;
+};
+
+
+} // namespace WebKit
diff --git a/Source/WebKit/UIProcess/mac/UserMediaPermissionRequestProxyMac.mm b/Source/WebKit/UIProcess/mac/UserMediaPermissionRequestProxyMac.mm
new file mode 100644
index 0000000..110d105
--- /dev/null
+++ b/Source/WebKit/UIProcess/mac/UserMediaPermissionRequestProxyMac.mm
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2021 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. ``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
+ * 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.
+ */
+
+#import "config.h"
+#import "UserMediaPermissionRequestProxyMac.h"
+
+#import "DisplayCaptureSessionManager.h"
+#import "UserMediaPermissionRequestManagerProxy.h"
+
+namespace WebKit {
+using namespace WebCore;
+
+Ref<UserMediaPermissionRequestProxy> UserMediaPermissionRequestProxy::create(UserMediaPermissionRequestManagerProxy& manager, UserMediaRequestIdentifier userMediaID, FrameIdentifier mainFrameID, FrameIdentifier frameID, Ref<SecurityOrigin>&& userMediaDocumentOrigin, Ref<SecurityOrigin>&& topLevelDocumentOrigin, Vector<CaptureDevice>&& audioDevices, Vector<CaptureDevice>&& videoDevices, MediaStreamRequest&& request, CompletionHandler<void(bool)>&& decisionCompletionHandler)
+{
+    return adoptRef(*new UserMediaPermissionRequestProxyMac(manager, userMediaID, mainFrameID, frameID, WTFMove(userMediaDocumentOrigin), WTFMove(topLevelDocumentOrigin), WTFMove(audioDevices), WTFMove(videoDevices), WTFMove(request), WTFMove(decisionCompletionHandler)));
+}
+
+UserMediaPermissionRequestProxyMac::UserMediaPermissionRequestProxyMac(UserMediaPermissionRequestManagerProxy& manager, UserMediaRequestIdentifier userMediaID, FrameIdentifier mainFrameID, FrameIdentifier frameID, Ref<SecurityOrigin>&& userMediaDocumentOrigin, Ref<SecurityOrigin>&& topLevelDocumentOrigin, Vector<CaptureDevice>&& audioDevices, Vector<CaptureDevice>&& videoDevices, MediaStreamRequest&& request, CompletionHandler<void(bool)>&& decisionCompletionHandler)
+    : UserMediaPermissionRequestProxy(manager, userMediaID, mainFrameID, frameID, WTFMove(userMediaDocumentOrigin), WTFMove(topLevelDocumentOrigin), WTFMove(audioDevices), WTFMove(videoDevices), WTFMove(request), WTFMove(decisionCompletionHandler))
+{
+}
+
+UserMediaPermissionRequestProxyMac::~UserMediaPermissionRequestProxyMac()
+{
+}
+
+void UserMediaPermissionRequestProxyMac::promptForGetDisplayMedia(UserMediaDisplayCapturePromptType promptType)
+{
+#if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM)
+    if (!manager())
+        return;
+
+    DisplayCaptureSessionManager::singleton().promptForGetDisplayMedia(promptType, manager()->page(), topLevelDocumentSecurityOrigin().data(), [protectedThis = Ref { *this }](std::optional<CaptureDevice> device) mutable {
+
+        if (!device) {
+            protectedThis->deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied);
+            return;
+        }
+
+        protectedThis->setEligibleVideoDeviceUIDs({ device.value() });
+        protectedThis->allow(String(), device.value().persistentId());
+    });
+#else
+    ASSERT_NOT_REACHED();
+#endif
+}
+
+bool UserMediaPermissionRequestProxyMac::canPromptForGetDisplayMedia()
+{
+#if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM)
+    return DisplayCaptureSessionManager::isAvailable();
+#else
+    return false;
+#endif
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit/WebKit.xcodeproj/project.pbxproj b/Source/WebKit/WebKit.xcodeproj/project.pbxproj
index 716c6a6..99bc337 100644
--- a/Source/WebKit/WebKit.xcodeproj/project.pbxproj
+++ b/Source/WebKit/WebKit.xcodeproj/project.pbxproj
@@ -2513,6 +2513,10 @@
 		07E19F0723D4DC880094FFB4 /* RemoteTextTrackProxy.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = RemoteTextTrackProxy.cpp; sourceTree = "<group>"; };
 		07E19F0823D533B90094FFB4 /* TextTrackPrivateRemote.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TextTrackPrivateRemote.cpp; sourceTree = "<group>"; };
 		07E19F0923D533BA0094FFB4 /* TextTrackPrivateRemote.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TextTrackPrivateRemote.h; sourceTree = "<group>"; };
+		07EF0751274593FA0066EA04 /* UserMediaPermissionRequestProxyMac.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = UserMediaPermissionRequestProxyMac.mm; sourceTree = "<group>"; };
+		07EF0752274593FA0066EA04 /* UserMediaPermissionRequestProxyMac.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UserMediaPermissionRequestProxyMac.h; sourceTree = "<group>"; };
+		07EF07582745A8160066EA04 /* DisplayCaptureSessionManager.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = DisplayCaptureSessionManager.mm; sourceTree = "<group>"; };
+		07EF07592745A8160066EA04 /* DisplayCaptureSessionManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DisplayCaptureSessionManager.h; sourceTree = "<group>"; };
 		0867D6A5FE840307C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
 		089C1667FE841158C02AAC07 /* en */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		0DCBF4D926E2ED3200EA0E07 /* WebAuthenticatorCoordinatorProxy.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = WebAuthenticatorCoordinatorProxy.mm; sourceTree = "<group>"; };
@@ -11718,6 +11722,8 @@
 			children = (
 				B878B613133428DC006888E9 /* CorrectionPanel.h */,
 				B878B614133428DC006888E9 /* CorrectionPanel.mm */,
+				07EF07592745A8160066EA04 /* DisplayCaptureSessionManager.h */,
+				07EF07582745A8160066EA04 /* DisplayCaptureSessionManager.mm */,
 				C1817362205844A900DFDA65 /* DisplayLink.cpp */,
 				C18173602058424700DFDA65 /* DisplayLink.h */,
 				31ABA79C215AF9E000C90E31 /* HighPerformanceGPUManager.h */,
@@ -11736,6 +11742,8 @@
 				CD491B101E73482100009066 /* UserMediaCaptureManagerProxy.cpp */,
 				CD491B111E73482100009066 /* UserMediaCaptureManagerProxy.h */,
 				CD491B141E7349F300009066 /* UserMediaCaptureManagerProxy.messages.in */,
+				07EF0752274593FA0066EA04 /* UserMediaPermissionRequestProxyMac.h */,
+				07EF0751274593FA0066EA04 /* UserMediaPermissionRequestProxyMac.mm */,
 				2D125C5D1857EA05003BA3CB /* ViewGestureControllerMac.mm */,
 				2D6CD118189058A500E5A4A0 /* ViewSnapshotStoreMac.mm */,
 				728E86EF1795188C0087879E /* WebColorPickerMac.h */,
diff --git a/Source/WebKit/WebProcess/cocoa/UserMediaCaptureManager.h b/Source/WebKit/WebProcess/cocoa/UserMediaCaptureManager.h
index 1e17951..7c54a2a 100644
--- a/Source/WebKit/WebProcess/cocoa/UserMediaCaptureManager.h
+++ b/Source/WebKit/WebProcess/cocoa/UserMediaCaptureManager.h
@@ -30,7 +30,7 @@
 #include "RemoteCaptureSampleManager.h"
 #include "SharedMemory.h"
 #include "WebProcessSupplement.h"
-#include <WebCore/CaptureDeviceManager.h>
+#include <WebCore/DisplayCaptureManager.h>
 #include <WebCore/RealtimeMediaSource.h>
 #include <WebCore/RealtimeMediaSourceFactory.h>
 #include <WebCore/RealtimeMediaSourceIdentifier.h>
@@ -100,12 +100,12 @@
 
     private:
         WebCore::CaptureSourceOrError createDisplayCaptureSource(const WebCore::CaptureDevice&, String&&, const WebCore::MediaConstraints*) final;
-        WebCore::CaptureDeviceManager& displayCaptureDeviceManager() final { return m_manager.m_noOpCaptureDeviceManager; }
+        WebCore::DisplayCaptureManager& displayCaptureDeviceManager() final { return m_manager.m_noOpCaptureDeviceManager; }
 
         UserMediaCaptureManager& m_manager;
     };
 
-    class NoOpCaptureDeviceManager : public WebCore::CaptureDeviceManager {
+    class NoOpCaptureDeviceManager : public WebCore::DisplayCaptureManager {
     public:
         NoOpCaptureDeviceManager() = default;
 
diff --git a/Tools/ChangeLog b/Tools/ChangeLog
index f1108a7..400fa7d 100644
--- a/Tools/ChangeLog
+++ b/Tools/ChangeLog
@@ -1,3 +1,24 @@
+2022-01-25  Eric Carlson  <eric.carlson@apple.com>
+
+        [macOS] Add new screen and window capture backend
+        https://bugs.webkit.org/show_bug.cgi?id=234029
+
+        Reviewed by Jer Noble and Youenn Fablet.
+
+        * TestWebKitAPI/SourcesCocoa.txt:
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKitCocoa/GetDisplayMediaWindowAndScreen.mm: Added.
+        (-[WindowAndScreenCaptureTestView haveStream:]):
+        (TestWebKitAPI::TEST):
+        * TestWebKitAPI/Tests/WebKitCocoa/WKWebViewUnderPageBackgroundColor.mm:
+        (TEST):
+        * TestWebKitAPI/Tests/WebKitCocoa/WebProcessTerminate.mm:
+        * TestWebKitAPI/cocoa/UserMediaCaptureUIDelegate.h:
+        * TestWebKitAPI/cocoa/UserMediaCaptureUIDelegate.mm:
+        (-[UserMediaCaptureUIDelegate init]):
+        (-[UserMediaCaptureUIDelegate setGetDisplayMediaDecision:]):
+        (-[UserMediaCaptureUIDelegate _webView:requestDisplayCapturePermissionForOrigin:initiatedByFrame:decisionHandler:]):
+
 2022-01-25  Aditya Keerthi  <akeerthi@apple.com>
 
         Disable input-security CSS property
diff --git a/Tools/TestWebKitAPI/SourcesCocoa.txt b/Tools/TestWebKitAPI/SourcesCocoa.txt
index a2d4d24..7116ed0 100644
--- a/Tools/TestWebKitAPI/SourcesCocoa.txt
+++ b/Tools/TestWebKitAPI/SourcesCocoa.txt
@@ -116,6 +116,7 @@
 Tests/WebKitCocoa/GPUProcess.mm
 Tests/WebKitCocoa/Geolocation.mm
 Tests/WebKitCocoa/GetDisplayMedia.mm
+Tests/WebKitCocoa/GetDisplayMediaWindowAndScreen.mm
 Tests/WebKitCocoa/GetResourceData.mm
 Tests/WebKitCocoa/HSTS.mm
 Tests/WebKitCocoa/IDBCheckpointWAL.mm
diff --git a/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj b/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
index 6071c12..0a34710 100644
--- a/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
+++ b/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
@@ -1654,6 +1654,7 @@
 		0451A5A6235E438E009DF945 /* BumpPointerAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BumpPointerAllocator.cpp; sourceTree = "<group>"; };
 		0711DF51226A95FB003DD2F7 /* AVFoundationSoftLinkTest.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AVFoundationSoftLinkTest.mm; sourceTree = "<group>"; };
 		07137049265320E500CA2C9A /* AudioBufferSize.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = AudioBufferSize.mm; sourceTree = "<group>"; };
+		0738012E275EADAB000FA77C /* GetDisplayMediaWindowAndScreen.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = GetDisplayMediaWindowAndScreen.mm; sourceTree = "<group>"; };
 		0746645722FF62D000E3451A /* AccessibilityTestSupportProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AccessibilityTestSupportProtocol.h; sourceTree = "<group>"; };
 		0746645822FF630500E3451A /* AccessibilityTestPlugin.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = AccessibilityTestPlugin.mm; sourceTree = "<group>"; };
 		07492B391DF8ADA400633DE1 /* enumerateMediaDevices.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = enumerateMediaDevices.html; sourceTree = "<group>"; };
@@ -3470,6 +3471,7 @@
 				CDDC7C6825FFF6D000224278 /* FullscreenRemoveNodeBeforeEnter.mm */,
 				631EFFF51E7B5E8D00D2EBB8 /* Geolocation.mm */,
 				07E1F6A01FFC3A080096C7EC /* GetDisplayMedia.mm */,
+				0738012E275EADAB000FA77C /* GetDisplayMediaWindowAndScreen.mm */,
 				2DADF26221CB8F32003D3E3A /* GetResourceData.mm */,
 				465E2806255B2A690063A787 /* GPUProcess.mm */,
 				5CB5990A269E74EC002A7CFF /* HSTS.mm */,
diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/GetDisplayMediaWindowAndScreen.mm b/Tools/TestWebKitAPI/Tests/WebKitCocoa/GetDisplayMediaWindowAndScreen.mm
new file mode 100644
index 0000000..73c2192
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKitCocoa/GetDisplayMediaWindowAndScreen.mm
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2017-2022 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.
+ */
+
+#import "config.h"
+
+#if HAVE(SCREEN_CAPTURE_KIT)
+
+#import "PlatformUtilities.h"
+#import "Test.h"
+#import "TestWKWebView.h"
+#import "UserMediaCaptureUIDelegate.h"
+#import <WebKit/WKPreferencesPrivate.h>
+#import <WebKit/WKUIDelegatePrivate.h>
+#import <WebKit/WKWebView.h>
+#import <WebKit/WKWebViewConfiguration.h>
+#import <WebKit/WKWebViewConfigurationPrivate.h>
+#import <WebKit/WKWebViewPrivateForTesting.h>
+
+@interface WindowAndScreenCaptureTestView : TestWKWebView
+- (BOOL)haveStream:(BOOL)expected;
+@end
+
+@implementation WindowAndScreenCaptureTestView
+- (BOOL)haveStream:(BOOL)expected
+{
+    int retryCount = 1000;
+    while (retryCount--) {
+        auto result = [self stringByEvaluatingJavaScript:@"haveStream()"];
+        if (result.boolValue == expected)
+            return YES;
+
+        TestWebKitAPI::Util::spinRunLoop(10);
+    }
+
+    return NO;
+}
+@end
+
+namespace TestWebKitAPI {
+
+TEST(WebKit2, GetDisplayMediaWindowAndScreenPrompt)
+{
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    auto context = adoptWK(TestWebKitAPI::Util::createContextForInjectedBundleTest("InternalsInjectedBundleTest"));
+
+    configuration.get().processPool = (WKProcessPool *)context.get();
+    configuration.get()._mediaCaptureEnabled = YES;
+
+    auto preferences = [configuration preferences];
+    preferences._mediaCaptureRequiresSecureConnection = NO;
+    preferences._mockCaptureDevicesEnabled = YES;
+    preferences._useScreenCaptureKit = YES;
+
+    auto delegate = adoptNS([[UserMediaCaptureUIDelegate alloc] init]);
+    auto webView = adoptNS([[WindowAndScreenCaptureTestView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration.get()]);
+    [webView setUIDelegate:delegate.get()];
+
+    [webView synchronouslyLoadTestPageNamed:@"getDisplayMedia"];
+
+    // Check "Don’t Allow"
+    [delegate setGetDisplayMediaDecision:WKDisplayCapturePermissionDecisionDeny];
+    [webView stringByEvaluatingJavaScript:@"promptForCapture({ video : true })"];
+    [delegate waitUntilPrompted];
+    EXPECT_TRUE([webView haveStream:NO]);
+
+    // Check "Allow Screen"
+    [webView stringByEvaluatingJavaScript:@"stop()"];
+    [delegate resetWasPrompted];
+    [webView _setIndexOfGetDisplayMediaDeviceSelectedForTesting:@0];
+    [delegate setGetDisplayMediaDecision:WKDisplayCapturePermissionDecisionScreenPrompt];
+    [webView stringByEvaluatingJavaScript:@"promptForCapture({ video : true })"];
+    [delegate waitUntilPrompted];
+    EXPECT_TRUE([webView haveStream:YES]);
+    auto label = [webView stringByEvaluatingJavaScript:@"stream.getVideoTracks()[0].label"];
+    EXPECT_WK_STREQ(label, @"Mock screen device 1");
+
+    // Check "Allow Window"
+    [webView stringByEvaluatingJavaScript:@"stop()"];
+    [delegate resetWasPrompted];
+    [webView _setIndexOfGetDisplayMediaDeviceSelectedForTesting:@0];
+    [delegate setGetDisplayMediaDecision:WKDisplayCapturePermissionDecisionWindowPrompt];
+    [webView stringByEvaluatingJavaScript:@"promptForCapture({ video : true })"];
+    [delegate waitUntilPrompted];
+    EXPECT_TRUE([webView haveStream:YES]);
+    label = [webView stringByEvaluatingJavaScript:@"stream.getVideoTracks()[0].label"];
+    EXPECT_WK_STREQ(label, @"Mock window device 1");
+
+    [webView stringByEvaluatingJavaScript:@"stop()"];
+    [webView _setIndexOfGetDisplayMediaDeviceSelectedForTesting:nil];
+}
+
+} // namespace TestWebKitAPI
+
+#endif // HAVE(SCREEN_CAPTURE_KIT)
diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/MessagePortProviders.mm b/Tools/TestWebKitAPI/Tests/WebKitCocoa/MessagePortProviders.mm
index 5486a2f..6421f60 100644
--- a/Tools/TestWebKitAPI/Tests/WebKitCocoa/MessagePortProviders.mm
+++ b/Tools/TestWebKitAPI/Tests/WebKitCocoa/MessagePortProviders.mm
@@ -27,14 +27,13 @@
 
 #if PLATFORM(MAC)
 
+#import "DeprecatedGlobalValues.h"
 #import "PlatformUtilities.h"
 #import "TestWKWebView.h"
 #import <WebKit/WKWebViewPrivate.h>
 #import <WebKit/WebFrame.h>
 #import <wtf/RetainPtr.h>
 
-static bool didFinishLoad;
-
 @interface MessagePortFrameLoadDelegate : NSObject <WebFrameLoadDelegate> {
 }
 @end
diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/PasteboardUtilities.mm b/Tools/TestWebKitAPI/Tests/WebKitCocoa/PasteboardUtilities.mm
index 9697d81..effd2a0 100644
--- a/Tools/TestWebKitAPI/Tests/WebKitCocoa/PasteboardUtilities.mm
+++ b/Tools/TestWebKitAPI/Tests/WebKitCocoa/PasteboardUtilities.mm
@@ -25,6 +25,9 @@
 
 #import "config.h"
 #import "PasteboardUtilities.h"
+#import <WebKit/WKPreferencesPrivate.h>
+#import <WebKit/WKPreferencesRefPrivate.h>
+#import <WebKit/WKWebViewConfigurationPrivate.h>
 
 #import "TestWKWebView.h"
 
diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/WebLocks.mm b/Tools/TestWebKitAPI/Tests/WebKitCocoa/WebLocks.mm
index 7fe95fe..033bd3d 100644
--- a/Tools/TestWebKitAPI/Tests/WebKitCocoa/WebLocks.mm
+++ b/Tools/TestWebKitAPI/Tests/WebKitCocoa/WebLocks.mm
@@ -31,6 +31,7 @@
 #import "TestWKWebView.h"
 #import "Utilities.h"
 #import <WebKit/WKPreferencesPrivate.h>
+#import <WebKit/WKWebViewConfigurationPrivate.h>
 #import <WebKit/WKWebViewPrivate.h>
 #import <WebKit/_WKExperimentalFeature.h>
 
diff --git a/Tools/TestWebKitAPI/cocoa/UserMediaCaptureUIDelegate.h b/Tools/TestWebKitAPI/cocoa/UserMediaCaptureUIDelegate.h
index 2c1fe96..cee515a 100644
--- a/Tools/TestWebKitAPI/cocoa/UserMediaCaptureUIDelegate.h
+++ b/Tools/TestWebKitAPI/cocoa/UserMediaCaptureUIDelegate.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 Apple Inc. All rights reserved.
+ * Copyright (C) 2021-2022 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -25,12 +25,14 @@
 
 #if ENABLE(MEDIA_STREAM)
 #import <WebKit/WKUIDelegate.h>
+#import <WebKit/WKUIDelegatePrivate.h>
 
 @interface UserMediaCaptureUIDelegate : NSObject<WKUIDelegate> {
     bool _wasPrompted;
     int _numberOfPrompts;
     WKPermissionDecision _audioDecision;
     WKPermissionDecision _videoDecision;
+    WKDisplayCapturePermissionDecision _getDisplayMediaDecision;
 }
 
 @property (readonly) BOOL wasPrompted;
@@ -42,10 +44,12 @@
 
 -(void)setAudioDecision:(WKPermissionDecision)decision;
 -(void)setVideoDecision:(WKPermissionDecision)decision;
+-(void)setGetDisplayMediaDecision:(WKDisplayCapturePermissionDecision)decision;
 
 // WKUIDelegate
 - (void)webView:(WKWebView *)webView requestMediaCapturePermissionForOrigin:(WKSecurityOrigin *)origin initiatedByFrame:(WKFrameInfo *)frame type:(WKMediaCaptureType)type decisionHandler:(void (^)(WKPermissionDecision decision))decisionHandler;
 - (void)_webView:(WKWebView *)webView checkUserMediaPermissionForURL:(NSURL *)url mainFrameURL:(NSURL *)mainFrameURL frameIdentifier:(NSUInteger)frameIdentifier decisionHandler:(void (^)(NSString *salt, BOOL authorized))decisionHandler;
+- (void)_webView:(WKWebView *)webView requestDisplayCapturePermissionForOrigin:(WKSecurityOrigin *)origin initiatedByFrame:(WKFrameInfo *)frame withSystemAudio:(BOOL)withSystemAudio decisionHandler:(void (^)(WKDisplayCapturePermissionDecision decision))decisionHandler;
 
 @end
 
diff --git a/Tools/TestWebKitAPI/cocoa/UserMediaCaptureUIDelegate.mm b/Tools/TestWebKitAPI/cocoa/UserMediaCaptureUIDelegate.mm
index a294d10..174f369 100644
--- a/Tools/TestWebKitAPI/cocoa/UserMediaCaptureUIDelegate.mm
+++ b/Tools/TestWebKitAPI/cocoa/UserMediaCaptureUIDelegate.mm
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 Apple Inc. All rights reserved.
+ * Copyright (C) 2021-2022 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -41,6 +41,7 @@
         _numberOfPrompts = 0;
         _audioDecision = WKPermissionDecisionGrant;
         _videoDecision = WKPermissionDecisionGrant;
+        _getDisplayMediaDecision = WKDisplayCapturePermissionDecisionDeny;
     }
 
     return self;
@@ -67,6 +68,10 @@
     _videoDecision = decision;
 }
 
+-(void)setGetDisplayMediaDecision:(WKDisplayCapturePermissionDecision)decision {
+    _getDisplayMediaDecision = decision;
+}
+
 - (void)webView:(WKWebView *)webView requestMediaCapturePermissionForOrigin:(WKSecurityOrigin *)origin initiatedByFrame:(WKFrameInfo *)frame type:(WKMediaCaptureType)type decisionHandler:(void (^)(WKPermissionDecision decision))decisionHandler {
     ++_numberOfPrompts;
     _wasPrompted = true;
@@ -96,6 +101,14 @@
 - (void)_webView:(WKWebView *)webView checkUserMediaPermissionForURL:(NSURL *)url mainFrameURL:(NSURL *)mainFrameURL frameIdentifier:(NSUInteger)frameIdentifier decisionHandler:(void (^)(NSString *salt, BOOL authorized))decisionHandler {
     decisionHandler(@"0x9876543210", YES);
 }
+
+- (void)_webView:(WKWebView *)webView requestDisplayCapturePermissionForOrigin:(WKSecurityOrigin *)origin initiatedByFrame:(WKFrameInfo *)frame withSystemAudio:(BOOL)withSystemAudio decisionHandler:(void (^)(WKDisplayCapturePermissionDecision decision))decisionHandler
+{
+    ++_numberOfPrompts;
+    _wasPrompted = true;
+    decisionHandler(_getDisplayMediaDecision);
+}
+
 @end
 
 #endif // ENABLE(MEDIA_STREAM)