PiP from Element Fullscreen should match AVKit's behavior
authorjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 18 Jul 2018 19:50:04 +0000 (19:50 +0000)
committerjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 18 Jul 2018 19:50:04 +0000 (19:50 +0000)
https://bugs.webkit.org/show_bug.cgi?id=187623
Source/WebCore:

Reviewed by Jon Lee.

PiP behavior should be defined at the WebKit2 level, and not in HTMLMediaElement:

* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::enterFullscreen):

Add an accessor for pictureInPictureWasStartedWhenEnteringBackground():

* platform/cocoa/VideoFullscreenModelVideoElement.mm:
(VideoFullscreenInterfaceAVKit::pictureInPictureWasStartedWhenEnteringBackground const):

Add VideoFullscreenModelClient virutal methods for PiP change notifications:

* platform/cocoa/VideoFullscreenModel.h:
(WebCore::VideoFullscreenModelClient::hasVideoChanged):
(WebCore::VideoFullscreenModelClient::videoDimensionsChanged):
(WebCore::VideoFullscreenModelClient::willEnterPictureInPicture):
(WebCore::VideoFullscreenModelClient::didEnterPictureInPicture):
(WebCore::VideoFullscreenModelClient::failedToEnterPictureInPicture):
(WebCore::VideoFullscreenModelClient::willExitPictureInPicture):
(WebCore::VideoFullscreenModelClient::didExitPictureInPicture):
(WebCore::VideoFullscreenModelClient::failedToExitPictureInPicture):
* platform/cocoa/VideoFullscreenModelVideoElement.h:
* platform/cocoa/VideoFullscreenModelVideoElement.mm:
(VideoFullscreenModelVideoElement::willEnterPictureInPicture):
(VideoFullscreenModelVideoElement::didEnterPictureInPicture):
(VideoFullscreenModelVideoElement::failedToEnterPictureInPicture):
(VideoFullscreenModelVideoElement::willExitPictureInPicture):
(VideoFullscreenModelVideoElement::didExitPictureInPicture):
(VideoFullscreenModelVideoElement::failedToExitPictureInPicture):
* platform/ios/VideoFullscreenInterfaceAVKit.h:
* platform/ios/VideoFullscreenInterfaceAVKit.mm:
(-[WebAVPlayerLayer layoutSublayers]):
(-[WebAVPlayerLayer resolveBounds]):
(-[WebAVPlayerLayer setVideoGravity:]):
(VideoFullscreenInterfaceAVKit::setupFullscreen):
(VideoFullscreenInterfaceAVKit::presentingViewController):
(VideoFullscreenInterfaceAVKit::willStartPictureInPicture):
(VideoFullscreenInterfaceAVKit::didStartPictureInPicture):
(VideoFullscreenInterfaceAVKit::failedToStartPictureInPicture):
(VideoFullscreenInterfaceAVKit::willStopPictureInPicture):
(VideoFullscreenInterfaceAVKit::didStopPictureInPicture):
(VideoFullscreenInterfaceAVKit::shouldExitFullscreenWithReason):
(VideoFullscreenInterfaceAVKit::doSetup):
* platform/ios/WebVideoFullscreenControllerAVKit.mm:
(VideoFullscreenControllerContext::willEnterPictureInPicture):
(VideoFullscreenControllerContext::didEnterPictureInPicture):
(VideoFullscreenControllerContext::failedToEnterPictureInPicture):
(VideoFullscreenControllerContext::willExitPictureInPicture):
(VideoFullscreenControllerContext::didExitPictureInPicture):
(VideoFullscreenControllerContext::failedToExitPictureInPicture):
* platform/mac/VideoFullscreenInterfaceMac.h:
(WebCore::VideoFullscreenInterfaceMac::requestHideAndExitFullscreen): Deleted.
* platform/mac/VideoFullscreenInterfaceMac.mm:
(-[WebVideoFullscreenInterfaceMacObjC invalidateFullscreenState]):
(-[WebVideoFullscreenInterfaceMacObjC exitPIP]):
(-[WebVideoFullscreenInterfaceMacObjC exitPIPAnimatingToRect:inWindow:]):
(-[WebVideoFullscreenInterfaceMacObjC pipShouldClose:]):
(-[WebVideoFullscreenInterfaceMacObjC pipDidClose:]):
(WebCore::VideoFullscreenInterfaceMac::enterFullscreen):
(WebCore::VideoFullscreenInterfaceMac::exitFullscreen):
(WebCore::VideoFullscreenInterfaceMac::exitFullscreenWithoutAnimationToMode):
(WebCore::VideoFullscreenInterfaceMac::requestHideAndExitFullscreen):

Source/WebCore/PAL:

Reviewed by Jon Lee.

* pal/spi/mac/PIPSPI.h:

Source/WebKit:

Reviewed by Jon Lee.

* UIProcess/Cocoa/PlaybackSessionManagerProxy.h:
(WebKit::PlaybackSessionManagerProxy::controlsManagerContextId const):
* UIProcess/Cocoa/VideoFullscreenManagerProxy.h:
* UIProcess/Cocoa/VideoFullscreenManagerProxy.mm:
(WebKit::VideoFullscreenModelContext::willEnterPictureInPicture):
(WebKit::VideoFullscreenModelContext::didEnterPictureInPicture):
(WebKit::VideoFullscreenModelContext::failedToEnterPictureInPicture):
(WebKit::VideoFullscreenModelContext::willExitPictureInPicture):
(WebKit::VideoFullscreenModelContext::didExitPictureInPicture):
(WebKit::VideoFullscreenModelContext::failedToExitPictureInPicture):
(WebKit::VideoFullscreenManagerProxy::controlsManagerInterface):
* UIProcess/ios/fullscreen/WKFullScreenViewController.mm:
(WKFullScreenViewControllerVideoFullscreenModelClient::setParent):
(WKFullScreenViewControllerVideoFullscreenModelClient::setInterface):
(WKFullScreenViewControllerVideoFullscreenModelClient::interface const):
(-[WKFullScreenViewController initWithWebView:]):
(-[WKFullScreenViewController dealloc]):
(-[WKFullScreenViewController videoControlsManagerDidChange]):
(-[WKFullScreenViewController ensurePiPAnimator]):
(-[WKFullScreenViewController willEnterPictureInPicture]):
(-[WKFullScreenViewController didEnterPictureInPicture]):
(-[WKFullScreenViewController failedToEnterPictureInPicture]):
(-[WKFullScreenViewController loadView]):
(-[WKFullScreenViewController viewWillAppear:]):
* UIProcess/Cocoa/WebViewImpl.mm:
(WebKit::WebViewImpl::videoControlsManagerDidChange):
* UIProcess/mac/WKFullScreenWindowController.h:
* UIProcess/mac/WKFullScreenWindowController.mm:
(WebKit::WKFullScreenWindowControllerVideoFullscreenModelClient::setParent):
(WebKit::WKFullScreenWindowControllerVideoFullscreenModelClient::setInterface):
(WebKit::WKFullScreenWindowControllerVideoFullscreenModelClient::interface const):
(-[WKFullScreenWindowController initWithWindow:webView:page:]):
(-[WKFullScreenWindowController dealloc]):
(-[WKFullScreenWindowController videoControlsManagerDidChange]):
(-[WKFullScreenWindowController willEnterPictureInPicture]):

Tools:

<rdar://problem/41212379>

Reviewed by Jon Lee.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKitCocoa/ExitFullscreenOnEnterPiP.html: Added.
* TestWebKitAPI/Tests/WebKitCocoa/ExitFullscreenOnEnterPiP.mm: Added.
(-[ExitFullscreenOnEnterPiPUIDelegate _webView:hasVideoInPictureInPictureDidChange:]):
(-[ExitFullscreenOnEnterPiPUIDelegate _webViewDidEnterFullscreen:]):
(-[ExitFullscreenOnEnterPiPUIDelegate _webViewDidExitFullscreen:]):
(TestWebKitAPI::TEST):

LayoutTests:

Reviewed by Jon Lee.

* TestExpectations:
* media/fullscreen-video-going-into-pip-expected.txt: Removed.
* media/fullscreen-video-going-into-pip.html: Removed.
* media/video-contained-in-fullscreen-element-going-into-pip-expected.txt: Removed.
* media/video-contained-in-fullscreen-element-going-into-pip.html: Removed.
* platform/mac-wk2/TestExpectations:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@233926 268f45cc-cd09-0410-ab3c-d52691b4dbfc

31 files changed:
LayoutTests/ChangeLog
LayoutTests/TestExpectations
LayoutTests/media/fullscreen-video-going-into-pip-expected.txt [deleted file]
LayoutTests/media/fullscreen-video-going-into-pip.html [deleted file]
LayoutTests/media/video-contained-in-fullscreen-element-going-into-pip-expected.txt [deleted file]
LayoutTests/media/video-contained-in-fullscreen-element-going-into-pip.html [deleted file]
LayoutTests/platform/mac-wk2/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/PAL/ChangeLog
Source/WebCore/PAL/pal/spi/mac/PIPSPI.h
Source/WebCore/html/HTMLMediaElement.cpp
Source/WebCore/platform/cocoa/VideoFullscreenModel.h
Source/WebCore/platform/cocoa/VideoFullscreenModelVideoElement.h
Source/WebCore/platform/cocoa/VideoFullscreenModelVideoElement.mm
Source/WebCore/platform/ios/VideoFullscreenInterfaceAVKit.h
Source/WebCore/platform/ios/VideoFullscreenInterfaceAVKit.mm
Source/WebCore/platform/ios/WebVideoFullscreenControllerAVKit.mm
Source/WebCore/platform/mac/VideoFullscreenInterfaceMac.h
Source/WebCore/platform/mac/VideoFullscreenInterfaceMac.mm
Source/WebKit/ChangeLog
Source/WebKit/UIProcess/Cocoa/PlaybackSessionManagerProxy.h
Source/WebKit/UIProcess/Cocoa/VideoFullscreenManagerProxy.h
Source/WebKit/UIProcess/Cocoa/VideoFullscreenManagerProxy.mm
Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm
Source/WebKit/UIProcess/ios/fullscreen/WKFullScreenViewController.mm
Source/WebKit/UIProcess/mac/WKFullScreenWindowController.h
Source/WebKit/UIProcess/mac/WKFullScreenWindowController.mm
Tools/ChangeLog
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/WebKitCocoa/ExitFullscreenOnEnterPiP.html [new file with mode: 0644]
Tools/TestWebKitAPI/Tests/WebKitCocoa/ExitFullscreenOnEnterPiP.mm [new file with mode: 0644]

index dc2426e..ae9c3a0 100644 (file)
@@ -1,3 +1,17 @@
+2018-07-18  Jer Noble  <jer.noble@apple.com>
+
+        PiP from Element Fullscreen should match AVKit's behavior
+        https://bugs.webkit.org/show_bug.cgi?id=187623
+
+        Reviewed by Jon Lee.
+
+        * TestExpectations:
+        * media/fullscreen-video-going-into-pip-expected.txt: Removed.
+        * media/fullscreen-video-going-into-pip.html: Removed.
+        * media/video-contained-in-fullscreen-element-going-into-pip-expected.txt: Removed.
+        * media/video-contained-in-fullscreen-element-going-into-pip.html: Removed.
+        * platform/mac-wk2/TestExpectations:
+
 2018-07-18  Truitt Savell  <tsavell@apple.com>
 
        [ WK2 ] Layout Test http/wpt/service-workers/update-service-worker.https.html is a flaky Timeout
index 0265dfc..01e7e0a 100644 (file)
@@ -1446,10 +1446,8 @@ media/controls/picture-in-picture.html [ WontFix ]
 media/controls/pip-placeholder-without-video-controls.html [ WontFix ]
 media/element-containing-pip-video-going-into-fullscreen.html [ WontFix ]
 media/fullscreen-api-enabled-media-with-presentation-mode.html [ WontFix ]
-media/fullscreen-video-going-into-pip.html [ WontFix ]
 media/navigate-with-pip-should-not-crash.html [ WontFix ]
 media/pip-video-going-into-fullscreen.html [ WontFix ]
-media/video-contained-in-fullscreen-element-going-into-pip.html [ WontFix ]
 
 webkit.org/b/159370 [ Debug ] fast/history/page-cache-destroy-document.html [ Skip ]
 
diff --git a/LayoutTests/media/fullscreen-video-going-into-pip-expected.txt b/LayoutTests/media/fullscreen-video-going-into-pip-expected.txt
deleted file mode 100644 (file)
index d9bba6f..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-Tests fullscreen video going into pip should exit fullscreen
-
-Going into Full Screen
-EXPECTED (document.webkitCurrentFullScreenElement == '[object HTMLVideoElement]') OK
-Going into Picture-in-Picture from Full Screen
-Entered Picture-in-Picture from Full Screen
-EXPECTED (document.webkitCurrentFullScreenElement == 'null') OK
-END OF TEST
-
diff --git a/LayoutTests/media/fullscreen-video-going-into-pip.html b/LayoutTests/media/fullscreen-video-going-into-pip.html
deleted file mode 100644 (file)
index 7f65479..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-<html>
-<head>
-    <title>Test fullscreen video going into pip should exit fullscreen</title>
-    <script src="media-file.js"></script>
-    <script src="video-test.js"></script>
-    <script>
-        if (window.internals)
-            window.internals.settings.setAllowsPictureInPictureMediaPlayback(true);
-
-        function init()
-        {
-            findMediaElement();
-            video.addEventListener('canplaythrough', oncanplaythrough);
-            video.src = findMediaFile('video', 'content/test');
-        }
-
-        function oncanplaythrough()
-        {
-            if (!('webkitSupportsPresentationMode' in video && 'webkitPresentationMode' in video)) {
-                failTest("Presentation mode is not supported in this video element.")
-                return;
-            }
-
-            consoleWrite("Going into Full Screen");
-            video.addEventListener('webkitpresentationmodechanged', onfullscreenchange);
-            runWithKeyDown(function(){ video.webkitRequestFullscreen(); });
-        }
-
-        function onfullscreenchange()
-        {
-            testExpected("document.webkitCurrentFullScreenElement", video);
-            video.removeEventListener('webkitpresentationmodechanged', onfullscreenchange);
-
-            consoleWrite("Going into Picture-in-Picture from Full Screen");
-            video.addEventListener('webkitpresentationmodechanged', onpresentationmodechanged);
-            runWithKeyDown(function() { video.webkitSetPresentationMode("picture-in-picture"); });
-        }
-
-        function onpresentationmodechanged()
-        {
-            consoleWrite("Entered Picture-in-Picture from Full Screen");
-            testExpected("document.webkitCurrentFullScreenElement", null);
-
-            endTest();
-        }
-
-    </script>
-</head>
-<body onload="init()">
-    Tests fullscreen video going into pip should exit fullscreen<br>
-    <video controls></video>
-</body>
-</html>
-
diff --git a/LayoutTests/media/video-contained-in-fullscreen-element-going-into-pip-expected.txt b/LayoutTests/media/video-contained-in-fullscreen-element-going-into-pip-expected.txt
deleted file mode 100644 (file)
index d5f057f..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-Tests video contained in fullscreen element going into pip should exit fullscreen
-
-Container div going into Full Screen
-EXPECTED (document.webkitCurrentFullScreenElement == '[object HTMLDivElement]') OK
-EXPECTED (video.webkitPresentationMode == 'inline') OK
-Video going into Picture-in-Picture
-Entered Picture-in-Picture from Full Screen
-EXPECTED (document.webkitCurrentFullScreenElement == 'null') OK
-EXPECTED (video.webkitPresentationMode == 'picture-in-picture') OK
-END OF TEST
-
diff --git a/LayoutTests/media/video-contained-in-fullscreen-element-going-into-pip.html b/LayoutTests/media/video-contained-in-fullscreen-element-going-into-pip.html
deleted file mode 100644 (file)
index 32f5c36..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-<html>
-<head>
-    <title>Test video contained in fullscreen element going into pip should exit fullscreen</title>
-    <script src="media-file.js"></script>
-    <script src="video-test.js"></script>
-    <script>
-        if (window.internals)
-            window.internals.settings.setAllowsPictureInPictureMediaPlayback(true);
-
-        function init()
-        {
-            findMediaElement();
-            video.addEventListener('canplaythrough', oncanplaythrough);
-            video.src = findMediaFile('video', 'content/test');
-        }
-
-        function oncanplaythrough()
-        {
-            if (!('webkitSupportsPresentationMode' in video && 'webkitPresentationMode' in video)) {
-                failTest("Presentation mode is not supported in this video element.")
-                return;
-            }
-
-            consoleWrite("Container div going into Full Screen");
-            videoContainer.addEventListener('webkitfullscreenchange', onfullscreenchange);
-            runWithKeyDown(function(){ videoContainer.webkitRequestFullscreen(); });
-        }
-
-        function onfullscreenchange()
-        {
-            testExpected("document.webkitCurrentFullScreenElement", videoContainer);
-            testExpected("video.webkitPresentationMode", "inline")
-
-            videoContainer.removeEventListener('webkitfullscreenchange', onfullscreenchange);
-
-            consoleWrite("Video going into Picture-in-Picture");
-            video.addEventListener('webkitpresentationmodechanged', onpresentationmodechanged);
-            runWithKeyDown(function() { video.webkitSetPresentationMode("picture-in-picture"); });
-        }
-
-        function onpresentationmodechanged()
-        {
-            consoleWrite("Entered Picture-in-Picture from Full Screen");
-            testExpected("document.webkitCurrentFullScreenElement", null);
-            testExpected("video.webkitPresentationMode", "picture-in-picture");
-
-            endTest();
-        }
-
-    </script>
-</head>
-<body onload="init()">
-    Tests video contained in fullscreen element going into pip should exit fullscreen<br>
-    <div id="videoContainer">
-        <video controls></video>
-    </div>
-</body>
-</html>
-
index ec7c34b..2c2186a 100644 (file)
@@ -547,10 +547,8 @@ webkit.org/b/158237 fast/scrolling/scroll-container-horizontally.html [ Pass Tim
 webkit.org/b/170620 [ Sierra+ ] media/controls/pip-placeholder-without-video-controls.html [ Pass Failure ]
 [ Sierra+ ] media/element-containing-pip-video-going-into-fullscreen.html [ Pass Timeout ]
 webkit.org/b/172998 [ Sierra+ ] media/fullscreen-api-enabled-media-with-presentation-mode.html [ Failure ]
-[ Sierra+ ] media/fullscreen-video-going-into-pip.html [ Pass ]
 webkit.org/b/173199 [ Sierra+ ] media/navigate-with-pip-should-not-crash.html [ Pass Failure ]
 [ Sierra+ ] media/pip-video-going-into-fullscreen.html [ Pass ]
-[ Sierra+ ] media/video-contained-in-fullscreen-element-going-into-pip.html [ Pass ]
 
 # RTL Scrollbars are enabled on Sierra WebKit2.
 webkit.org/b/179455 [ Sierra+ ] fast/scrolling/rtl-scrollbars.html [ Pass ImageOnlyFailure ]
index 34a16ae..868edda 100644 (file)
@@ -1,3 +1,73 @@
+2018-07-18  Jer Noble  <jer.noble@apple.com>
+
+        PiP from Element Fullscreen should match AVKit's behavior
+        https://bugs.webkit.org/show_bug.cgi?id=187623
+
+        Reviewed by Jon Lee.
+
+        PiP behavior should be defined at the WebKit2 level, and not in HTMLMediaElement:
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::enterFullscreen):
+
+        Add an accessor for pictureInPictureWasStartedWhenEnteringBackground():
+
+        * platform/cocoa/VideoFullscreenModelVideoElement.mm:
+        (VideoFullscreenInterfaceAVKit::pictureInPictureWasStartedWhenEnteringBackground const):
+
+        Add VideoFullscreenModelClient virutal methods for PiP change notifications:
+
+        * platform/cocoa/VideoFullscreenModel.h:
+        (WebCore::VideoFullscreenModelClient::hasVideoChanged):
+        (WebCore::VideoFullscreenModelClient::videoDimensionsChanged):
+        (WebCore::VideoFullscreenModelClient::willEnterPictureInPicture):
+        (WebCore::VideoFullscreenModelClient::didEnterPictureInPicture):
+        (WebCore::VideoFullscreenModelClient::failedToEnterPictureInPicture):
+        (WebCore::VideoFullscreenModelClient::willExitPictureInPicture):
+        (WebCore::VideoFullscreenModelClient::didExitPictureInPicture):
+        (WebCore::VideoFullscreenModelClient::failedToExitPictureInPicture):
+        * platform/cocoa/VideoFullscreenModelVideoElement.h:
+        * platform/cocoa/VideoFullscreenModelVideoElement.mm:
+        (VideoFullscreenModelVideoElement::willEnterPictureInPicture):
+        (VideoFullscreenModelVideoElement::didEnterPictureInPicture):
+        (VideoFullscreenModelVideoElement::failedToEnterPictureInPicture):
+        (VideoFullscreenModelVideoElement::willExitPictureInPicture):
+        (VideoFullscreenModelVideoElement::didExitPictureInPicture):
+        (VideoFullscreenModelVideoElement::failedToExitPictureInPicture):
+        * platform/ios/VideoFullscreenInterfaceAVKit.h:
+        * platform/ios/VideoFullscreenInterfaceAVKit.mm:
+        (-[WebAVPlayerLayer layoutSublayers]):
+        (-[WebAVPlayerLayer resolveBounds]):
+        (-[WebAVPlayerLayer setVideoGravity:]):
+        (VideoFullscreenInterfaceAVKit::setupFullscreen):
+        (VideoFullscreenInterfaceAVKit::presentingViewController):
+        (VideoFullscreenInterfaceAVKit::willStartPictureInPicture):
+        (VideoFullscreenInterfaceAVKit::didStartPictureInPicture):
+        (VideoFullscreenInterfaceAVKit::failedToStartPictureInPicture):
+        (VideoFullscreenInterfaceAVKit::willStopPictureInPicture):
+        (VideoFullscreenInterfaceAVKit::didStopPictureInPicture):
+        (VideoFullscreenInterfaceAVKit::shouldExitFullscreenWithReason):
+        (VideoFullscreenInterfaceAVKit::doSetup):
+        * platform/ios/WebVideoFullscreenControllerAVKit.mm:
+        (VideoFullscreenControllerContext::willEnterPictureInPicture):
+        (VideoFullscreenControllerContext::didEnterPictureInPicture):
+        (VideoFullscreenControllerContext::failedToEnterPictureInPicture):
+        (VideoFullscreenControllerContext::willExitPictureInPicture):
+        (VideoFullscreenControllerContext::didExitPictureInPicture):
+        (VideoFullscreenControllerContext::failedToExitPictureInPicture):
+        * platform/mac/VideoFullscreenInterfaceMac.h:
+        (WebCore::VideoFullscreenInterfaceMac::requestHideAndExitFullscreen): Deleted.
+        * platform/mac/VideoFullscreenInterfaceMac.mm:
+        (-[WebVideoFullscreenInterfaceMacObjC invalidateFullscreenState]):
+        (-[WebVideoFullscreenInterfaceMacObjC exitPIP]):
+        (-[WebVideoFullscreenInterfaceMacObjC exitPIPAnimatingToRect:inWindow:]):
+        (-[WebVideoFullscreenInterfaceMacObjC pipShouldClose:]):
+        (-[WebVideoFullscreenInterfaceMacObjC pipDidClose:]):
+        (WebCore::VideoFullscreenInterfaceMac::enterFullscreen):
+        (WebCore::VideoFullscreenInterfaceMac::exitFullscreen):
+        (WebCore::VideoFullscreenInterfaceMac::exitFullscreenWithoutAnimationToMode):
+        (WebCore::VideoFullscreenInterfaceMac::requestHideAndExitFullscreen):
+
 2018-07-18  Basuke Suzuki  <Basuke.Suzuki@sony.com>
 
         [Curl] Disable CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST specified by setAllowsAnyHTTPSCertificate.
index 7864911..69d299b 100644 (file)
@@ -1,3 +1,12 @@
+2018-07-18  Jer Noble  <jer.noble@apple.com>
+
+        PiP from Element Fullscreen should match AVKit's behavior
+        https://bugs.webkit.org/show_bug.cgi?id=187623
+
+        Reviewed by Jon Lee.
+
+        * pal/spi/mac/PIPSPI.h:
+
 2018-07-14  Kocsen Chung  <kocsen_chung@apple.com>
 
         Ensure WebKit stack is ad-hoc signed
index b4af134..631eb9b 100644 (file)
@@ -49,6 +49,7 @@ NS_ASSUME_NONNULL_BEGIN
 @protocol PIPViewControllerDelegate <NSObject>
 @optional
 - (BOOL)pipShouldClose:(PIPViewController *)pip;
+- (void)pipWillClose:(PIPViewController *)pip;
 - (void)pipDidClose:(PIPViewController *)pip;
 - (void)pipActionPlay:(PIPViewController *)pip;
 - (void)pipActionPause:(PIPViewController *)pip;
index 2fe9753..280d166 100644 (file)
@@ -5918,22 +5918,10 @@ void HTMLMediaElement::enterFullscreen(VideoFullscreenMode mode)
     m_temporarilyAllowingInlinePlaybackAfterFullscreen = false;
     m_waitingToEnterFullscreen = true;
 
-#if ENABLE(FULLSCREEN_API)
-    if (document().settings().fullScreenEnabled()) {
-#if ENABLE(VIDEO_USES_ELEMENT_FULLSCREEN)
-        if (mode == VideoFullscreenModeStandard) {
-            document().requestFullScreenForElement(this, Document::ExemptIFrameAllowFullScreenRequirement);
-            return;
-        }
-#endif
-
-        // If this media element is not going to standard fullscreen mode but there's
-        // an element that's currently in full screen in the document, exit full screen
-        // if it contains this media element.
-        if (RefPtr<Element> fullscreenElement = document().webkitCurrentFullScreenElement()) {
-            if (fullscreenElement->contains(this))
-                document().webkitCancelFullScreen();
-        }
+#if ENABLE(FULLSCREEN_API) && ENABLE(VIDEO_USES_ELEMENT_FULLSCREEN)
+    if (document().settings().fullScreenEnabled() && mode == VideoFullscreenModeStandard) {
+        document().requestFullScreenForElement(this, Document::ExemptIFrameAllowFullScreenRequirement);
+        return;
     }
 #endif
 
index da52175..ce51354 100644 (file)
@@ -57,6 +57,12 @@ public:
     virtual FloatSize videoDimensions() const = 0;
     virtual bool hasVideo() const = 0;
 
+    virtual void willEnterPictureInPicture() = 0;
+    virtual void didEnterPictureInPicture() = 0;
+    virtual void failedToEnterPictureInPicture() = 0;
+    virtual void willExitPictureInPicture() = 0;
+    virtual void didExitPictureInPicture() = 0;
+
 #if PLATFORM(IOS)
     virtual UIViewController *presentingViewController() { return nullptr; }
     virtual UIViewController *createVideoFullscreenViewController(AVPlayerViewController *) { return nullptr; }
@@ -66,8 +72,13 @@ public:
 class VideoFullscreenModelClient {
 public:
     virtual ~VideoFullscreenModelClient() = default;
-    virtual void hasVideoChanged(bool) = 0;
-    virtual void videoDimensionsChanged(const FloatSize&) = 0;
+    virtual void hasVideoChanged(bool) { };
+    virtual void videoDimensionsChanged(const FloatSize&) { };
+    virtual void willEnterPictureInPicture() { }
+    virtual void didEnterPictureInPicture() { }
+    virtual void failedToEnterPictureInPicture() { }
+    virtual void willExitPictureInPicture() { }
+    virtual void didExitPictureInPicture() { }
 };
 
 WEBCORE_EXPORT bool supportsPictureInPicture();
index 36b1857..037dd02 100644 (file)
@@ -80,6 +80,12 @@ private:
     void setHasVideo(bool);
     void setVideoDimensions(const FloatSize&);
 
+    void willEnterPictureInPicture() override;
+    void didEnterPictureInPicture() override;
+    void failedToEnterPictureInPicture() override;
+    void willExitPictureInPicture() override;
+    void didExitPictureInPicture() override;
+
     static const Vector<WTF::AtomicString>& observedEventNames();
     const WTF::AtomicString& eventNameAll();
 
index c3f7dee..c0a4fa5 100644 (file)
@@ -240,4 +240,34 @@ void VideoFullscreenModelVideoElement::setVideoDimensions(const FloatSize& video
         client->videoDimensionsChanged(m_videoDimensions);
 }
 
+void VideoFullscreenModelVideoElement::willEnterPictureInPicture()
+{
+    for (auto& client : m_clients)
+        client->willEnterPictureInPicture();
+}
+
+void VideoFullscreenModelVideoElement::didEnterPictureInPicture()
+{
+    for (auto& client : m_clients)
+        client->didEnterPictureInPicture();
+}
+
+void VideoFullscreenModelVideoElement::failedToEnterPictureInPicture()
+{
+    for (auto& client : m_clients)
+        client->failedToEnterPictureInPicture();
+}
+
+void VideoFullscreenModelVideoElement::willExitPictureInPicture()
+{
+    for (auto& client : m_clients)
+        client->willExitPictureInPicture();
+}
+
+void VideoFullscreenModelVideoElement::didExitPictureInPicture()
+{
+    for (auto& client : m_clients)
+        client->didExitPictureInPicture();
+}
+
 #endif
index b47deda..c6d2ead 100644 (file)
@@ -58,16 +58,17 @@ class FloatSize;
 class VideoFullscreenModel;
 class VideoFullscreenChangeObserver;
     
-class WEBCORE_EXPORT VideoFullscreenInterfaceAVKit final
+class VideoFullscreenInterfaceAVKit final
     : public VideoFullscreenModelClient
     , public PlaybackSessionModelClient
     , public ThreadSafeRefCounted<VideoFullscreenInterfaceAVKit> {
 
 public:
-    static Ref<VideoFullscreenInterfaceAVKit> create(PlaybackSessionInterfaceAVKit&);
+    WEBCORE_EXPORT static Ref<VideoFullscreenInterfaceAVKit> create(PlaybackSessionInterfaceAVKit&);
     virtual ~VideoFullscreenInterfaceAVKit();
     WEBCORE_EXPORT void setVideoFullscreenModel(VideoFullscreenModel*);
     WEBCORE_EXPORT void setVideoFullscreenChangeObserver(VideoFullscreenChangeObserver*);
+    PlaybackSessionInterfaceAVKit& playbackSessionInterface() const { return m_playbackSessionInterface.get(); }
     PlaybackSessionModel* playbackSessionModel() const { return m_playbackSessionInterface->playbackSessionModel(); }
 
     // VideoFullscreenModelClient
@@ -130,14 +131,14 @@ public:
     Mode m_targetMode;
 #endif
 
-    VideoFullscreenModel* model() const { return m_videoFullscreenModel; }
+    VideoFullscreenModel* videoFullscreenModel() const { return m_videoFullscreenModel; }
     bool shouldExitFullscreenWithReason(ExitFullScreenReason);
     HTMLMediaElementEnums::VideoFullscreenMode mode() const { return m_currentMode.mode(); }
     bool allowsPictureInPicturePlayback() const { return m_allowsPictureInPicturePlayback; }
     WEBCORE_EXPORT bool mayAutomaticallyShowVideoPictureInPicture() const;
     void fullscreenMayReturnToInline(WTF::Function<void(bool)>&& callback);
     bool wirelessVideoPlaybackDisabled() const;
-    void applicationDidBecomeActive();
+    WEBCORE_EXPORT void applicationDidBecomeActive();
 
     void willStartPictureInPicture();
     void didStartPictureInPicture();
@@ -151,7 +152,7 @@ public:
 #endif
     bool isPlayingVideoInEnhancedFullscreen() const;
 
-    void setMode(HTMLMediaElementEnums::VideoFullscreenMode);
+    WEBCORE_EXPORT void setMode(HTMLMediaElementEnums::VideoFullscreenMode);
     void clearMode(HTMLMediaElementEnums::VideoFullscreenMode);
     bool hasMode(HTMLMediaElementEnums::VideoFullscreenMode mode) const { return m_currentMode.hasMode(mode); }
 
@@ -159,6 +160,7 @@ public:
     UIViewController *presentingViewController();
     UIViewController *fullscreenViewController() const { return m_viewController.get(); }
     WebAVPlayerLayerView* playerLayerView() const { return m_playerLayerView.get(); }
+    WEBCORE_EXPORT bool pictureInPictureWasStartedWhenEnteringBackground() const;
 #endif
 
 protected:
index a755d1b..6dcbd6e 100644 (file)
@@ -289,8 +289,8 @@ static VideoFullscreenInterfaceAVKit::ExitFullScreenReason convertToExitFullScre
     } else if ([getAVLayerVideoGravityResizeAspectFill() isEqualToString:self.videoGravity]) {
         sourceVideoFrame = smallestRectWithAspectRatioAroundRect(videoAspectRatio, self.modelVideoLayerFrame);
         self.modelVideoLayerFrame = CGRectMake(0, 0, sourceVideoFrame.width(), sourceVideoFrame.height());
-        ASSERT(_fullscreenInterface->model());
-        _fullscreenInterface->model()->setVideoLayerFrame(self.modelVideoLayerFrame);
+        ASSERT(_fullscreenInterface->videoFullscreenModel());
+        _fullscreenInterface->videoFullscreenModel()->setVideoLayerFrame(self.modelVideoLayerFrame);
         targetVideoFrame = smallestRectWithAspectRatioAroundRect(videoAspectRatio, self.bounds);
     } else
         ASSERT_NOT_REACHED();
@@ -325,8 +325,8 @@ static VideoFullscreenInterfaceAVKit::ExitFullScreenReason convertToExitFullScre
     
     if (!CGRectEqualToRect(self.modelVideoLayerFrame, [self bounds])) {
         self.modelVideoLayerFrame = [self bounds];
-        ASSERT(_fullscreenInterface->model());
-        _fullscreenInterface->model()->setVideoLayerFrame(self.modelVideoLayerFrame);
+        ASSERT(_fullscreenInterface->videoFullscreenModel());
+        _fullscreenInterface->videoFullscreenModel()->setVideoLayerFrame(self.modelVideoLayerFrame);
     }
     [(UIView *)[_videoSublayer delegate] setTransform:CGAffineTransformIdentity];
     
@@ -350,8 +350,8 @@ static VideoFullscreenInterfaceAVKit::ExitFullScreenReason convertToExitFullScre
     else
         ASSERT_NOT_REACHED();
     
-    ASSERT(_fullscreenInterface->model());
-    _fullscreenInterface->model()->setVideoLayerGravity(gravity);
+    ASSERT(_fullscreenInterface->videoFullscreenModel());
+    _fullscreenInterface->videoFullscreenModel()->setVideoLayerGravity(gravity);
 }
 
 - (NSString *)videoGravity
@@ -797,6 +797,11 @@ void VideoFullscreenInterfaceAVKit::externalPlaybackChanged(bool enabled, Playba
     [m_playerLayerView setHidden:enabled];
 }
 
+BOOL VideoFullscreenInterfaceAVKit::pictureInPictureWasStartedWhenEnteringBackground() const
+{
+    return [m_playerViewController pictureInPictureWasStartedWhenEnteringBackground];
+}
+
 #if !ENABLE(FULLSCREEN_API)
 
 void VideoFullscreenInterfaceAVKit::applicationDidBecomeActive()
@@ -879,7 +884,7 @@ void VideoFullscreenInterfaceAVKit::setupFullscreen(UIView& videoView, const Int
     [playerController() setPictureInPicturePossible:m_allowsPictureInPicturePlayback];
 
 #if PLATFORM(WATCHOS)
-    m_viewController = model()->createVideoFullscreenViewController(m_playerViewController.get().avPlayerViewController);
+    m_viewController = videoFullscreenModel()->createVideoFullscreenViewController(m_playerViewController.get().avPlayerViewController);
 #endif
 
     if (m_viewController) {
@@ -944,7 +949,7 @@ static UIViewController *fallbackViewController(UIView *view)
 
 UIViewController *VideoFullscreenInterfaceAVKit::presentingViewController()
 {
-    auto *controller = model()->presentingViewController();
+    auto *controller = videoFullscreenModel()->presentingViewController();
     if (!controller)
         controller = fallbackViewController(m_parentView.get());
 
@@ -1134,16 +1139,18 @@ void VideoFullscreenInterfaceAVKit::willStartPictureInPicture()
 {
     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::willStartPictureInPicture(%p)", this);
     setMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
+    if (m_videoFullscreenModel)
+        m_videoFullscreenModel->willEnterPictureInPicture();
 }
 
 void VideoFullscreenInterfaceAVKit::didStartPictureInPicture()
 {
     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::didStartPictureInPicture(%p)", this);
-    m_shouldReturnToFullscreenAfterEnteringForeground = [m_playerViewController pictureInPictureWasStartedWhenEnteringBackground];
+    m_shouldReturnToFullscreenAfterEnteringForeground = pictureInPictureWasStartedWhenEnteringBackground();
     [m_playerViewController setShowsPlaybackControls:YES];
 
     if (m_currentMode.hasFullscreen()) {
-        if (![m_playerViewController pictureInPictureWasStartedWhenEnteringBackground]) {
+        if (!pictureInPictureWasStartedWhenEnteringBackground()) {
             [[m_playerViewController view] layoutIfNeeded];
             [m_playerViewController exitFullScreenAnimated:YES completionHandler:[protectedThis = makeRefPtr(this), this] (BOOL success, NSError* error) {
                 if (!success)
@@ -1159,6 +1166,8 @@ void VideoFullscreenInterfaceAVKit::didStartPictureInPicture()
 
     if (m_fullscreenChangeObserver)
         m_fullscreenChangeObserver->didEnterFullscreen();
+    if (m_videoFullscreenModel)
+        m_videoFullscreenModel->didEnterPictureInPicture();
 }
 
 void VideoFullscreenInterfaceAVKit::failedToStartPictureInPicture()
@@ -1173,6 +1182,8 @@ void VideoFullscreenInterfaceAVKit::failedToStartPictureInPicture()
 
     if (m_fullscreenChangeObserver)
         m_fullscreenChangeObserver->didEnterFullscreen();
+    if (m_videoFullscreenModel)
+        m_videoFullscreenModel->failedToEnterPictureInPicture();
 
     if (m_videoFullscreenModel)
         m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
@@ -1193,6 +1204,8 @@ void VideoFullscreenInterfaceAVKit::willStopPictureInPicture()
 
     if (m_videoFullscreenModel)
         m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
+    if (m_videoFullscreenModel)
+        m_videoFullscreenModel->willExitPictureInPicture();
 }
 
 void VideoFullscreenInterfaceAVKit::didStopPictureInPicture()
@@ -1215,6 +1228,8 @@ void VideoFullscreenInterfaceAVKit::didStopPictureInPicture()
 
     if (m_fullscreenChangeObserver)
         m_fullscreenChangeObserver->didExitFullscreen();
+    if (m_videoFullscreenModel)
+        m_videoFullscreenModel->didExitPictureInPicture();
 }
 
 void VideoFullscreenInterfaceAVKit::prepareForPictureInPictureStopWithCompletionHandler(void (^completionHandler)(BOOL restored))
@@ -1255,7 +1270,7 @@ bool VideoFullscreenInterfaceAVKit::shouldExitFullscreenWithReason(VideoFullscre
         return true;
 
     if (reason == ExitFullScreenReason::PictureInPictureStarted) {
-        if ([m_playerViewController pictureInPictureWasStartedWhenEnteringBackground])
+        if (pictureInPictureWasStartedWhenEnteringBackground())
             return false;
 
         m_shouldReturnToFullscreenWhenStoppingPiP = m_currentMode.hasFullscreen();
@@ -1430,6 +1445,8 @@ void VideoFullscreenInterfaceAVKit::willStartPictureInPicture()
 
     if (!m_hasVideoContentLayer)
         m_fullscreenChangeObserver->requestVideoContentLayer();
+    if (m_videoFullscreenModel)
+        m_videoFullscreenModel->willEnterPictureInPicture();
 }
 
 void VideoFullscreenInterfaceAVKit::didStartPictureInPicture()
@@ -1449,6 +1466,9 @@ void VideoFullscreenInterfaceAVKit::didStartPictureInPicture()
         [[m_playerViewController view] setHidden:YES];
     }
 
+    if (m_videoFullscreenModel)
+        m_videoFullscreenModel->didEnterPictureInPicture();
+
     if (m_enterFullscreenNeedsEnterPictureInPicture)
         doEnterFullscreen();
 }
@@ -1466,6 +1486,9 @@ void VideoFullscreenInterfaceAVKit::failedToStartPictureInPicture()
         m_fullscreenChangeObserver->didEnterFullscreen();
 
     if (m_videoFullscreenModel)
+        m_videoFullscreenModel->failedToEnterPictureInPicture();
+
+    if (m_videoFullscreenModel)
         m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
 }
 
@@ -1480,6 +1503,9 @@ void VideoFullscreenInterfaceAVKit::willStopPictureInPicture()
 
     [m_window setHidden:NO];
     [[m_playerViewController view] setHidden:NO];
+
+    if (m_videoFullscreenModel)
+        m_videoFullscreenModel->willExitPictureInPicture();
 }
 
 void VideoFullscreenInterfaceAVKit::didStopPictureInPicture()
@@ -1504,6 +1530,9 @@ void VideoFullscreenInterfaceAVKit::didStopPictureInPicture()
 
     clearMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
 
+    if (m_videoFullscreenModel)
+        m_videoFullscreenModel->didExitPictureInPicture();
+
     if (m_enterFullscreenNeedsExitPictureInPicture)
         doEnterFullscreen();
 
@@ -1653,7 +1682,7 @@ void VideoFullscreenInterfaceAVKit::doSetup()
     [playerController() setPictureInPicturePossible:m_allowsPictureInPicturePlayback];
 
 #if PLATFORM(WATCHOS)
-    m_viewController = model()->createVideoFullscreenViewController(m_playerViewController.get().avPlayerViewController);
+    m_viewController = videoFullscreenModel()->createVideoFullscreenViewController(m_playerViewController.get().avPlayerViewController);
 #endif
 
     if (m_viewController) {
index 72b8448..3efbb17 100644 (file)
@@ -202,6 +202,11 @@ private:
     bool isMuted() const override;
     double volume() const override;
     bool isPictureInPictureActive() const override;
+    void willEnterPictureInPicture() final;
+    void didEnterPictureInPicture() final;
+    void failedToEnterPictureInPicture() final;
+    void willExitPictureInPicture() final;
+    void didExitPictureInPicture() final;
 
     HashSet<PlaybackSessionModelClient*> m_playbackClients;
     HashSet<VideoFullscreenModelClient*> m_fullscreenClients;
@@ -627,6 +632,41 @@ bool VideoFullscreenControllerContext::isPictureInPictureActive() const
     return m_playbackModel ? m_playbackModel->isPictureInPictureActive() : false;
 }
 
+void VideoFullscreenControllerContext::willEnterPictureInPicture()
+{
+    ASSERT(isUIThread());
+    for (auto* client : m_fullscreenClients)
+        client->willEnterPictureInPicture();
+}
+
+void VideoFullscreenControllerContext::didEnterPictureInPicture()
+{
+    ASSERT(isUIThread());
+    for (auto* client : m_fullscreenClients)
+        client->didEnterPictureInPicture();
+}
+
+void VideoFullscreenControllerContext::failedToEnterPictureInPicture()
+{
+    ASSERT(isUIThread());
+    for (auto* client : m_fullscreenClients)
+        client->failedToEnterPictureInPicture();
+}
+
+void VideoFullscreenControllerContext::willExitPictureInPicture()
+{
+    ASSERT(isUIThread());
+    for (auto* client : m_fullscreenClients)
+        client->willExitPictureInPicture();
+}
+
+void VideoFullscreenControllerContext::didExitPictureInPicture()
+{
+    ASSERT(isUIThread());
+    for (auto* client : m_fullscreenClients)
+        client->didExitPictureInPicture();
+}
+
 FloatSize VideoFullscreenControllerContext::videoDimensions() const
 {
     ASSERT(isUIThread());
index 5e48eaa..8b68c6b 100644 (file)
@@ -44,7 +44,7 @@ class FloatSize;
 class PlaybackSessionInterfaceMac;
 class VideoFullscreenChangeObserver;
 
-class WEBCORE_EXPORT VideoFullscreenInterfaceMac
+class VideoFullscreenInterfaceMac
     : public VideoFullscreenModelClient
     , private PlaybackSessionModelClient
     , public RefCounted<VideoFullscreenInterfaceMac> {
@@ -55,6 +55,7 @@ public:
         return adoptRef(*new VideoFullscreenInterfaceMac(playbackSessionInterface));
     }
     virtual ~VideoFullscreenInterfaceMac();
+    PlaybackSessionInterfaceMac& playbackSessionInterface() const { return m_playbackSessionInterface.get(); }
     VideoFullscreenModel* videoFullscreenModel() const { return m_videoFullscreenModel; }
     PlaybackSessionModel* playbackSessionModel() const { return m_playbackSessionInterface->playbackSessionModel(); }
     WEBCORE_EXPORT void setVideoFullscreenModel(VideoFullscreenModel*);
@@ -76,17 +77,17 @@ public:
     WEBCORE_EXPORT void exitFullscreenWithoutAnimationToMode(HTMLMediaElementEnums::VideoFullscreenMode);
     WEBCORE_EXPORT void cleanupFullscreen();
     WEBCORE_EXPORT void invalidate();
-    void requestHideAndExitFullscreen() { }
+    WEBCORE_EXPORT void requestHideAndExitFullscreen();
     WEBCORE_EXPORT void preparedToReturnToInline(bool visible, const IntRect& inlineRect, NSWindow *parentWindow);
     void preparedToExitFullscreen() { }
 
     HTMLMediaElementEnums::VideoFullscreenMode mode() const { return m_mode; }
     bool hasMode(HTMLMediaElementEnums::VideoFullscreenMode mode) const { return m_mode & mode; }
     bool isMode(HTMLMediaElementEnums::VideoFullscreenMode mode) const { return m_mode == mode; }
-    void setMode(HTMLMediaElementEnums::VideoFullscreenMode);
+    WEBCORE_EXPORT void setMode(HTMLMediaElementEnums::VideoFullscreenMode);
     void clearMode(HTMLMediaElementEnums::VideoFullscreenMode);
 
-    bool isPlayingVideoInEnhancedFullscreen() const;
+    WEBCORE_EXPORT bool isPlayingVideoInEnhancedFullscreen() const;
 
     bool mayAutomaticallyShowVideoPictureInPicture() const { return false; }
     void applicationDidBecomeActive() { }
@@ -94,7 +95,7 @@ public:
     WEBCORE_EXPORT WebVideoFullscreenInterfaceMacObjC *videoFullscreenInterfaceObjC();
 
 private:
-    VideoFullscreenInterfaceMac(PlaybackSessionInterfaceMac&);
+    WEBCORE_EXPORT VideoFullscreenInterfaceMac(PlaybackSessionInterfaceMac&);
     Ref<PlaybackSessionInterfaceMac> m_playbackSessionInterface;
     VideoFullscreenModel* m_videoFullscreenModel { nullptr };
     VideoFullscreenChangeObserver* m_fullscreenChangeObserver { nullptr };
index 441c76e..b92b379 100644 (file)
@@ -107,7 +107,6 @@ enum class PIPState {
     RetainPtr<NSWindow> _returningWindow;
     NSRect _returningRect;
     BOOL _playing;
-    BOOL _didRequestExitingPIP;
     BOOL _exitingToStandardFullscreen;
 }
 
@@ -121,7 +120,6 @@ enum class PIPState {
 - (void)updateIsPlaying:(BOOL)isPlaying newPlaybackRate:(float)playbackRate;
 
 // Handling PIP transitions
-@property (nonatomic, readonly) BOOL didRequestExitingPIP;
 @property (nonatomic, getter=isExitingToStandardFullscreen) BOOL exitingToStandardFullscreen;
 
 - (void)setUpPIPForVideoView:(NSView *)videoView withFrame:(NSRect)frame inWindow:(NSWindow *)window;
@@ -135,7 +133,6 @@ enum class PIPState {
 
 @synthesize playing=_playing;
 @synthesize videoDimensions=_videoDimensions;
-@synthesize didRequestExitingPIP=_didRequestExitingPIP;
 @synthesize exitingToStandardFullscreen=_exitingToStandardFullscreen;
 
 - (instancetype)initWithVideoFullscreenInterfaceMac:(WebCore::VideoFullscreenInterfaceMac*)videoFullscreenInterfaceMac
@@ -158,7 +155,6 @@ enum class PIPState {
     _videoViewContainer = nil;
     _videoViewContainerController = nil;
     _pipState = PIPState::NotInPIP;
-    _didRequestExitingPIP = NO;
     _exitingToStandardFullscreen = NO;
     _returningWindow = nil;
     _returningRect = NSZeroRect;
@@ -225,7 +221,6 @@ enum class PIPState {
     if (_pipState != PIPState::InPIP || !_pipViewController || !_videoViewContainerController)
         return;
 
-    _didRequestExitingPIP = YES;
     [_videoViewContainerController view].layer.backgroundColor = CGColorGetConstantColor(kCGColorClear);
     [_pipViewController dismissViewController:_videoViewContainerController.get()];
     _pipState = PIPState::ExitingPIP;
@@ -235,7 +230,7 @@ enum class PIPState {
 {
     _returningWindow = window;
     _returningRect = rect;
-    
+
     [_pipViewController setReplacementRect:rect];
     [_pipViewController setReplacementWindow:window];
 
@@ -279,8 +274,7 @@ enum class PIPState {
     if (!_videoFullscreenInterfaceMac || !_videoFullscreenInterfaceMac->videoFullscreenChangeObserver())
         return YES;
 
-    _didRequestExitingPIP = YES;
-    _videoFullscreenInterfaceMac->videoFullscreenChangeObserver()->fullscreenMayReturnToInline();
+    _videoFullscreenInterfaceMac->requestHideAndExitFullscreen();
 
     return NO;
 }
@@ -303,13 +297,11 @@ enum class PIPState {
     if (_videoFullscreenInterfaceMac) {
         if (!self.isExitingToStandardFullscreen) {
             if (VideoFullscreenModel* videoFullscreenModel = _videoFullscreenInterfaceMac->videoFullscreenModel()) {
-                videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
+                videoFullscreenModel->didExitPictureInPicture();
                 videoFullscreenModel->setVideoLayerGravity(VideoFullscreenModel::VideoGravityResizeAspect);
             }
         }
 
-        _videoFullscreenInterfaceMac->clearMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
-
         if (VideoFullscreenChangeObserver* fullscreenChangeObserver = _videoFullscreenInterfaceMac->videoFullscreenChangeObserver())
             fullscreenChangeObserver->didExitFullscreen();
     }
@@ -443,12 +435,15 @@ void VideoFullscreenInterfaceMac::enterFullscreen()
     LOG(Fullscreen, "VideoFullscreenInterfaceMac::enterFullscreen(%p)", this);
 
     if (mode() == HTMLMediaElementEnums::VideoFullscreenModePictureInPicture) {
+        m_videoFullscreenModel->willEnterPictureInPicture();
         [m_webVideoFullscreenInterfaceObjC enterPIP];
 
 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
         [m_playbackSessionInterface->playBackControlsManager() setPictureInPictureActive:YES];
 #endif
 
+        // FIXME(rdar://problem/42250952): Move this call into a completion handler or delegate callback.
+        m_videoFullscreenModel->didEnterPictureInPicture();
         if (m_fullscreenChangeObserver)
             m_fullscreenChangeObserver->didEnterFullscreen();
     }
@@ -462,9 +457,6 @@ void VideoFullscreenInterfaceMac::exitFullscreen(const IntRect& finalRect, NSWin
     [m_playbackSessionInterface->playBackControlsManager() setPictureInPictureActive:NO];
 #endif
 
-    if ([m_webVideoFullscreenInterfaceObjC didRequestExitingPIP])
-        return;
-
     if (finalRect.isEmpty())
         [m_webVideoFullscreenInterfaceObjC exitPIP];
     else
@@ -479,9 +471,6 @@ void VideoFullscreenInterfaceMac::exitFullscreenWithoutAnimationToMode(HTMLMedia
     [m_playbackSessionInterface->playBackControlsManager() setPictureInPictureActive:NO];
 #endif
 
-    if ([m_webVideoFullscreenInterfaceObjC didRequestExitingPIP])
-        return;
-
     bool isExitingToStandardFullscreen = mode == HTMLMediaElementEnums::VideoFullscreenModeStandard;
     // On Mac, standard fullscreen is handled by the Fullscreen API and not by VideoFullscreenManager.
     // Just update m_mode directly to HTMLMediaElementEnums::VideoFullscreenModeStandard in that case to keep
@@ -517,6 +506,15 @@ void VideoFullscreenInterfaceMac::invalidate()
     m_webVideoFullscreenInterfaceObjC = nil;
 }
 
+void VideoFullscreenInterfaceMac::requestHideAndExitFullscreen()
+{
+    if (!m_videoFullscreenModel)
+        return;
+
+    m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
+    m_videoFullscreenModel->willExitPictureInPicture();
+}
+
 #if !LOG_DISABLED
 static const char* boolString(bool val)
 {
index d7e7e1e..1cce107 100644 (file)
@@ -1,5 +1,48 @@
 2018-07-18  Jer Noble  <jer.noble@apple.com>
 
+        PiP from Element Fullscreen should match AVKit's behavior
+        https://bugs.webkit.org/show_bug.cgi?id=187623
+
+        Reviewed by Jon Lee.
+
+        * UIProcess/Cocoa/PlaybackSessionManagerProxy.h:
+        (WebKit::PlaybackSessionManagerProxy::controlsManagerContextId const):
+        * UIProcess/Cocoa/VideoFullscreenManagerProxy.h:
+        * UIProcess/Cocoa/VideoFullscreenManagerProxy.mm:
+        (WebKit::VideoFullscreenModelContext::willEnterPictureInPicture):
+        (WebKit::VideoFullscreenModelContext::didEnterPictureInPicture):
+        (WebKit::VideoFullscreenModelContext::failedToEnterPictureInPicture):
+        (WebKit::VideoFullscreenModelContext::willExitPictureInPicture):
+        (WebKit::VideoFullscreenModelContext::didExitPictureInPicture):
+        (WebKit::VideoFullscreenModelContext::failedToExitPictureInPicture):
+        (WebKit::VideoFullscreenManagerProxy::controlsManagerInterface):
+        * UIProcess/ios/fullscreen/WKFullScreenViewController.mm:
+        (WKFullScreenViewControllerVideoFullscreenModelClient::setParent):
+        (WKFullScreenViewControllerVideoFullscreenModelClient::setInterface):
+        (WKFullScreenViewControllerVideoFullscreenModelClient::interface const):
+        (-[WKFullScreenViewController initWithWebView:]):
+        (-[WKFullScreenViewController dealloc]):
+        (-[WKFullScreenViewController videoControlsManagerDidChange]):
+        (-[WKFullScreenViewController ensurePiPAnimator]):
+        (-[WKFullScreenViewController willEnterPictureInPicture]):
+        (-[WKFullScreenViewController didEnterPictureInPicture]):
+        (-[WKFullScreenViewController failedToEnterPictureInPicture]):
+        (-[WKFullScreenViewController loadView]):
+        (-[WKFullScreenViewController viewWillAppear:]):
+        * UIProcess/Cocoa/WebViewImpl.mm:
+        (WebKit::WebViewImpl::videoControlsManagerDidChange):
+        * UIProcess/mac/WKFullScreenWindowController.h:
+        * UIProcess/mac/WKFullScreenWindowController.mm:
+        (WebKit::WKFullScreenWindowControllerVideoFullscreenModelClient::setParent):
+        (WebKit::WKFullScreenWindowControllerVideoFullscreenModelClient::setInterface):
+        (WebKit::WKFullScreenWindowControllerVideoFullscreenModelClient::interface const):
+        (-[WKFullScreenWindowController initWithWindow:webView:page:]):
+        (-[WKFullScreenWindowController dealloc]):
+        (-[WKFullScreenWindowController videoControlsManagerDidChange]):
+        (-[WKFullScreenWindowController willEnterPictureInPicture]):
+
+2018-07-18  Jer Noble  <jer.noble@apple.com>
+
         Dissociate the VideoFullscreenInterface from its VideoFullscreenModel before removing it from the manager
         https://bugs.webkit.org/show_bug.cgi?id=187775
         <rdar://problem/42343229>
index e5d6a49..835bb9b 100644 (file)
@@ -190,6 +190,8 @@ private:
     void addClientForContext(uint64_t contextId);
     void removeClientForContext(uint64_t contextId);
 
+    uint64_t controlsManagerContextId() const { return m_controlsManagerContextId; }
+
     // Messages from PlaybackSessionManager
     void setUpPlaybackControlsManagerWithID(uint64_t contextId);
     void clearPlaybackControlsManager();
index b66ec7f..48663c2 100644 (file)
@@ -89,6 +89,11 @@ private:
     UIViewController *presentingViewController() final;
     UIViewController *createVideoFullscreenViewController(AVPlayerViewController*) final;
 #endif
+    void willEnterPictureInPicture() final;
+    void didEnterPictureInPicture() final;
+    void failedToEnterPictureInPicture() final;
+    void willExitPictureInPicture() final;
+    void didExitPictureInPicture() final;
 
     // VideoFullscreenChangeObserver
     void requestUpdateInlineRect() final;
@@ -127,6 +132,8 @@ public:
     bool isPlayingVideoInEnhancedFullscreen() const;
 #endif
 
+    PlatformVideoFullscreenInterface* controlsManagerInterface();
+
 private:
     friend class VideoFullscreenModelContext;
 
index fcbd02b..0e9e9e4 100644 (file)
@@ -282,6 +282,36 @@ void VideoFullscreenModelContext::fullscreenMayReturnToInline()
         m_manager->fullscreenMayReturnToInline(m_contextId);
 }
 
+void VideoFullscreenModelContext::willEnterPictureInPicture()
+{
+    for (auto& client : m_clients)
+        client->willEnterPictureInPicture();
+}
+
+void VideoFullscreenModelContext::didEnterPictureInPicture()
+{
+    for (auto& client : m_clients)
+        client->didEnterPictureInPicture();
+}
+
+void VideoFullscreenModelContext::failedToEnterPictureInPicture()
+{
+    for (auto& client : m_clients)
+        client->failedToEnterPictureInPicture();
+}
+
+void VideoFullscreenModelContext::willExitPictureInPicture()
+{
+    for (auto& client : m_clients)
+        client->willExitPictureInPicture();
+}
+
+void VideoFullscreenModelContext::didExitPictureInPicture()
+{
+    for (auto& client : m_clients)
+        client->didExitPictureInPicture();
+}
+
 #pragma mark - VideoFullscreenManagerProxy
 
 RefPtr<VideoFullscreenManagerProxy> VideoFullscreenManagerProxy::create(WebPageProxy& page, PlaybackSessionManagerProxy& playbackSessionManagerProxy)
@@ -358,6 +388,13 @@ bool VideoFullscreenManagerProxy::isPlayingVideoInEnhancedFullscreen() const
 }
 #endif
 
+PlatformVideoFullscreenInterface* VideoFullscreenManagerProxy::controlsManagerInterface()
+{
+    if (auto contextId = m_playbackSessionManagerProxy->controlsManagerContextId())
+        return &ensureInterface(contextId);
+    return nullptr;
+}
+
 void VideoFullscreenManagerProxy::applicationDidBecomeActive()
 {
     for (auto& tuple : m_contextMap.values())
index 86acbb7..566ff59 100644 (file)
@@ -3283,6 +3283,11 @@ void WebViewImpl::videoControlsManagerDidChange()
 #if HAVE(TOUCH_BAR)
     updateTouchBar();
 #endif
+
+#if ENABLE(FULLSCREEN_API)
+    if (hasFullScreenWindowController())
+        [fullScreenWindowController() videoControlsManagerDidChange];
+#endif
 }
 
 void WebViewImpl::setIgnoresNonWheelEvents(bool ignoresNonWheelEvents)
index 02e60eb..12db8c8 100644 (file)
@@ -31,6 +31,7 @@
 #import "FullscreenTouchSecheuristic.h"
 #import "PlaybackSessionManagerProxy.h"
 #import "UIKitSPI.h"
+#import "VideoFullscreenManagerProxy.h"
 #import "WKFullscreenStackView.h"
 #import "WKWebViewInternal.h"
 #import "WebFullScreenManagerProxy.h"
@@ -43,11 +44,18 @@ using namespace WebCore;
 using namespace WebKit;
 
 static const NSTimeInterval showHideAnimationDuration = 0.1;
+static const NSTimeInterval pipHideAnimationDuration = 0.2;
 static const NSTimeInterval autoHideDelay = 4.0;
 static const double requiredScore = 0.1;
 
 @class WKFullscreenStackView;
 
+@interface WKFullScreenViewController (VideoFullscreenClientCallbacks)
+- (void)willEnterPictureInPicture;
+- (void)didEnterPictureInPicture;
+- (void)failedToEnterPictureInPicture;
+@end
+
 class WKFullScreenViewControllerPlaybackSessionModelClient : PlaybackSessionModelClient {
 public:
     void setParent(WKFullScreenViewController *parent) { m_parent = parent; }
@@ -79,6 +87,44 @@ private:
     RefPtr<PlaybackSessionInterfaceAVKit> m_interface;
 };
 
+class WKFullScreenViewControllerVideoFullscreenModelClient : VideoFullscreenModelClient {
+public:
+    void setParent(WKFullScreenViewController *parent) { m_parent = parent; }
+
+    void setInterface(VideoFullscreenInterfaceAVKit* interface)
+    {
+        if (m_interface == interface)
+            return;
+
+        if (m_interface && m_interface->videoFullscreenModel())
+            m_interface->videoFullscreenModel()->removeClient(*this);
+        m_interface = interface;
+        if (m_interface && m_interface->videoFullscreenModel())
+            m_interface->videoFullscreenModel()->addClient(*this);
+    }
+
+    VideoFullscreenInterfaceAVKit* interface() const { return m_interface.get(); }
+
+    void willEnterPictureInPicture() final
+    {
+        [m_parent willEnterPictureInPicture];
+    }
+
+    void didEnterPictureInPicture() final
+    {
+        [m_parent didEnterPictureInPicture];
+    }
+
+    void failedToEnterPictureInPicture() final
+    {
+        [m_parent failedToEnterPictureInPicture];
+    }
+
+private:
+    WKFullScreenViewController *m_parent { nullptr };
+    RefPtr<VideoFullscreenInterfaceAVKit> m_interface;
+};
+
 #pragma mark - _WKExtrinsicButton
 
 @interface _WKExtrinsicButton : UIButton
@@ -108,6 +154,7 @@ private:
 
 @implementation WKFullScreenViewController {
     RetainPtr<UILongPressGestureRecognizer> _touchGestureRecognizer;
+    RetainPtr<UIView> _animatingView;
     RetainPtr<WKFullscreenStackView> _stackView;
     RetainPtr<_WKExtrinsicButton> _cancelButton;
     RetainPtr<_WKExtrinsicButton> _pipButton;
@@ -116,6 +163,7 @@ private:
     RetainPtr<NSLayoutConstraint> _topConstraint;
     WebKit::FullscreenTouchSecheuristic _secheuristic;
     WKFullScreenViewControllerPlaybackSessionModelClient _playbackClient;
+    WKFullScreenViewControllerVideoFullscreenModelClient _videoFullscreenClient;
     CGFloat _nonZeroStatusBarHeight;
 }
 
@@ -141,6 +189,7 @@ private:
     self._webView = webView;
 
     _playbackClient.setParent(self);
+    _videoFullscreenClient.setParent(self);
 
     return self;
 }
@@ -151,6 +200,8 @@ private:
     [[NSNotificationCenter defaultCenter] removeObserver:self];
 
     _playbackClient.setInterface(nullptr);
+    _videoFullscreenClient.setParent(nullptr);
+    _videoFullscreenClient.setInterface(nullptr);
 
     [_target release];
     [_location release];
@@ -205,9 +256,12 @@ private:
 - (void)videoControlsManagerDidChange
 {
     WebPageProxy* page = [self._webView _page];
-    PlaybackSessionManagerProxy* playbackSessionManager = page ? page->playbackSessionManager() : nullptr;
-    PlatformPlaybackSessionInterface* playbackSessionInterface = playbackSessionManager ? playbackSessionManager->controlsManagerInterface() : nullptr;
+    auto* videoFullscreenManager = page ? page->videoFullscreenManager() : nullptr;
+    auto* videoFullscreenInterface = videoFullscreenManager ? videoFullscreenManager->controlsManagerInterface() : nullptr;
+    auto* playbackSessionInterface = videoFullscreenInterface ? &videoFullscreenInterface->playbackSessionInterface() : nullptr;
+
     _playbackClient.setInterface(playbackSessionInterface);
+    _videoFullscreenClient.setInterface(videoFullscreenInterface);
 
     PlaybackSessionModel* playbackSessionModel = playbackSessionInterface ? playbackSessionInterface->playbackSessionModel() : nullptr;
     self.playing = playbackSessionModel ? playbackSessionModel->isPlaying() : NO;
@@ -264,12 +318,44 @@ private:
         [self showUI];
 }
 
+- (void)willEnterPictureInPicture
+{
+    auto* interface = _videoFullscreenClient.interface();
+    if (!interface || !interface->pictureInPictureWasStartedWhenEnteringBackground())
+        return;
+
+    [UIView animateWithDuration:pipHideAnimationDuration animations:^{
+        _animatingView.get().alpha = 0;
+    }];
+}
+
+- (void)didEnterPictureInPicture
+{
+    [self _cancelAction:self];
+}
+
+- (void)failedToEnterPictureInPicture
+{
+    auto* interface = _videoFullscreenClient.interface();
+    if (!interface || !interface->pictureInPictureWasStartedWhenEnteringBackground())
+        return;
+
+    [UIView animateWithDuration:pipHideAnimationDuration animations:^{
+        _animatingView.get().alpha = 1;
+    }];
+}
+
 #pragma mark - UIViewController Overrides
 
 - (void)loadView
 {
     [self setView:adoptNS([[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]).get()];
     self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+    self.view.backgroundColor = [UIColor blackColor];
+
+    _animatingView = adoptNS([[UIView alloc] initWithFrame:self.view.bounds]);
+    _animatingView.get().autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+    [self.view addSubview:_animatingView.get()];
 
     _cancelButton = [_WKExtrinsicButton buttonWithType:UIButtonTypeSystem];
     [_cancelButton setTranslatesAutoresizingMaskIntoConstraints:NO];
@@ -298,7 +384,7 @@ private:
     [_stackView setTranslatesAutoresizingMaskIntoConstraints:NO];
     [_stackView addArrangedSubview:_cancelButton.get() applyingMaterialStyle:AVBackgroundViewMaterialStyleSecondary tintEffectStyle:AVBackgroundViewTintEffectStyleSecondary];
     [_stackView addArrangedSubview:_pipButton.get() applyingMaterialStyle:AVBackgroundViewMaterialStylePrimary tintEffectStyle:AVBackgroundViewTintEffectStyleSecondary];
-    [[self view] addSubview:_stackView.get()];
+    [_animatingView addSubview:_stackView.get()];
 
     UILayoutGuide *safeArea = self.view.safeAreaLayoutGuide;
     UILayoutGuide *margins = self.view.layoutMarginsGuide;
@@ -328,7 +414,7 @@ private:
 {
     self._webView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
     self._webView.frame = self.view.bounds;
-    [self.view insertSubview:self._webView atIndex:0];
+    [_animatingView insertSubview:self._webView atIndex:0];
 
     if (auto* manager = self._manager)
         manager->setFullscreenAutoHideDuration(Seconds(showHideAnimationDuration));
index 35426d5..33c58e7 100644 (file)
@@ -31,6 +31,7 @@
 namespace WebKit { 
 class LayerTreeContext;
 class WebPageProxy;
+class WKFullScreenWindowControllerVideoFullscreenModelClient;
 }
 
 namespace WebCore {
@@ -59,6 +60,7 @@ typedef enum FullScreenState : NSInteger FullScreenState;
 
     double _savedScale;
     RefPtr<WebKit::VoidCallback> _repaintCallback;
+    std::unique_ptr<WebKit::WKFullScreenWindowControllerVideoFullscreenModelClient> _videoFullscreenClient;
     float _savedTopContentInset;
 }
 
@@ -79,6 +81,9 @@ typedef enum FullScreenState : NSInteger FullScreenState;
 - (void)beganEnterFullScreenWithInitialFrame:(NSRect)initialFrame finalFrame:(NSRect)finalFrame;
 - (void)beganExitFullScreenWithInitialFrame:(NSRect)initialFrame finalFrame:(NSRect)finalFrame;
 
+- (void)videoControlsManagerDidChange;
+- (void)didEnterPictureInPicture;
+
 @end
 
 #endif
index ea50e32..66b072f 100644 (file)
@@ -30,6 +30,7 @@
 #import "WKFullScreenWindowController.h"
 
 #import "LayerTreeContext.h"
+#import "VideoFullscreenManagerProxy.h"
 #import "WKAPICast.h"
 #import "WKViewInternal.h"
 #import "WKViewPrivate.h"
 #import <WebCore/GeometryUtilities.h>
 #import <WebCore/IntRect.h>
 #import <WebCore/LocalizedStrings.h>
+#import <WebCore/VideoFullscreenInterfaceMac.h>
+#import <WebCore/VideoFullscreenModel.h>
 #import <WebCore/WebCoreFullScreenPlaceholderView.h>
 #import <WebCore/WebCoreFullScreenWindow.h>
 #import <pal/system/SleepDisabler.h>
 #import <wtf/BlockObjCExceptions.h>
 
-using namespace WebKit;
 using namespace WebCore;
 
 static const NSTimeInterval DefaultWatchdogTimerInterval = 1;
 
+namespace WebKit {
+
+class WKFullScreenWindowControllerVideoFullscreenModelClient : VideoFullscreenModelClient {
+public:
+    void setParent(WKFullScreenWindowController *parent) { m_parent = parent; }
+
+    void setInterface(VideoFullscreenInterfaceMac* interface)
+    {
+        if (m_interface == interface)
+            return;
+
+        if (m_interface && m_interface->videoFullscreenModel())
+            m_interface->videoFullscreenModel()->removeClient(*this);
+        m_interface = interface;
+        if (m_interface && m_interface->videoFullscreenModel())
+            m_interface->videoFullscreenModel()->addClient(*this);
+    }
+
+    VideoFullscreenInterfaceMac* interface() const { return m_interface.get(); }
+
+    void didEnterPictureInPicture() final
+    {
+        [m_parent didEnterPictureInPicture];
+    }
+
+private:
+    WKFullScreenWindowController *m_parent { nullptr };
+    RefPtr<VideoFullscreenInterfaceMac> m_interface;
+};
+
+}
+
+using namespace WebKit;
+
 enum FullScreenState : NSInteger {
     NotInFullScreen,
     WaitingToEnterFullScreen,
@@ -113,7 +149,12 @@ static void makeResponderFirstResponderIfDescendantOfView(NSWindow *window, NSRe
     [window displayIfNeeded];
     _webView = webView;
     _page = &page;
-    
+
+    _videoFullscreenClient = std::make_unique<WKFullScreenWindowControllerVideoFullscreenModelClient>();
+    _videoFullscreenClient->setParent(self);
+
+    [self videoControlsManagerDidChange];
+
     return self;
 }
 
@@ -132,6 +173,9 @@ static void makeResponderFirstResponderIfDescendantOfView(NSWindow *window, NSRe
         ASSERT(!_repaintCallback);
     }
 
+    _videoFullscreenClient->setParent(nil);
+    _videoFullscreenClient->setInterface(nullptr);
+
     [super dealloc];
 }
 
@@ -506,6 +550,19 @@ static const float minVideoWidth = 480 + 20 + 20; // Note: Keep in sync with med
     [super close];
 }
 
+- (void)videoControlsManagerDidChange
+{
+    auto* videoFullscreenManager = _page ? _page->videoFullscreenManager() : nullptr;
+    auto* videoFullscreenInterface = videoFullscreenManager ? videoFullscreenManager->controlsManagerInterface() : nullptr;
+
+    _videoFullscreenClient->setInterface(videoFullscreenInterface);
+}
+
+- (void)didEnterPictureInPicture
+{
+    [self requestExitFullScreen];
+}
+
 #pragma mark -
 #pragma mark Custom NSWindow Full Screen Animation
 
index d5a8c0b..db9fa0a 100644 (file)
@@ -1,3 +1,19 @@
+2018-07-18  Jer Noble  <jer.noble@apple.com>
+
+        PiP from Element Fullscreen should match AVKit's behavior
+        https://bugs.webkit.org/show_bug.cgi?id=187623
+        <rdar://problem/41212379>
+
+        Reviewed by Jon Lee.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKitCocoa/ExitFullscreenOnEnterPiP.html: Added.
+        * TestWebKitAPI/Tests/WebKitCocoa/ExitFullscreenOnEnterPiP.mm: Added.
+        (-[ExitFullscreenOnEnterPiPUIDelegate _webView:hasVideoInPictureInPictureDidChange:]):
+        (-[ExitFullscreenOnEnterPiPUIDelegate _webViewDidEnterFullscreen:]):
+        (-[ExitFullscreenOnEnterPiPUIDelegate _webViewDidExitFullscreen:]):
+        (TestWebKitAPI::TEST):
+
 2018-07-18  Aakash Jain  <aakash_jain@apple.com>
 
         [ews-build] Add build step to run layout-test
index 3f8dc9a..02497f8 100644 (file)
                CD78E11D1DB7EA660014A2DE /* FullscreenDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = CD78E11A1DB7EA360014A2DE /* FullscreenDelegate.mm */; };
                CD78E11E1DB7EE2A0014A2DE /* FullscreenDelegate.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = CD78E11B1DB7EA360014A2DE /* FullscreenDelegate.html */; };
                CD9E292E1C90C33F000BB800 /* audio-only.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = CD9E292D1C90C1BA000BB800 /* audio-only.html */; };
+               CDA29B2920FD2A9900F15CED /* ExitFullscreenOnEnterPiP.mm in Sources */ = {isa = PBXBuildFile; fileRef = CDA29B2820FD2A9900F15CED /* ExitFullscreenOnEnterPiP.mm */; };
+               CDA29B2B20FD358400F15CED /* ExitFullscreenOnEnterPiP.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = CDA29B2A20FD344E00F15CED /* ExitFullscreenOnEnterPiP.html */; };
                CDA315981ED53651009F60D3 /* MediaPlaybackSleepAssertion.mm in Sources */ = {isa = PBXBuildFile; fileRef = CDA315961ED53651009F60D3 /* MediaPlaybackSleepAssertion.mm */; };
                CDA3159A1ED548F1009F60D3 /* MediaPlaybackSleepAssertion.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = CDA315991ED540A5009F60D3 /* MediaPlaybackSleepAssertion.html */; };
                CDA3159D1ED5643F009F60D3 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CDA3159C1ED5643F009F60D3 /* IOKit.framework */; };
                                F407FE391F1D0DFC0017CF25 /* enormous.svg in Copy Resources */,
                                07492B3C1DF8B86600633DE1 /* enumerateMediaDevices.html in Copy Resources */,
                                C5E1AFFE16B221F1006CC1F2 /* execCopy.html in Copy Resources */,
+                               CDA29B2B20FD358400F15CED /* ExitFullscreenOnEnterPiP.html in Copy Resources */,
                                F41AB9A31EF4696B0083FA08 /* file-uploading.html in Copy Resources */,
                                BC2D006412AA04CE00E732A3 /* file-with-anchor.html in Copy Resources */,
                                CD59F53419E9110D00CF1835 /* file-with-mse.html in Copy Resources */,
                CD89D0381C4EDB2A00040A04 /* WebCoreNSURLSession.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebCoreNSURLSession.mm; sourceTree = "<group>"; };
                CD9E292B1C90A71F000BB800 /* RequiresUserActionForPlayback.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RequiresUserActionForPlayback.mm; sourceTree = "<group>"; };
                CD9E292D1C90C1BA000BB800 /* audio-only.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "audio-only.html"; sourceTree = "<group>"; };
+               CDA29B2820FD2A9900F15CED /* ExitFullscreenOnEnterPiP.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ExitFullscreenOnEnterPiP.mm; sourceTree = "<group>"; };
+               CDA29B2A20FD344E00F15CED /* ExitFullscreenOnEnterPiP.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = ExitFullscreenOnEnterPiP.html; sourceTree = "<group>"; };
                CDA315961ED53651009F60D3 /* MediaPlaybackSleepAssertion.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MediaPlaybackSleepAssertion.mm; sourceTree = "<group>"; };
                CDA315991ED540A5009F60D3 /* MediaPlaybackSleepAssertion.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = MediaPlaybackSleepAssertion.html; sourceTree = "<group>"; };
                CDA3159C1ED5643F009F60D3 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; };
                                A1A4FE5D18DD3DB700B5EA8A /* Download.mm */,
                                A15502281E05020B00A24C57 /* DuplicateCompletionHandlerCalls.mm */,
                                F44D06461F395C4D001A0E29 /* EditorStateTests.mm */,
+                               CDA29B2820FD2A9900F15CED /* ExitFullscreenOnEnterPiP.mm */,
                                2D8104CB1BEC13E70020DA46 /* FindInPage.mm */,
                                2D1FE0AF1AD465C1006CD9E6 /* FixedLayoutSize.mm */,
                                5CB5B3BD1FFC517E00C27BB0 /* FrameHandleSerialization.mm */,
                                9984FACD1CFFB038008D198C /* editable-body.html */,
                                F44D06441F395C0D001A0E29 /* editor-state-test-harness.html */,
                                51C8E1A81F27F47300BF731B /* EmptyGrandfatheredResourceLoadStatistics.plist */,
+                               CDA29B2A20FD344E00F15CED /* ExitFullscreenOnEnterPiP.html */,
                                F4C2AB211DD6D94100E06D5B /* enormous-video-with-sound.html */,
                                F407FE381F1D0DE60017CF25 /* enormous.svg */,
                                F41AB99B1EF4692C0083FA08 /* file-uploading.html */,
                                518C1153205B0504001FF4AE /* ProcessSwapOnNavigation.mm in Sources */,
                                7C83E0C11D0A652F00FEBCF3 /* ProvisionalURLNotChange.mm in Sources */,
                                7CCE7EC81A411A7E00447C4C /* PublicSuffix.mm in Sources */,
+                               CDA29B2920FD2A9900F15CED /* ExitFullscreenOnEnterPiP.mm in Sources */,
                                7C83E0C21D0A653500FEBCF3 /* QuickLook.mm in Sources */,
                                7CCE7F0D1A411AE600447C4C /* ReloadPageAfterCrash.cpp in Sources */,
                                7C83E0C31D0A653A00FEBCF3 /* RemoteObjectRegistry.mm in Sources */,
diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/ExitFullscreenOnEnterPiP.html b/Tools/TestWebKitAPI/Tests/WebKitCocoa/ExitFullscreenOnEnterPiP.html
new file mode 100644 (file)
index 0000000..1131616
--- /dev/null
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<button id="enter-video-fullscreen" onclick="document.querySelector('video').webkitEnterFullscreen()">enter video fullscreen</button>
+<button id="enter-element-fullscreen" onclick="document.querySelector('#target').webkitRequestFullscreen()">enter element fullscreen</button>
+<button id="enter-pip" onclick="document.querySelector('video').webkitSetPresentationMode('picture-in-picture')">enter pip</button>
+<button id="exit-pip" onclick="document.querySelector('video').webkitSetPresentationMode('inline')">exit pip</button>
+<body onload="load(); window.onloadcompleted = true; ">
+    <div id="target">
+        <video id="video" playsinline src="test.mp4" />
+    </div>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/ExitFullscreenOnEnterPiP.mm b/Tools/TestWebKitAPI/Tests/WebKitCocoa/ExitFullscreenOnEnterPiP.mm
new file mode 100644 (file)
index 0000000..0bcb8f7
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2018 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 (WK_API_ENABLED && PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300) || (PLATFORM(IOS) && !PLATFORM(IOS_SIMULATOR))
+
+#import "PlatformUtilities.h"
+#import "Test.h"
+#import "TestWKWebView.h"
+#import <WebKit/WKPreferencesPrivate.h>
+#import <WebKit/WKUIDelegatePrivate.h>
+#import <WebKit/_WKFullscreenDelegate.h>
+#import <wtf/RetainPtr.h>
+#import <wtf/Seconds.h>
+
+static bool didEnterPiP;
+static bool didExitPiP;
+static bool didEnterFullscreen;
+static bool didExitFullscreen;
+
+@interface ExitFullscreenOnEnterPiPUIDelegate : NSObject <WKUIDelegate, _WKFullscreenDelegate>
+@end
+
+@implementation ExitFullscreenOnEnterPiPUIDelegate
+
+- (void)_webView:(WKWebView *)webView hasVideoInPictureInPictureDidChange:(BOOL)value
+{
+    if (value)
+        didEnterPiP = true;
+    else
+        didExitPiP = true;
+}
+
+- (void)_webViewDidEnterFullscreen:(WKWebView *)webView
+{
+    didEnterFullscreen = true;
+}
+
+- (void)_webViewDidExitFullscreen:(WKWebView *)webView
+{
+    didExitFullscreen = true;
+}
+@end
+
+namespace TestWebKitAPI {
+
+TEST(ExitFullscreenOnEnterPiP, VideoFullscreen)
+{
+    RetainPtr<WKWebViewConfiguration> configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    [configuration preferences]._fullScreenEnabled = YES;
+    [configuration preferences]._allowsPictureInPictureMediaPlayback = YES;
+    RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 300, 300) configuration:configuration.get() addToWindow:YES]);
+    RetainPtr<ExitFullscreenOnEnterPiPUIDelegate> handler = adoptNS([[ExitFullscreenOnEnterPiPUIDelegate alloc] init]);
+    [webView setUIDelegate:handler.get()];
+    [webView _setFullscreenDelegate:handler.get()];
+
+    [webView synchronouslyLoadTestPageNamed:@"ExitFullscreenOnEnterPiP"];
+
+    didEnterFullscreen = false;
+    [webView evaluateJavaScript:@"document.getElementById('enter-video-fullscreen').click()" completionHandler: nil];
+    TestWebKitAPI::Util::run(&didEnterFullscreen);
+    ASSERT_TRUE(didEnterFullscreen);
+
+    didEnterPiP = false;
+    didExitFullscreen = false;
+    [webView evaluateJavaScript:@"document.getElementById('enter-pip').click()" completionHandler: nil];
+    TestWebKitAPI::Util::run(&didEnterPiP);
+    TestWebKitAPI::Util::run(&didExitFullscreen);
+
+    sleep(1_s); // Wait for PIPAgent to launch, or it won't call -pipDidClose: callback.
+
+    [webView evaluateJavaScript:@"document.getElementById('exit-pip').click()" completionHandler: nil];
+    TestWebKitAPI::Util::run(&didExitPiP);
+}
+
+
+TEST(ExitFullscreenOnEnterPiP, ElementFullscreen)
+{
+    RetainPtr<WKWebViewConfiguration> configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    [configuration preferences]._fullScreenEnabled = YES;
+    [configuration preferences]._allowsPictureInPictureMediaPlayback = YES;
+    RetainPtr<TestWKWebView> webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 300, 300) configuration:configuration.get() addToWindow:YES]);
+    RetainPtr<ExitFullscreenOnEnterPiPUIDelegate> handler = adoptNS([[ExitFullscreenOnEnterPiPUIDelegate alloc] init]);
+    [webView setUIDelegate:handler.get()];
+    [webView _setFullscreenDelegate:handler.get()];
+
+    [webView synchronouslyLoadTestPageNamed:@"ExitFullscreenOnEnterPiP"];
+
+    didEnterFullscreen = false;
+    [webView evaluateJavaScript:@"document.getElementById('enter-element-fullscreen').click()" completionHandler: nil];
+    TestWebKitAPI::Util::run(&didEnterFullscreen);
+    ASSERT_TRUE(didEnterFullscreen);
+
+    didEnterPiP = false;
+    didExitFullscreen = false;
+    [webView evaluateJavaScript:@"document.getElementById('enter-pip').click()" completionHandler: nil];
+    TestWebKitAPI::Util::run(&didEnterPiP);
+    TestWebKitAPI::Util::run(&didExitFullscreen);
+
+    sleep(1_s); // Wait for PIPAgent to launch, or it won't call -pipDidClose: callback.
+
+    [webView evaluateJavaScript:@"document.getElementById('exit-pip').click()" completionHandler: nil];
+    TestWebKitAPI::Util::run(&didExitPiP);
+}
+
+} // namespace TestWebKitAPI
+
+#endif