Enable picture-in-picture from inline element on suspend.
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 21 Dec 2017 10:08:14 +0000 (10:08 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 21 Dec 2017 10:08:14 +0000 (10:08 +0000)
https://bugs.webkit.org/show_bug.cgi?id=180942
rdar://problem/34745234

Patch by Jeremy Jones <jeremyj@apple.com> on 2017-12-21
Reviewed by Jer Noble.

Source/WebCore:

When a element goes into element fullscreen mode, a descendant video element gains the ability to automatically enter picture-in-picture on application suspend.

This adds support for video fullscreen standby mode, which creates a VideoFullscreenInterfaceAVKit so that it can
trigger auto-pip on application suspend while the element is not actually presenting in video fullscreen mode.

VideoFullscreenInterfaceAVKit has a new state transition system that will replace the existing one to enable the increased
number and complexity of state transitions. Until we are ready to completely commit to this new code path, this implementation is
conditionalized to keep the existing code path working.

* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::enterFullscreen):
(WebCore::HTMLMediaElement::exitFullscreen):
(WebCore::HTMLMediaElement::setVideoFullscreenStandby):
(WebCore::HTMLMediaElement::shouldOverrideBackgroundPlaybackRestriction const):
* html/HTMLMediaElement.h:
* page/ChromeClient.h:
* platform/cocoa/VideoFullscreenChangeObserver.h:
* platform/ios/VideoFullscreenInterfaceAVKit.h:
* platform/ios/VideoFullscreenInterfaceAVKit.mm:
(-[WebAVPlayerViewControllerDelegate playerViewControllerShouldStartPictureInPictureFromInlineWhenEnteringBackground:]):
(-[WebAVPlayerLayer layoutSublayers]):
(allocWebAVPictureInPicturePlayerLayerViewInstance):
(allocWebAVPlayerLayerViewInstance):
(VideoFullscreenInterfaceAVKit::applicationDidBecomeActive):
(VideoFullscreenInterfaceAVKit::setupFullscreen):
(VideoFullscreenInterfaceAVKit::enterFullscreen):
(VideoFullscreenInterfaceAVKit::exitFullscreen):
(VideoFullscreenInterfaceAVKit::cleanupFullscreen):
(VideoFullscreenInterfaceAVKit::requestHideAndExitFullscreen):
(VideoFullscreenInterfaceAVKit::preparedToReturnToInline):
(VideoFullscreenInterfaceAVKit::mayAutomaticallyShowVideoPictureInPicture const):
(VideoFullscreenInterfaceAVKit::willStartPictureInPicture):
(VideoFullscreenInterfaceAVKit::didStartPictureInPicture):
(VideoFullscreenInterfaceAVKit::failedToStartPictureInPicture):
(VideoFullscreenInterfaceAVKit::willStopPictureInPicture):
(VideoFullscreenInterfaceAVKit::didStopPictureInPicture):
(VideoFullscreenInterfaceAVKit::prepareForPictureInPictureStopWithCompletionHandler):
(VideoFullscreenInterfaceAVKit::shouldExitFullscreenWithReason):
(VideoFullscreenInterfaceAVKit::setMode):
(VideoFullscreenInterfaceAVKit::clearMode):
(VideoFullscreenInterfaceAVKit::setHasVideoContentLayer):
(VideoFullscreenInterfaceAVKit::setInlineRect):
(VideoFullscreenInterfaceAVKit::doSetup):
(VideoFullscreenInterfaceAVKit::finalizeSetup):
(VideoFullscreenInterfaceAVKit::doEnterFullscreen):
(VideoFullscreenInterfaceAVKit::doExitFullscreen):
(VideoFullscreenInterfaceAVKit::exitFullscreenHandler):
(VideoFullscreenInterfaceAVKit::enterFullscreenHandler):
(VideoFullscreenInterfaceAVKit::returnToStandby):
* platform/ios/WebVideoFullscreenControllerAVKit.mm:
(VideoFullscreenControllerContext::requestUpdateInlineRect):
(VideoFullscreenControllerContext::requestVideoContentLayer):
(VideoFullscreenControllerContext::returnVideoContentLayer):
(VideoFullscreenControllerContext::didSetupFullscreen):
(VideoFullscreenControllerContext::didExitFullscreen):
(VideoFullscreenControllerContext::setUpFullscreen):

Source/WebKit:

Add support for video fullscreen standby and imporved fullscreen state transition process.

Video fullscreen standby allows a video element to have its fullscreen interface state created and
continuously updated so that it can quickly change presentation state on application state.

In order to accomplish this, this change allows the fullscreen presentation to decide when it needs
an updated inline rect, or the presence of the video layer.

This is conditionalized until mac supports this model.

* UIProcess/Cocoa/VideoFullscreenManagerProxy.h:
* UIProcess/Cocoa/VideoFullscreenManagerProxy.messages.in:
* UIProcess/Cocoa/VideoFullscreenManagerProxy.mm:
(WebKit::VideoFullscreenModelContext::requestUpdateInlineRect):
(WebKit::VideoFullscreenModelContext::requestVideoContentLayer):
(WebKit::VideoFullscreenModelContext::returnVideoContentLayer):
(WebKit::VideoFullscreenManagerProxy::setupFullscreenWithID):
(WebKit::VideoFullscreenManagerProxy::setInlineRect):
(WebKit::VideoFullscreenManagerProxy::setHasVideoContentLayer):
(WebKit::VideoFullscreenManagerProxy::requestUpdateInlineRect):
(WebKit::VideoFullscreenManagerProxy::requestVideoContentLayer):
(WebKit::VideoFullscreenManagerProxy::returnVideoContentLayer):
* WebProcess/FullScreen/WebFullScreenManager.cpp:
(WebKit::WebFullScreenManager::didEnterFullScreen):
(WebKit::WebFullScreenManager::willExitFullScreen):
* WebProcess/FullScreen/WebFullScreenManager.h:
* WebProcess/WebCoreSupport/WebChromeClient.cpp:
(WebKit::WebChromeClient::supportsVideoFullscreenStandby):
(WebKit::WebChromeClient::enterVideoFullscreenForVideoElement):
* WebProcess/WebCoreSupport/WebChromeClient.h:
* WebProcess/cocoa/VideoFullscreenManager.h:
(WebKit::VideoFullscreenInterfaceContext::fullscreenStandby const):
(WebKit::VideoFullscreenInterfaceContext::setFullscreenStandby):
* WebProcess/cocoa/VideoFullscreenManager.messages.in:
* WebProcess/cocoa/VideoFullscreenManager.mm:
(WebKit::VideoFullscreenManager::supportsVideoFullscreenStandby const):
(WebKit::VideoFullscreenManager::enterVideoFullscreenForVideoElement):
(WebKit::VideoFullscreenManager::requestUpdateInlineRect):
(WebKit::VideoFullscreenManager::requestVideoContentLayer):
(WebKit::VideoFullscreenManager::returnVideoContentLayer):
(WebKit::VideoFullscreenManager::didSetupFullscreen):
(WebKit::VideoFullscreenManager::didExitFullscreen):
(WebKit::VideoFullscreenManager::didCleanupFullscreen):

Source/WebKitLegacy/mac:

Update signature of enterVideoFullscreenForVideoElement().

* WebCoreSupport/WebChromeClient.h:
* WebCoreSupport/WebChromeClient.mm:
(WebChromeClient::enterVideoFullscreenForVideoElement):

Source/WebKitLegacy/win:

Update signature of enterVideoFullscreenForVideoElement.

* WebCoreSupport/WebChromeClient.cpp:
(WebChromeClient::enterVideoFullscreenForVideoElement):
* WebCoreSupport/WebChromeClient.h:

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

27 files changed:
Source/WebCore/ChangeLog
Source/WebCore/html/HTMLMediaElement.cpp
Source/WebCore/html/HTMLMediaElement.h
Source/WebCore/page/ChromeClient.h
Source/WebCore/platform/cocoa/VideoFullscreenChangeObserver.h
Source/WebCore/platform/ios/VideoFullscreenInterfaceAVKit.h
Source/WebCore/platform/ios/VideoFullscreenInterfaceAVKit.mm
Source/WebCore/platform/ios/WebVideoFullscreenControllerAVKit.mm
Source/WebCore/platform/mac/VideoFullscreenInterfaceMac.mm
Source/WebKit/ChangeLog
Source/WebKit/UIProcess/Cocoa/VideoFullscreenManagerProxy.h
Source/WebKit/UIProcess/Cocoa/VideoFullscreenManagerProxy.messages.in
Source/WebKit/UIProcess/Cocoa/VideoFullscreenManagerProxy.mm
Source/WebKit/UIProcess/ios/WKFullScreenWindowControllerIOS.mm
Source/WebKit/WebProcess/FullScreen/WebFullScreenManager.cpp
Source/WebKit/WebProcess/FullScreen/WebFullScreenManager.h
Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp
Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h
Source/WebKit/WebProcess/cocoa/VideoFullscreenManager.h
Source/WebKit/WebProcess/cocoa/VideoFullscreenManager.messages.in
Source/WebKit/WebProcess/cocoa/VideoFullscreenManager.mm
Source/WebKitLegacy/mac/ChangeLog
Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.h
Source/WebKitLegacy/mac/WebCoreSupport/WebChromeClient.mm
Source/WebKitLegacy/win/ChangeLog
Source/WebKitLegacy/win/WebCoreSupport/WebChromeClient.cpp
Source/WebKitLegacy/win/WebCoreSupport/WebChromeClient.h

index 2e4be4e..e67c85d 100644 (file)
@@ -1,3 +1,68 @@
+2017-12-21  Jeremy Jones  <jeremyj@apple.com>
+
+        Enable picture-in-picture from inline element on suspend.
+        https://bugs.webkit.org/show_bug.cgi?id=180942
+        rdar://problem/34745234
+
+        Reviewed by Jer Noble.
+
+        When a element goes into element fullscreen mode, a descendant video element gains the ability to automatically enter picture-in-picture on application suspend.
+
+        This adds support for video fullscreen standby mode, which creates a VideoFullscreenInterfaceAVKit so that it can
+        trigger auto-pip on application suspend while the element is not actually presenting in video fullscreen mode.
+
+        VideoFullscreenInterfaceAVKit has a new state transition system that will replace the existing one to enable the increased
+        number and complexity of state transitions. Until we are ready to completely commit to this new code path, this implementation is
+        conditionalized to keep the existing code path working.
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::enterFullscreen):
+        (WebCore::HTMLMediaElement::exitFullscreen):
+        (WebCore::HTMLMediaElement::setVideoFullscreenStandby):
+        (WebCore::HTMLMediaElement::shouldOverrideBackgroundPlaybackRestriction const):
+        * html/HTMLMediaElement.h:
+        * page/ChromeClient.h:
+        * platform/cocoa/VideoFullscreenChangeObserver.h:
+        * platform/ios/VideoFullscreenInterfaceAVKit.h:
+        * platform/ios/VideoFullscreenInterfaceAVKit.mm:
+        (-[WebAVPlayerViewControllerDelegate playerViewControllerShouldStartPictureInPictureFromInlineWhenEnteringBackground:]):
+        (-[WebAVPlayerLayer layoutSublayers]):
+        (allocWebAVPictureInPicturePlayerLayerViewInstance):
+        (allocWebAVPlayerLayerViewInstance):
+        (VideoFullscreenInterfaceAVKit::applicationDidBecomeActive):
+        (VideoFullscreenInterfaceAVKit::setupFullscreen):
+        (VideoFullscreenInterfaceAVKit::enterFullscreen):
+        (VideoFullscreenInterfaceAVKit::exitFullscreen):
+        (VideoFullscreenInterfaceAVKit::cleanupFullscreen):
+        (VideoFullscreenInterfaceAVKit::requestHideAndExitFullscreen):
+        (VideoFullscreenInterfaceAVKit::preparedToReturnToInline):
+        (VideoFullscreenInterfaceAVKit::mayAutomaticallyShowVideoPictureInPicture const):
+        (VideoFullscreenInterfaceAVKit::willStartPictureInPicture):
+        (VideoFullscreenInterfaceAVKit::didStartPictureInPicture):
+        (VideoFullscreenInterfaceAVKit::failedToStartPictureInPicture):
+        (VideoFullscreenInterfaceAVKit::willStopPictureInPicture):
+        (VideoFullscreenInterfaceAVKit::didStopPictureInPicture):
+        (VideoFullscreenInterfaceAVKit::prepareForPictureInPictureStopWithCompletionHandler):
+        (VideoFullscreenInterfaceAVKit::shouldExitFullscreenWithReason):
+        (VideoFullscreenInterfaceAVKit::setMode):
+        (VideoFullscreenInterfaceAVKit::clearMode):
+        (VideoFullscreenInterfaceAVKit::setHasVideoContentLayer):
+        (VideoFullscreenInterfaceAVKit::setInlineRect):
+        (VideoFullscreenInterfaceAVKit::doSetup):
+        (VideoFullscreenInterfaceAVKit::finalizeSetup):
+        (VideoFullscreenInterfaceAVKit::doEnterFullscreen):
+        (VideoFullscreenInterfaceAVKit::doExitFullscreen):
+        (VideoFullscreenInterfaceAVKit::exitFullscreenHandler):
+        (VideoFullscreenInterfaceAVKit::enterFullscreenHandler):
+        (VideoFullscreenInterfaceAVKit::returnToStandby):
+        * platform/ios/WebVideoFullscreenControllerAVKit.mm:
+        (VideoFullscreenControllerContext::requestUpdateInlineRect):
+        (VideoFullscreenControllerContext::requestVideoContentLayer):
+        (VideoFullscreenControllerContext::returnVideoContentLayer):
+        (VideoFullscreenControllerContext::didSetupFullscreen):
+        (VideoFullscreenControllerContext::didExitFullscreen):
+        (VideoFullscreenControllerContext::setUpFullscreen):
+
 2017-12-20  Ryosuke Niwa  <rniwa@webkit.org>
 
         DeferredLoadingScope incorrectly disabled images or enables deferred loading
index 068b393..bfcbe3e 100644 (file)
@@ -5840,7 +5840,7 @@ void HTMLMediaElement::enterFullscreen(VideoFullscreenMode mode)
     if (document().page() && is<HTMLVideoElement>(*this)) {
         HTMLVideoElement& asVideo = downcast<HTMLVideoElement>(*this);
         if (document().page()->chrome().client().supportsVideoFullscreen(m_videoFullscreenMode)) {
-            document().page()->chrome().client().enterVideoFullscreenForVideoElement(asVideo, m_videoFullscreenMode);
+            document().page()->chrome().client().enterVideoFullscreenForVideoElement(asVideo, m_videoFullscreenMode, m_videoFullscreenStandby);
             scheduleEvent(eventNames().webkitbeginfullscreenEvent);
         }
     }
@@ -5892,11 +5892,34 @@ void HTMLMediaElement::exitFullscreen()
     else
 #endif
     if (document().page()->chrome().client().supportsVideoFullscreen(oldVideoFullscreenMode)) {
-        document().page()->chrome().client().exitVideoFullscreenForVideoElement(downcast<HTMLVideoElement>(*this));
+        if (m_videoFullscreenStandby)
+            document().page()->chrome().client().enterVideoFullscreenForVideoElement(downcast<HTMLVideoElement>(*this), m_videoFullscreenMode, m_videoFullscreenStandby);
+        else
+            document().page()->chrome().client().exitVideoFullscreenForVideoElement(downcast<HTMLVideoElement>(*this));
         scheduleEvent(eventNames().webkitendfullscreenEvent);
     }
 }
 
+WEBCORE_EXPORT void HTMLMediaElement::setVideoFullscreenStandby(bool value)
+{
+    ASSERT(is<HTMLVideoElement>(*this));
+    if (m_videoFullscreenStandby == value)
+        return;
+
+    if (!document().page())
+        return;
+
+    if (!document().page()->chrome().client().supportsVideoFullscreenStandby())
+        return;
+
+    m_videoFullscreenStandby = value;
+
+    if (m_videoFullscreenStandby || m_videoFullscreenMode != VideoFullscreenModeNone)
+        document().page()->chrome().client().enterVideoFullscreenForVideoElement(downcast<HTMLVideoElement>(*this), m_videoFullscreenMode, m_videoFullscreenStandby);
+    else
+        document().page()->chrome().client().exitVideoFullscreenForVideoElement(downcast<HTMLVideoElement>(*this));
+}
+
 void HTMLMediaElement::willBecomeFullscreenElement()
 {
 #if PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE)
@@ -7446,7 +7469,7 @@ bool HTMLMediaElement::shouldOverrideBackgroundPlaybackRestriction(PlatformMedia
         if (m_videoFullscreenMode & VideoFullscreenModePictureInPicture)
             return true;
 #if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
-        if (m_videoFullscreenMode == VideoFullscreenModeStandard && supportsPictureInPicture() && isPlaying())
+        if (((m_videoFullscreenMode == VideoFullscreenModeStandard) || m_videoFullscreenStandby) && supportsPictureInPicture() && isPlaying())
             return true;
 #endif
     } else if (type == PlatformMediaSession::SuspendedUnderLock) {
index 1128f9e..b4cbd91 100644 (file)
@@ -422,6 +422,7 @@ public:
     void enterFullscreen(VideoFullscreenMode);
     void enterFullscreen() override;
     WEBCORE_EXPORT void exitFullscreen();
+    WEBCORE_EXPORT void setVideoFullscreenStandby(bool);
 
     bool hasClosedCaptions() const override;
     bool closedCaptionsVisible() const override;
@@ -977,6 +978,7 @@ private:
     RefPtr<HTMLSourceElement> m_nextChildNodeToConsider;
 
     VideoFullscreenMode m_videoFullscreenMode { VideoFullscreenModeNone };
+    bool m_videoFullscreenStandby { false };
     bool m_preparedForInline;
     WTF::Function<void()> m_preparedForInlineCompletionHandler;
 
index 1dfc1f9..3e5c48f 100644 (file)
@@ -334,9 +334,10 @@ public:
 #endif
 
     virtual bool supportsVideoFullscreen(HTMLMediaElementEnums::VideoFullscreenMode) { return false; }
+    virtual bool supportsVideoFullscreenStandby() { return false; }
 
 #if ENABLE(VIDEO)
-    virtual void enterVideoFullscreenForVideoElement(HTMLVideoElement&, HTMLMediaElementEnums::VideoFullscreenMode) { }
+    virtual void enterVideoFullscreenForVideoElement(HTMLVideoElement&, HTMLMediaElementEnums::VideoFullscreenMode, bool standby) { UNUSED_PARAM(standby); }
     virtual void setUpPlaybackControlsManager(HTMLMediaElement&) { }
     virtual void clearPlaybackControlsManager() { }
 #endif
index c5c15b1..5b04fd3 100644 (file)
@@ -33,6 +33,9 @@ namespace WebCore {
 class VideoFullscreenChangeObserver {
 public:
     virtual ~VideoFullscreenChangeObserver() { };
+    virtual void requestUpdateInlineRect() = 0;
+    virtual void requestVideoContentLayer() = 0;
+    virtual void returnVideoContentLayer() = 0;
     virtual void didSetupFullscreen() = 0;
     virtual void didEnterFullscreen() = 0;
     virtual void didExitFullscreen() = 0;
index 1277103..e7149a4 100644 (file)
@@ -49,6 +49,7 @@ OBJC_CLASS WebAVPlayerController;
 OBJC_CLASS WebAVPlayerLayerView;
 OBJC_CLASS WebAVPlayerLayer;
 OBJC_CLASS WebAVPlayerViewControllerDelegate;
+OBJC_CLASS NSError;
 
 namespace WTF {
 class String;
@@ -79,13 +80,17 @@ public:
     // PlaybackSessionModelClient
     WEBCORE_EXPORT void externalPlaybackChanged(bool enabled, PlaybackSessionModel::ExternalPlaybackTargetType, const String& localizedDeviceName) final;
 
-    WEBCORE_EXPORT virtual void setupFullscreen(UIView&, const IntRect& initialRect, UIView *, HTMLMediaElementEnums::VideoFullscreenMode, bool allowsPictureInPicturePlayback);
-    WEBCORE_EXPORT virtual void enterFullscreen();
-    WEBCORE_EXPORT virtual void exitFullscreen(const IntRect& finalRect);
-    WEBCORE_EXPORT virtual void cleanupFullscreen();
-    WEBCORE_EXPORT virtual void invalidate();
-    WEBCORE_EXPORT virtual void requestHideAndExitFullscreen();
-    WEBCORE_EXPORT virtual void preparedToReturnToInline(bool visible, const IntRect& inlineRect);
+    WEBCORE_EXPORT void setupFullscreen(UIView&, const IntRect& initialRect, UIView *, HTMLMediaElementEnums::VideoFullscreenMode, bool allowsPictureInPicturePlayback, bool standby);
+    WEBCORE_EXPORT void enterFullscreen();
+    WEBCORE_EXPORT void exitFullscreen(const IntRect& finalRect);
+    WEBCORE_EXPORT void cleanupFullscreen();
+    WEBCORE_EXPORT void invalidate();
+    WEBCORE_EXPORT void requestHideAndExitFullscreen();
+    WEBCORE_EXPORT void preparedToReturnToInline(bool visible, const IntRect& inlineRect);
+#if ENABLE(FULLSCREEN_API)
+    WEBCORE_EXPORT void setHasVideoContentLayer(bool);
+    WEBCORE_EXPORT void setInlineRect(const IntRect&, bool visible);
+#endif
 
     enum class ExitFullScreenReason {
         DoneButtonTapped,
@@ -95,9 +100,41 @@ public:
         PictureInPictureStarted
     };
 
+    class Mode {
+        HTMLMediaElementEnums::VideoFullscreenMode m_mode { HTMLMediaElementEnums::VideoFullscreenModeNone };
+
+    public:
+        Mode() = default;
+        Mode(const Mode&) = default;
+        Mode(HTMLMediaElementEnums::VideoFullscreenMode mode) : m_mode(mode) { }
+        void operator=(HTMLMediaElementEnums::VideoFullscreenMode mode) { m_mode = mode; }
+        HTMLMediaElementEnums::VideoFullscreenMode mode() const { return m_mode; }
+
+        void setModeValue(HTMLMediaElementEnums::VideoFullscreenMode mode, bool value) { value ? setMode(mode) : clearMode(mode); }
+        void setMode(HTMLMediaElementEnums::VideoFullscreenMode mode) { m_mode |= mode; }
+        void clearMode(HTMLMediaElementEnums::VideoFullscreenMode mode) { m_mode &= ~mode; }
+        bool hasMode(HTMLMediaElementEnums::VideoFullscreenMode mode) const { return m_mode & mode; }
+
+        bool isPictureInPicture() const { return m_mode == HTMLMediaElementEnums::VideoFullscreenModePictureInPicture; }
+        bool isFullscreen() const { return m_mode == HTMLMediaElementEnums::VideoFullscreenModeStandard; }
+
+        void setPictureInPicture(bool value) { setModeValue(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture, value); }
+        void setFullscreen(bool value) { setModeValue(HTMLMediaElementEnums::VideoFullscreenModeStandard, value); }
+
+        bool hasFullscreen() const { return hasMode(HTMLMediaElementEnums::VideoFullscreenModeStandard); }
+        bool hasPictureInPicture() const { return hasMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture); }
+
+        bool hasVideo() const { return m_mode & (HTMLMediaElementEnums::VideoFullscreenModeStandard | HTMLMediaElementEnums::VideoFullscreenModePictureInPicture); }
+    };
+
+    Mode m_currentMode;
+#if ENABLE(FULLSCREEN_API)
+    Mode m_targetMode;
+#endif
+
     VideoFullscreenModel* model() const { return m_videoFullscreenModel; }
     bool shouldExitFullscreenWithReason(ExitFullScreenReason);
-    HTMLMediaElementEnums::VideoFullscreenMode mode() const { return m_mode; }
+    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);
@@ -110,17 +147,28 @@ public:
     void willStopPictureInPicture();
     void didStopPictureInPicture();
     void prepareForPictureInPictureStopWithCompletionHandler(void (^)(BOOL));
+#if ENABLE(FULLSCREEN_API)
+    void exitFullscreenHandler(BOOL success, NSError *);
+    void enterFullscreenHandler(BOOL success, NSError *);
+#endif
 
     void setMode(HTMLMediaElementEnums::VideoFullscreenMode);
     void clearMode(HTMLMediaElementEnums::VideoFullscreenMode);
-    bool hasMode(HTMLMediaElementEnums::VideoFullscreenMode mode) const { return m_mode & mode; }
-    bool isMode(HTMLMediaElementEnums::VideoFullscreenMode mode) const { return m_mode == mode; }
+    bool hasMode(HTMLMediaElementEnums::VideoFullscreenMode mode) const { return m_currentMode.hasMode(mode); }
 
 protected:
     WEBCORE_EXPORT VideoFullscreenInterfaceAVKit(PlaybackSessionInterfaceAVKit&);
-    void beginSession();
+
+#if ENABLE(FULLSCREEN_API)
+    void doSetup();
+    void finalizeSetup();
+    void doExitFullscreen();
+    void returnToStandby();
+#else
     void enterPictureInPicture();
     void enterFullscreenStandard();
+#endif
+    void doEnterFullscreen();
     void watchdogTimerFired();
     WebAVPlayerController *playerController() const;
 
@@ -133,25 +181,52 @@ protected:
     // These are only used when fullscreen is presented in a separate window.
     RetainPtr<UIWindow> m_window;
     RetainPtr<UIViewController> m_viewController;
+    RetainPtr<UIView> m_videoView;
     RetainPtr<UIView> m_parentView;
     RetainPtr<UIWindow> m_parentWindow;
     RetainPtr<WebAVPlayerLayerView> m_playerLayerView;
-    HTMLMediaElementEnums::VideoFullscreenMode m_mode { HTMLMediaElementEnums::VideoFullscreenModeNone };
     WTF::Function<void(bool)> m_prepareToInlineCallback;
     RunLoop::Timer<VideoFullscreenInterfaceAVKit> m_watchdogTimer;
+    FloatRect m_inlineRect;
     bool m_allowsPictureInPicturePlayback { false };
-    bool m_exitRequested { false };
-    bool m_exitCompleted { false };
-    bool m_enterRequested { false };
     bool m_wirelessVideoPlaybackDisabled { true };
     bool m_shouldReturnToFullscreenWhenStoppingPiP { false };
-    bool m_shouldReturnToFullscreenAfterEnteringForeground { false };
     bool m_restoringFullscreenForPictureInPictureStop { false };
 
-    void doEnterFullscreen();
+#if ENABLE(FULLSCREEN_API)
+    bool m_setupNeedsInlineRect { false };
+    bool m_exitFullscreenNeedInlineRect { false };
+
+    bool m_finalizeSetupNeedsVideoContentLayer { false };
+    bool m_cleanupNeedsReturnVideoContentLayer { false };
+
+    bool m_returnToStandbyNeedsReturnVideoContentLayer { false };
+    bool m_finalizeSetupNeedsReturnVideoContentLayer { false };
+
+    bool m_exitFullscreenNeedsExitFullscreen { false };
+    bool m_exitFullscreenNeedsExitPictureInPicture { false };
+    bool m_exitFullscreenNeedsReturnContentLayer { false };
+
+    bool m_enterFullscreenNeedsEnterFullscreen { false };
+    bool m_enterFullscreenNeedsExitFullscreen { false };
+    bool m_enterFullscreenNeedsEnterPictureInPicture { false };
+    bool m_enterFullscreenNeedsExitPictureInPicture { false };
+
+    bool m_hasVideoContentLayer { false };
+
+    bool m_hasUpdatedInlineRect { false };
+    bool m_inlineIsVisible { false };
+    bool m_standby { false };
+    bool m_targetStandby { false };
+#else
+    bool m_exitRequested { false };
+    bool m_exitCompleted { false };
+    bool m_enterRequested { false };
+    bool m_shouldReturnToFullscreenAfterEnteringForeground { false };
+#endif
 };
 
 }
 
-#endif
+#endif // PLATFORM(IOS)
 
index 8c5b179..cab2eda 100644 (file)
@@ -72,6 +72,14 @@ SOFT_LINK_CLASS(UIKit, UIViewController)
 SOFT_LINK_CLASS(UIKit, UIColor)
 SOFT_LINK_CONSTANT(UIKit, UITextEffectsBeneathStatusBarWindowLevel, UIWindowLevel)
 
+@interface UIWindow ()
+- (BOOL)_isHostedInAnotherProcess;
+@end
+
+@interface UIViewController ()
+@property (nonatomic, assign, setter=_setIgnoreAppSupportedOrientations:) BOOL _ignoreAppSupportedOrientations;
+@end
+
 static UIColor *clearUIColor()
 {
     return (UIColor *)[getUIColorClass() clearColor];
@@ -164,6 +172,15 @@ static VideoFullscreenInterfaceAVKit::ExitFullScreenReason convertToExitFullScre
     UNUSED_PARAM(playerViewController);
     self.fullscreenInterface->prepareForPictureInPictureStopWithCompletionHandler(completionHandler);
 }
+
+#if ENABLE(FULLSCREEN_API)
+- (BOOL)playerViewControllerShouldStartPictureInPictureFromInlineWhenEnteringBackground:(AVPlayerViewController *)playerViewController
+{
+    UNUSED_PARAM(playerViewController);
+    return YES;
+}
+#endif
+
 @end
 
 @interface WebAVPlayerLayer : CALayer
@@ -269,7 +286,7 @@ static VideoFullscreenInterfaceAVKit::ExitFullScreenReason convertToExitFullScre
     [view setTransform:transform];
     
     NSTimeInterval animationDuration = [CATransaction animationDuration];
-    dispatch_async(dispatch_get_main_queue(), ^ {
+    dispatch_async(dispatch_get_main_queue(), ^{
         [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(resolveBounds) object:nil];
 
         [self performSelector:@selector(resolveBounds) withObject:nil afterDelay:animationDuration + 0.1];
@@ -362,7 +379,7 @@ static WebAVPictureInPicturePlayerLayerView *allocWebAVPictureInPicturePlayerLay
 {
     static Class theClass = nil;
     static dispatch_once_t onceToken;
-    dispatch_once(&onceToken, ^ {
+    dispatch_once(&onceToken, ^{
         theClass = objc_allocateClassPair(getUIViewClass(), "WebAVPictureInPicturePlayerLayerView", 0);
         objc_registerClassPair(theClass);
         Class metaClass = objc_getMetaClass("WebAVPictureInPicturePlayerLayerView");
@@ -468,7 +485,7 @@ static WebAVPlayerLayerView *allocWebAVPlayerLayerViewInstance()
 {
     static Class theClass = nil;
     static dispatch_once_t onceToken;
-    dispatch_once(&onceToken, ^ {
+    dispatch_once(&onceToken, ^{
         theClass = objc_allocateClassPair(get__AVPlayerLayerViewClass(), "WebAVPlayerLayerView", 0);
         class_addMethod(theClass, @selector(dealloc), (IMP)WebAVPlayerLayerView_dealloc, "v@:");
         class_addMethod(theClass, @selector(setPlayerController:), (IMP)WebAVPlayerLayerView_setPlayerController, "v@:@");
@@ -560,6 +577,8 @@ void VideoFullscreenInterfaceAVKit::externalPlaybackChanged(bool enabled, Playba
     [m_playerLayerView setHidden:enabled];
 }
 
+#if !ENABLE(FULLSCREEN_API)
+
 void VideoFullscreenInterfaceAVKit::applicationDidBecomeActive()
 {
     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::applicationDidBecomeActive(%p)", this);
@@ -570,38 +589,33 @@ void VideoFullscreenInterfaceAVKit::applicationDidBecomeActive()
 
     // If we are both in PiP and in Fullscreen (i.e., via auto-PiP), and we did not stop fullscreen upon returning, it must be
     // because the originating view is not visible, so hide the fullscreen window.
-    if (isMode(HTMLMediaElementEnums::VideoFullscreenModeStandard | HTMLMediaElementEnums::VideoFullscreenModePictureInPicture)) {
-        RefPtr<VideoFullscreenInterfaceAVKit> protectedThis(this);
-        [m_playerViewController exitFullScreenAnimated:NO completionHandler:[protectedThis, this] (BOOL, NSError*) {
+    if (m_currentMode.hasFullscreen() && m_currentMode.hasPictureInPicture()) {
+        [m_playerViewController exitFullScreenAnimated:NO completionHandler:[protectedThis = makeRefPtr(this), this] (BOOL, NSError *) {
             [m_window setHidden:YES];
             [[m_playerViewController view] setHidden:YES];
         }];
     }
 }
 
-@interface UIWindow ()
-- (BOOL)_isHostedInAnotherProcess;
-@end
-
-@interface UIViewController ()
-@property (nonatomic, assign, setter=_setIgnoreAppSupportedOrientations:) BOOL _ignoreAppSupportedOrientations;
-@end
-
-void VideoFullscreenInterfaceAVKit::setupFullscreen(UIView& videoView, const WebCore::IntRect& initialRect, UIView* parentView, HTMLMediaElementEnums::VideoFullscreenMode mode, bool allowsPictureInPicturePlayback)
+void VideoFullscreenInterfaceAVKit::setupFullscreen(UIView& videoView, const IntRect& initialRect, UIView* parentView, HTMLMediaElementEnums::VideoFullscreenMode mode, bool allowsPictureInPicturePlayback, bool standby)
 {
     ASSERT(mode != HTMLMediaElementEnums::VideoFullscreenModeNone);
     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::setupFullscreen(%p)", this);
 
     m_allowsPictureInPicturePlayback = allowsPictureInPicturePlayback;
+    m_videoView = &videoView;
+    m_parentView = parentView;
+    m_parentWindow = parentView.window;
+
+    ASSERT_UNUSED(standby, !standby);
+    bool isInPictureInPictureMode = m_currentMode.hasPictureInPicture();
+    m_currentMode = mode;
+    m_inlineRect = initialRect;
 
     [CATransaction begin];
     [CATransaction setDisableActions:YES];
-    bool isInPictureInPictureMode = hasMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
-    m_mode = mode;
-    m_parentView = parentView;
-    m_parentWindow = parentView.window;
 
-    if (![[parentView window] _isHostedInAnotherProcess]) {
+    if (![[m_parentView window] _isHostedInAnotherProcess]) {
         if (!m_window)
             m_window = adoptNS([allocUIWindowInstance() initWithFrame:[[getUIScreenClass() mainScreen] bounds]]);
         [m_window setBackgroundColor:clearUIColor()];
@@ -620,13 +634,13 @@ void VideoFullscreenInterfaceAVKit::setupFullscreen(UIView& videoView, const Web
     [m_playerLayerView setBackgroundColor:clearUIColor()];
 
     if (!isInPictureInPictureMode) {
-        [m_playerLayerView setVideoView:&videoView];
-        [m_playerLayerView addSubview:&videoView];
+        [m_playerLayerView setVideoView:m_videoView.get()];
+        [m_playerLayerView addSubview:m_videoView.get()];
     }
 
     WebAVPlayerLayer *playerLayer = (WebAVPlayerLayer *)[m_playerLayerView playerLayer];
 
-    [playerLayer setModelVideoLayerFrame:CGRectMake(0, 0, initialRect.width(), initialRect.height())];
+    [playerLayer setModelVideoLayerFrame:CGRectMake(0, 0, m_inlineRect.width(), m_inlineRect.height())];
     [playerLayer setVideoDimensions:[playerController() contentDimensions]];
     playerLayer.fullscreenInterface = this;
 
@@ -644,9 +658,9 @@ void VideoFullscreenInterfaceAVKit::setupFullscreen(UIView& videoView, const Web
         [m_viewController addChildViewController:m_playerViewController.get()];
         [[m_viewController view] addSubview:[m_playerViewController view]];
     } else
-        [parentView addSubview:[m_playerViewController view]];
+        [m_parentView addSubview:[m_playerViewController view]];
 
-    [m_playerViewController view].frame = [parentView convertRect:initialRect toView:[m_playerViewController view].superview];
+    [m_playerViewController view].frame = [m_parentView convertRect:m_inlineRect toView:[m_playerViewController view].superview];
 
     [[m_playerViewController view] setBackgroundColor:clearUIColor()];
     [[m_playerViewController view] setAutoresizingMask:(UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin)];
@@ -656,8 +670,7 @@ void VideoFullscreenInterfaceAVKit::setupFullscreen(UIView& videoView, const Web
 
     [CATransaction commit];
 
-    RefPtr<VideoFullscreenInterfaceAVKit> protectedThis(this);
-    dispatch_async(dispatch_get_main_queue(), [protectedThis, this] {
+    dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), this] {
         if (m_fullscreenChangeObserver)
             m_fullscreenChangeObserver->didSetupFullscreen();
     });
@@ -665,15 +678,15 @@ void VideoFullscreenInterfaceAVKit::setupFullscreen(UIView& videoView, const Web
 
 void VideoFullscreenInterfaceAVKit::enterFullscreen()
 {
-    LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::enterFullscreen(%p)", this);
+    LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::enterFullscreen(%p) %d", this, mode());
 
     m_exitCompleted = false;
     m_exitRequested = false;
     m_enterRequested = true;
 
-    if (mode() == HTMLMediaElementEnums::VideoFullscreenModePictureInPicture)
+    if (m_currentMode.isPictureInPicture())
         enterPictureInPicture();
-    else if (mode() == HTMLMediaElementEnums::VideoFullscreenModeStandard)
+    else if (m_currentMode.isFullscreen())
         enterFullscreenStandard();
     else
         ASSERT_NOT_REACHED();
@@ -692,7 +705,6 @@ void VideoFullscreenInterfaceAVKit::enterPictureInPicture()
 void VideoFullscreenInterfaceAVKit::enterFullscreenStandard()
 {
     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::enterFullscreenStandard(%p)", this);
-    RefPtr<VideoFullscreenInterfaceAVKit> protectedThis(this);
 
     if ([m_playerViewController isPictureInPictureActive]) {
         // NOTE: The fullscreen mode will be restored in prepareForPictureInPictureStopWithCompletionHandler().
@@ -701,7 +713,7 @@ void VideoFullscreenInterfaceAVKit::enterFullscreenStandard()
         return;
     }
 
-    [m_playerViewController enterFullScreenAnimated:YES completionHandler:[this, protectedThis] (BOOL succeeded, NSError*) {
+    [m_playerViewController enterFullScreenAnimated:YES completionHandler:[this, protectedThis = makeRefPtr(this)] (BOOL succeeded, NSError*) {
         UNUSED_PARAM(succeeded);
         LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::enterFullscreenStandard - lambda(%p) - succeeded(%s)", this, boolString(succeeded));
         [m_playerViewController setShowsPlaybackControls:YES];
@@ -711,7 +723,7 @@ void VideoFullscreenInterfaceAVKit::enterFullscreenStandard()
     }];
 }
 
-void VideoFullscreenInterfaceAVKit::exitFullscreen(const WebCore::IntRect& finalRect)
+void VideoFullscreenInterfaceAVKit::exitFullscreen(const IntRect& finalRect)
 {
     m_watchdogTimer.stop();
 
@@ -732,20 +744,18 @@ void VideoFullscreenInterfaceAVKit::exitFullscreen(const WebCore::IntRect& final
         [playerLayer setVideoGravity:getAVLayerVideoGravityResizeAspect()];
     [[m_playerViewController view] layoutIfNeeded];
 
-    if (isMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture)) {
+    if (m_currentMode.isPictureInPicture()) {
         m_shouldReturnToFullscreenWhenStoppingPiP = false;
         [m_window setHidden:NO];
         [m_playerViewController stopPictureInPicture];
-    } else if (isMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture | HTMLMediaElementEnums::VideoFullscreenModeStandard)) {
-        RefPtr<VideoFullscreenInterfaceAVKit> protectedThis(this);
-        [m_playerViewController exitFullScreenAnimated:NO completionHandler:[protectedThis, this] (BOOL, NSError*) {
+    } else if (m_currentMode.hasPictureInPicture() && m_currentMode.hasFullscreen()) {
+        [m_playerViewController exitFullScreenAnimated:NO completionHandler:[protectedThis = makeRefPtr(this), this] (BOOL, NSError*) {
             clearMode(HTMLMediaElementEnums::VideoFullscreenModeStandard);
             [m_window setHidden:NO];
             [m_playerViewController stopPictureInPicture];
         }];
-    } else if (isMode(HTMLMediaElementEnums::VideoFullscreenModeStandard)) {
-        RefPtr<VideoFullscreenInterfaceAVKit> protectedThis(this);
-        [m_playerViewController exitFullScreenAnimated:YES completionHandler:[protectedThis, this] (BOOL, NSError*) {
+    } else if (m_currentMode.isFullscreen()) {
+        [m_playerViewController exitFullScreenAnimated:YES completionHandler:[protectedThis = makeRefPtr(this), this] (BOOL, NSError*) () mutable {
             m_exitCompleted = true;
 
             [CATransaction begin];
@@ -754,7 +764,7 @@ void VideoFullscreenInterfaceAVKit::exitFullscreen(const WebCore::IntRect& final
             [[m_playerViewController view] setBackgroundColor:clearUIColor()];
             [CATransaction commit];
 
-            dispatch_async(dispatch_get_main_queue(), [protectedThis, this]() {
+            dispatch_async(dispatch_get_main_queue(), [protectedThis = WTFMove(protectedThis), this]() {
                 if (m_fullscreenChangeObserver)
                     m_fullscreenChangeObserver->didExitFullscreen();
             });
@@ -765,6 +775,7 @@ void VideoFullscreenInterfaceAVKit::exitFullscreen(const WebCore::IntRect& final
 void VideoFullscreenInterfaceAVKit::cleanupFullscreen()
 {
     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::cleanupFullscreen(%p)", this);
+
     if (m_window) {
         [m_window setHidden:YES];
         [m_window setRootViewController:nil];
@@ -773,9 +784,9 @@ void VideoFullscreenInterfaceAVKit::cleanupFullscreen()
     [m_playerViewController setDelegate:nil];
     [m_playerViewController setPlayerController:nil];
     
-    if (hasMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture))
+    if (m_currentMode.hasPictureInPicture())
         [m_playerViewController stopPictureInPicture];
-    if (hasMode(HTMLMediaElementEnums::VideoFullscreenModeStandard))
+    if (m_currentMode.hasFullscreen())
         [m_playerViewController exitFullScreenAnimated:NO completionHandler:[] (BOOL, NSError *) { }];
     
     [[m_playerViewController view] removeFromSuperview];
@@ -788,6 +799,7 @@ void VideoFullscreenInterfaceAVKit::cleanupFullscreen()
     m_playerLayerView = nil;
     m_playerViewController = nil;
     m_window = nil;
+    m_videoView = nil;
     m_parentView = nil;
     m_parentWindow = nil;
     
@@ -810,7 +822,7 @@ void VideoFullscreenInterfaceAVKit::requestHideAndExitFullscreen()
     if (!m_enterRequested)
         return;
     
-    if (hasMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture))
+    if (m_currentMode.hasPictureInPicture())
         return;
     
     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::requestHideAndExitFullscreen(%p)", this);
@@ -828,9 +840,7 @@ void VideoFullscreenInterfaceAVKit::preparedToReturnToInline(bool visible, const
 {
     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::preparedToReturnToInline(%p) - visible(%s)", this, boolString(visible));
     if (m_prepareToInlineCallback) {
-        
         [m_playerViewController view].frame = [m_parentView convertRect:inlineRect toView:[m_playerViewController view].superview];
-
         WTF::Function<void(bool)> callback = WTFMove(m_prepareToInlineCallback);
         callback(visible);
     }
@@ -838,7 +848,7 @@ void VideoFullscreenInterfaceAVKit::preparedToReturnToInline(bool visible, const
 
 bool VideoFullscreenInterfaceAVKit::mayAutomaticallyShowVideoPictureInPicture() const
 {
-    return [playerController() isPlaying] && m_mode == HTMLMediaElementEnums::VideoFullscreenModeStandard && supportsPictureInPicture();
+    return [playerController() isPlaying] && m_currentMode.isFullscreen() && supportsPictureInPicture();
 }
 
 void VideoFullscreenInterfaceAVKit::fullscreenMayReturnToInline(WTF::Function<void(bool)>&& callback)
@@ -860,10 +870,9 @@ void VideoFullscreenInterfaceAVKit::didStartPictureInPicture()
     m_shouldReturnToFullscreenAfterEnteringForeground = [m_playerViewController pictureInPictureWasStartedWhenEnteringBackground];
     [m_playerViewController setShowsPlaybackControls:YES];
 
-    if (m_mode & HTMLMediaElementEnums::VideoFullscreenModeStandard) {
+    if (m_currentMode.hasFullscreen()) {
         if (![m_playerViewController pictureInPictureWasStartedWhenEnteringBackground]) {
-            RefPtr<VideoFullscreenInterfaceAVKit> protectedThis(this);
-            [m_playerViewController exitFullScreenAnimated:YES completionHandler:[protectedThis, this] (BOOL, NSError*) {
+            [m_playerViewController exitFullScreenAnimated:YES completionHandler:[protectedThis = makeRefPtr(this), this] (BOOL, NSError *) {
                 [m_window setHidden:YES];
                 [[m_playerViewController view] setHidden:YES];
             }];
@@ -882,7 +891,7 @@ void VideoFullscreenInterfaceAVKit::failedToStartPictureInPicture()
     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::failedToStartPictureInPicture(%p)", this);
     [m_playerViewController setShowsPlaybackControls:YES];
 
-    if (hasMode(HTMLMediaElementEnums::VideoFullscreenModeStandard))
+    if (m_currentMode.hasFullscreen())
         return;
 
     m_exitCompleted = true;
@@ -896,11 +905,12 @@ void VideoFullscreenInterfaceAVKit::failedToStartPictureInPicture()
 
 void VideoFullscreenInterfaceAVKit::willStopPictureInPicture()
 {
+    LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::willStopPictureInPicture(%p)", this);
+
     m_shouldReturnToFullscreenWhenStoppingPiP = false;
     m_shouldReturnToFullscreenAfterEnteringForeground = false;
 
-    LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::willStopPictureInPicture(%p)", this);
-    if (hasMode(HTMLMediaElementEnums::VideoFullscreenModeStandard) || m_restoringFullscreenForPictureInPictureStop)
+    if (m_currentMode.hasFullscreen() || m_restoringFullscreenForPictureInPictureStop)
         return;
 
     [m_window setHidden:NO];
@@ -913,10 +923,11 @@ void VideoFullscreenInterfaceAVKit::willStopPictureInPicture()
 void VideoFullscreenInterfaceAVKit::didStopPictureInPicture()
 {
     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::didStopPictureInPicture(%p)", this);
-    if (hasMode(HTMLMediaElementEnums::VideoFullscreenModeStandard) || m_restoringFullscreenForPictureInPictureStop) {
-        // ASSUMPTION: we are exiting pip because we are entering fullscreen
+
+    if (m_currentMode.hasFullscreen() || m_restoringFullscreenForPictureInPictureStop) {
         clearMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
         [m_playerViewController setShowsPlaybackControls:YES];
+
         return;
     }
 
@@ -926,7 +937,7 @@ void VideoFullscreenInterfaceAVKit::didStopPictureInPicture()
     [[m_playerViewController view] setBackgroundColor:clearUIColor()];
 
     clearMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
-    
+
     if (m_fullscreenChangeObserver)
         m_fullscreenChangeObserver->didExitFullscreen();
 }
@@ -935,14 +946,16 @@ void VideoFullscreenInterfaceAVKit::prepareForPictureInPictureStopWithCompletion
 {
     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::prepareForPictureInPictureStopWithCompletionHandler(%p)", this);
     if (m_shouldReturnToFullscreenWhenStoppingPiP || m_shouldReturnToFullscreenAfterEnteringForeground) {
-        m_shouldReturnToFullscreenWhenStoppingPiP = false;
+
         m_shouldReturnToFullscreenAfterEnteringForeground = false;
+        m_shouldReturnToFullscreenWhenStoppingPiP = false;
         m_restoringFullscreenForPictureInPictureStop = true;
 
         [m_window setHidden:NO];
         [[m_playerViewController view] setHidden:NO];
 
-        [m_playerViewController enterFullScreenAnimated:YES completionHandler:^(BOOL success, NSError*) {
+        [m_playerViewController enterFullScreenAnimated:YES completionHandler:^(BOOL success, NSError *error) {
+            UNUSED_PARAM(error);
             m_restoringFullscreenForPictureInPictureStop = false;
             setMode(HTMLMediaElementEnums::VideoFullscreenModeStandard);
             completionHandler(success);
@@ -952,12 +965,9 @@ void VideoFullscreenInterfaceAVKit::prepareForPictureInPictureStopWithCompletion
         return;
     }
 
-    RefPtr<VideoFullscreenInterfaceAVKit> protectedThis(this);
-    RetainPtr<id> strongCompletionHandler = adoptNS([completionHandler copy]);
-    fullscreenMayReturnToInline([protectedThis, strongCompletionHandler](bool restored)  {
+    fullscreenMayReturnToInline([protectedThis = makeRefPtr(this), strongCompletionHandler = adoptNS([completionHandler copy])](bool restored)  {
         LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::prepareForPictureInPictureStopWithCompletionHandler lambda(%p) - restored(%s)", protectedThis.get(), boolString(restored));
-        void (^completionHandler)(BOOL restored) = strongCompletionHandler.get();
-        completionHandler(restored);
+        ((void (^)(BOOL))strongCompletionHandler.get())(restored);
     });
 }
 
@@ -970,7 +980,7 @@ bool VideoFullscreenInterfaceAVKit::shouldExitFullscreenWithReason(VideoFullscre
         if ([m_playerViewController pictureInPictureWasStartedWhenEnteringBackground])
             return false;
 
-        m_shouldReturnToFullscreenWhenStoppingPiP = hasMode(HTMLMediaElementEnums::VideoFullscreenModeStandard);
+        m_shouldReturnToFullscreenWhenStoppingPiP = m_currentMode.hasFullscreen();
         clearMode(HTMLMediaElementEnums::VideoFullscreenModeStandard);
         return true;
     }
@@ -987,6 +997,565 @@ bool VideoFullscreenInterfaceAVKit::shouldExitFullscreenWithReason(VideoFullscre
     return false;
 }
 
+#else // ENABLE(FULLSCREEN_API)
+
+void VideoFullscreenInterfaceAVKit::applicationDidBecomeActive()
+{
+    LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::applicationDidBecomeActive(%p)", this);
+
+    // If we are both in PiP and in Fullscreen (i.e., via auto-PiP), and we did not stop fullscreen upon returning, it must be
+    // because the originating view is not visible, so hide the fullscreen window.
+    if (m_currentMode.hasFullscreen() && m_currentMode.hasPictureInPicture()) {
+        [m_playerViewController exitFullScreenAnimated:NO completionHandler:[protectedThis = makeRefPtr(this), this] (BOOL success, NSError *error) {
+            exitFullscreenHandler(success, error);
+        }];
+    }
+}
+
+void VideoFullscreenInterfaceAVKit::setupFullscreen(UIView& videoView, const IntRect& initialRect, UIView* parentView, HTMLMediaElementEnums::VideoFullscreenMode mode, bool allowsPictureInPicturePlayback, bool standby)
+{
+    ASSERT(standby || mode != HTMLMediaElementEnums::VideoFullscreenModeNone);
+    LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::setupFullscreen(%p)", this);
+
+    m_allowsPictureInPicturePlayback = allowsPictureInPicturePlayback;
+    m_videoView = &videoView;
+    m_parentView = parentView;
+    m_parentWindow = parentView.window;
+
+    m_targetStandby = standby;
+    m_targetMode = mode;
+    setInlineRect(initialRect, true);
+    doSetup();
+}
+
+void VideoFullscreenInterfaceAVKit::enterFullscreen()
+{
+    LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::enterFullscreen(%p) %d", this, mode());
+
+    doEnterFullscreen();
+}
+
+void VideoFullscreenInterfaceAVKit::exitFullscreen(const IntRect& finalRect)
+{
+    m_watchdogTimer.stop();
+
+    m_targetMode = HTMLMediaElementEnums::VideoFullscreenModeNone;
+
+    setInlineRect(finalRect, true);
+    doExitFullscreen();
+}
+
+void VideoFullscreenInterfaceAVKit::cleanupFullscreen()
+{
+    LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::cleanupFullscreen(%p)", this);
+
+    m_cleanupNeedsReturnVideoContentLayer = true;
+    if (m_hasVideoContentLayer && m_fullscreenChangeObserver) {
+        m_fullscreenChangeObserver->returnVideoContentLayer();
+        return;
+    }
+    m_cleanupNeedsReturnVideoContentLayer = false;
+
+    if (m_window) {
+        [m_window setHidden:YES];
+        [m_window setRootViewController:nil];
+    }
+    
+    [m_playerViewController setDelegate:nil];
+    [m_playerViewController setPlayerController:nil];
+    
+    if (m_currentMode.hasPictureInPicture())
+        [m_playerViewController stopPictureInPicture];
+    if (m_currentMode.hasFullscreen())
+        [m_playerViewController exitFullScreenAnimated:NO completionHandler:[] (BOOL, NSError *) { }];
+    
+    [[m_playerViewController view] removeFromSuperview];
+    if (m_viewController)
+        [m_playerViewController removeFromParentViewController];
+    
+    [m_playerLayerView removeFromSuperview];
+    [[m_viewController view] removeFromSuperview];
+
+    m_playerLayerView = nil;
+    m_playerViewController = nil;
+    m_window = nil;
+    m_videoView = nil;
+    m_parentView = nil;
+    m_parentWindow = nil;
+    
+    if (m_fullscreenChangeObserver)
+        m_fullscreenChangeObserver->didCleanupFullscreen();
+}
+
+void VideoFullscreenInterfaceAVKit::invalidate()
+{
+    m_videoFullscreenModel = nil;
+    m_fullscreenChangeObserver = nil;
+    
+    cleanupFullscreen();
+}
+
+void VideoFullscreenInterfaceAVKit::requestHideAndExitFullscreen()
+{
+    if (m_currentMode.hasPictureInPicture())
+        return;
+    
+    LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::requestHideAndExitFullscreen(%p)", this);
+
+    [m_window setHidden:YES];
+    [[m_playerViewController view] setHidden:YES];
+
+    if (playbackSessionModel() && m_videoFullscreenModel) {
+        playbackSessionModel()->pause();
+        m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
+    }
+}
+
+void VideoFullscreenInterfaceAVKit::preparedToReturnToInline(bool visible, const IntRect& inlineRect)
+{
+    LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::preparedToReturnToInline(%p) - visible(%s)", this, boolString(visible));
+    setInlineRect(inlineRect, visible);
+    if (m_prepareToInlineCallback) {
+        WTF::Function<void(bool)> callback = WTFMove(m_prepareToInlineCallback);
+        callback(visible);
+    }
+}
+
+bool VideoFullscreenInterfaceAVKit::mayAutomaticallyShowVideoPictureInPicture() const
+{
+    return [playerController() isPlaying] && (m_standby || m_currentMode.isFullscreen()) && supportsPictureInPicture();
+}
+
+void VideoFullscreenInterfaceAVKit::fullscreenMayReturnToInline(WTF::Function<void(bool)>&& callback)
+{
+    m_prepareToInlineCallback = WTFMove(callback);
+    if (m_fullscreenChangeObserver)
+        m_fullscreenChangeObserver->fullscreenMayReturnToInline();
+}
+
+void VideoFullscreenInterfaceAVKit::willStartPictureInPicture()
+{
+    LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::willStartPictureInPicture(%p)", this);
+    if (m_standby && !m_currentMode.hasVideo()) {
+        [m_window setHidden:NO];
+        [[m_playerViewController view] setHidden:NO];
+    }
+
+    if (!m_hasVideoContentLayer)
+        m_fullscreenChangeObserver->requestVideoContentLayer();
+}
+
+void VideoFullscreenInterfaceAVKit::didStartPictureInPicture()
+{
+    LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::didStartPictureInPicture(%p)", this);
+    setMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
+    [m_playerViewController setShowsPlaybackControls:YES];
+
+    if (m_currentMode.hasFullscreen()) {
+        if (![m_playerViewController pictureInPictureWasStartedWhenEnteringBackground]) {
+            [m_playerViewController exitFullScreenAnimated:YES completionHandler:[protectedThis = makeRefPtr(this), this] (BOOL success, NSError *error) {
+                exitFullscreenHandler(success, error);
+            }];
+        }
+    } else {
+        [m_window setHidden:YES];
+        [[m_playerViewController view] setHidden:YES];
+    }
+
+    if (m_enterFullscreenNeedsEnterPictureInPicture)
+        doEnterFullscreen();
+}
+
+void VideoFullscreenInterfaceAVKit::failedToStartPictureInPicture()
+{
+    LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::failedToStartPictureInPicture(%p)", this);
+    [m_playerViewController setShowsPlaybackControls:YES];
+
+    m_targetMode.setPictureInPicture(false);
+    if (m_currentMode.hasFullscreen())
+        return;
+
+    if (m_fullscreenChangeObserver)
+        m_fullscreenChangeObserver->didEnterFullscreen();
+
+    if (m_videoFullscreenModel)
+        m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
+}
+
+void VideoFullscreenInterfaceAVKit::willStopPictureInPicture()
+{
+    LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::willStopPictureInPicture(%p)", this);
+
+    m_shouldReturnToFullscreenWhenStoppingPiP = false;
+
+    if (m_currentMode.hasFullscreen() || m_restoringFullscreenForPictureInPictureStop)
+        return;
+
+    [m_window setHidden:NO];
+    [[m_playerViewController view] setHidden:NO];
+}
+
+void VideoFullscreenInterfaceAVKit::didStopPictureInPicture()
+{
+    LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::didStopPictureInPicture(%p)", this);
+    m_targetMode.setPictureInPicture(false);
+
+    if (m_currentMode.hasFullscreen() || m_restoringFullscreenForPictureInPictureStop) {
+        clearMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
+        [m_playerViewController setShowsPlaybackControls:YES];
+
+        if (m_exitFullscreenNeedsExitPictureInPicture)
+            doExitFullscreen();
+        return;
+    }
+
+    [m_playerLayerView setBackgroundColor:clearUIColor()];
+    [[m_playerViewController view] setBackgroundColor:clearUIColor()];
+
+    if (m_videoFullscreenModel)
+        m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
+
+    clearMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
+
+    if (m_enterFullscreenNeedsExitPictureInPicture)
+        doEnterFullscreen();
+
+    if (m_exitFullscreenNeedsExitPictureInPicture)
+        doExitFullscreen();
+}
+
+void VideoFullscreenInterfaceAVKit::prepareForPictureInPictureStopWithCompletionHandler(void (^completionHandler)(BOOL restored))
+{
+    LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::prepareForPictureInPictureStopWithCompletionHandler(%p)", this);
+    if (m_shouldReturnToFullscreenWhenStoppingPiP) {
+
+        m_shouldReturnToFullscreenWhenStoppingPiP = false;
+        m_restoringFullscreenForPictureInPictureStop = true;
+
+        [m_window setHidden:NO];
+        [[m_playerViewController view] setHidden:NO];
+
+        [m_playerViewController enterFullScreenAnimated:YES completionHandler:^(BOOL success, NSError *error) {
+            enterFullscreenHandler(success, error);
+            completionHandler(success);
+        }];
+        return;
+    }
+
+    fullscreenMayReturnToInline([protectedThis = makeRefPtr(this), strongCompletionHandler = adoptNS([completionHandler copy])](bool restored)  {
+        LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::prepareForPictureInPictureStopWithCompletionHandler lambda(%p) - restored(%s)", protectedThis.get(), boolString(restored));
+        ((void (^)(BOOL))strongCompletionHandler.get())(restored);
+    });
+}
+
+bool VideoFullscreenInterfaceAVKit::shouldExitFullscreenWithReason(VideoFullscreenInterfaceAVKit::ExitFullScreenReason reason)
+{
+    if (!m_videoFullscreenModel)
+        return true;
+
+    if (reason == ExitFullScreenReason::PictureInPictureStarted) {
+        m_shouldReturnToFullscreenWhenStoppingPiP = m_currentMode.hasMode(HTMLMediaElementEnums::VideoFullscreenModeStandard);
+        dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), this] () mutable {
+            [m_playerViewController exitFullScreenAnimated:NO completionHandler:[protectedThis = WTFMove(protectedThis), this] (BOOL success, NSError *error) {
+                exitFullscreenHandler(success, error);
+            }];
+        });
+        return false;
+    }
+
+    if (playbackSessionModel() && (reason == ExitFullScreenReason::DoneButtonTapped || reason == ExitFullScreenReason::RemoteControlStopEventReceived))
+        playbackSessionModel()->pause();
+
+    BOOL finished = reason == ExitFullScreenReason::DoneButtonTapped || reason == ExitFullScreenReason::PinchGestureHandled;
+    m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone, finished);
+
+    if (!m_watchdogTimer.isActive())
+        m_watchdogTimer.startOneShot(defaultWatchdogTimerInterval);
+
+    return false;
+}
+
+void VideoFullscreenInterfaceAVKit::setHasVideoContentLayer(bool value)
+{
+    m_hasVideoContentLayer = value;
+
+    if (m_hasVideoContentLayer && m_finalizeSetupNeedsVideoContentLayer)
+        finalizeSetup();
+    if (!m_hasVideoContentLayer && m_cleanupNeedsReturnVideoContentLayer)
+        cleanupFullscreen();
+    if (!m_hasVideoContentLayer && m_returnToStandbyNeedsReturnVideoContentLayer)
+        returnToStandby();
+    if (!m_hasVideoContentLayer && m_finalizeSetupNeedsReturnVideoContentLayer)
+        finalizeSetup();
+    if (!m_hasVideoContentLayer && m_exitFullscreenNeedsReturnContentLayer)
+        doExitFullscreen();
+}
+
+void VideoFullscreenInterfaceAVKit::setInlineRect(const IntRect& inlineRect, bool visible)
+{
+    m_inlineRect = inlineRect;
+    m_inlineIsVisible = visible;
+    m_hasUpdatedInlineRect = true;
+
+    if (m_playerViewController && m_parentView) {
+        [CATransaction begin];
+        [CATransaction setDisableActions:YES];
+        [m_playerViewController view].frame = [m_parentView convertRect:inlineRect toView:[m_playerViewController view].superview];
+        [CATransaction commit];
+    }
+
+    if (m_setupNeedsInlineRect)
+        doSetup();
+
+    if (m_exitFullscreenNeedInlineRect)
+        doExitFullscreen();
+}
+
+void VideoFullscreenInterfaceAVKit::doSetup()
+{
+    Mode changes { m_currentMode.mode() ^ m_targetMode.mode() };
+
+    if (m_currentMode.hasVideo() && m_targetMode.hasVideo() && (m_standby != m_targetStandby)) {
+        m_standby = m_targetStandby;
+        finalizeSetup();
+        return;
+    }
+
+    if (!m_hasUpdatedInlineRect && m_fullscreenChangeObserver) {
+        m_setupNeedsInlineRect = true;
+        m_fullscreenChangeObserver->requestUpdateInlineRect();
+        return;
+    }
+    m_setupNeedsInlineRect = false;
+
+    [CATransaction begin];
+    [CATransaction setDisableActions:YES];
+    if (![[m_parentView window] _isHostedInAnotherProcess] && !m_window) {
+        if (!m_window)
+            m_window = adoptNS([allocUIWindowInstance() initWithFrame:[[getUIScreenClass() mainScreen] bounds]]);
+        [m_window setBackgroundColor:clearUIColor()];
+        if (!m_viewController)
+            m_viewController = adoptNS([allocUIViewControllerInstance() init]);
+        [[m_viewController view] setFrame:[m_window bounds]];
+        [m_viewController _setIgnoreAppSupportedOrientations:YES];
+        [m_window setRootViewController:m_viewController.get()];
+        [m_window setWindowLevel:getUITextEffectsBeneathStatusBarWindowLevel() + 1];
+        [m_window makeKeyAndVisible];
+    }
+
+    if (!m_playerLayerView)
+        m_playerLayerView = adoptNS([allocWebAVPlayerLayerViewInstance() init]);
+    [m_playerLayerView setHidden:[playerController() isExternalPlaybackActive]];
+    [m_playerLayerView setBackgroundColor:clearUIColor()];
+
+    if (!m_currentMode.hasPictureInPicture()) {
+        [m_playerLayerView setVideoView:m_videoView.get()];
+        [m_playerLayerView addSubview:m_videoView.get()];
+    }
+
+    WebAVPlayerLayer *playerLayer = (WebAVPlayerLayer *)[m_playerLayerView playerLayer];
+
+    [playerLayer setModelVideoLayerFrame:CGRectMake(0, 0, m_inlineRect.width(), m_inlineRect.height())];
+    [playerLayer setVideoDimensions:[playerController() contentDimensions]];
+    playerLayer.fullscreenInterface = this;
+
+    if (!m_playerViewController)
+        m_playerViewController = adoptNS([allocAVPlayerViewControllerInstance() initWithPlayerLayerView:m_playerLayerView.get()]);
+
+    [m_playerViewController setShowsPlaybackControls:NO];
+    [m_playerViewController setPlayerController:(AVPlayerController *)playerController()];
+    [m_playerViewController setDelegate:m_playerViewControllerDelegate.get()];
+    [m_playerViewController setAllowsPictureInPicturePlayback:m_allowsPictureInPicturePlayback];
+
+    [playerController() setPictureInPicturePossible:m_allowsPictureInPicturePlayback];
+
+    if (m_viewController) {
+        [m_viewController addChildViewController:m_playerViewController.get()];
+        [[m_viewController view] addSubview:[m_playerViewController view]];
+    } else
+        [m_parentView addSubview:[m_playerViewController view]];
+
+    [m_playerViewController view].frame = [m_parentView convertRect:m_inlineRect toView:[m_playerViewController view].superview];
+
+    [[m_playerViewController view] setBackgroundColor:clearUIColor()];
+    [[m_playerViewController view] setAutoresizingMask:(UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin)];
+
+    [[m_playerViewController view] setNeedsLayout];
+    [[m_playerViewController view] layoutIfNeeded];
+
+    if (m_targetStandby && !m_currentMode.hasVideo()) {
+        [m_window setHidden:YES];
+        [[m_playerViewController view] setHidden:YES];
+    }
+
+    [CATransaction commit];
+
+    finalizeSetup();
+}
+
+void VideoFullscreenInterfaceAVKit::finalizeSetup()
+{
+    dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), this] {
+        if (m_fullscreenChangeObserver) {
+            if (!m_hasVideoContentLayer && m_targetMode.hasVideo()) {
+                m_finalizeSetupNeedsVideoContentLayer = true;
+                m_fullscreenChangeObserver->requestVideoContentLayer();
+                return;
+            }
+            m_finalizeSetupNeedsVideoContentLayer = false;
+            if (m_hasVideoContentLayer && !m_targetMode.hasVideo()) {
+                m_finalizeSetupNeedsReturnVideoContentLayer = true;
+                m_fullscreenChangeObserver->returnVideoContentLayer();
+                return;
+            }
+            m_finalizeSetupNeedsReturnVideoContentLayer = false;
+            m_fullscreenChangeObserver->didSetupFullscreen();
+        }
+    });
+}
+
+void VideoFullscreenInterfaceAVKit::doEnterFullscreen()
+{
+    m_standby = m_targetStandby;
+
+    if (m_targetMode.hasFullscreen() && !m_currentMode.hasFullscreen()) {
+        m_enterFullscreenNeedsEnterFullscreen = true;
+        [m_playerViewController enterFullScreenAnimated:YES completionHandler:[this, protectedThis = makeRefPtr(this)] (BOOL success, NSError *error) {
+            enterFullscreenHandler(success, error);
+        }];
+        return;
+    }
+    m_enterFullscreenNeedsEnterFullscreen = false;
+
+    if (m_targetMode.hasPictureInPicture() && !m_currentMode.hasPictureInPicture()) {
+        m_enterFullscreenNeedsEnterPictureInPicture = true;
+        if ([m_playerViewController isPictureInPicturePossible])
+            [m_playerViewController startPictureInPicture];
+        else
+            failedToStartPictureInPicture();
+        return;
+    }
+    m_enterFullscreenNeedsEnterPictureInPicture = false;
+
+    if (!m_targetMode.hasFullscreen() && m_currentMode.hasFullscreen()) {
+        m_enterFullscreenNeedsExitFullscreen = true;
+        [m_playerViewController exitFullScreenAnimated:YES completionHandler:[protectedThis = makeRefPtr(this), this] (BOOL success, NSError *error) {
+            exitFullscreenHandler(success, error);
+        }];
+        return;
+    }
+    m_enterFullscreenNeedsExitFullscreen = false;
+
+    if (!m_targetMode.hasPictureInPicture() && m_currentMode.hasPictureInPicture()) {
+        m_enterFullscreenNeedsExitPictureInPicture = true;
+        [m_playerViewController stopPictureInPicture];
+        return;
+    }
+    m_enterFullscreenNeedsExitPictureInPicture = false;
+
+    if (m_fullscreenChangeObserver)
+        m_fullscreenChangeObserver->didEnterFullscreen();
+}
+
+void VideoFullscreenInterfaceAVKit::doExitFullscreen()
+{
+    LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::doExitFullscreen(%p)", this);
+
+    if (m_currentMode.hasVideo() && !m_hasUpdatedInlineRect && m_fullscreenChangeObserver) {
+        m_exitFullscreenNeedInlineRect = true;
+        m_fullscreenChangeObserver->requestUpdateInlineRect();
+        return;
+    }
+    m_exitFullscreenNeedInlineRect = false;
+
+    if (m_currentMode.hasMode(HTMLMediaElementEnums::VideoFullscreenModeStandard)) {
+        m_exitFullscreenNeedsExitFullscreen = true;
+        [m_playerViewController exitFullScreenAnimated:YES completionHandler:[protectedThis = makeRefPtr(this), this] (BOOL success, NSError *error) {
+            exitFullscreenHandler(success, error);
+        }];
+        return;
+    }
+    m_exitFullscreenNeedsExitFullscreen = false;
+
+    if (m_currentMode.hasMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture)) {
+        m_exitFullscreenNeedsExitPictureInPicture = true;
+        m_shouldReturnToFullscreenWhenStoppingPiP = false;
+        [m_window setHidden:NO];
+        [m_playerViewController stopPictureInPicture];
+        return;
+    }
+    m_exitFullscreenNeedsExitPictureInPicture = false;
+
+    if (m_hasVideoContentLayer && m_fullscreenChangeObserver) {
+        m_exitFullscreenNeedsReturnContentLayer = true;
+        m_fullscreenChangeObserver->returnVideoContentLayer();
+        return;
+    }
+    m_exitFullscreenNeedsReturnContentLayer = false;
+
+    m_standby = false;
+
+    dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), this] {
+        if (m_fullscreenChangeObserver)
+            m_fullscreenChangeObserver->didExitFullscreen();
+    });
+}
+
+void VideoFullscreenInterfaceAVKit::exitFullscreenHandler(BOOL success, NSError *)
+{
+    UNUSED_PARAM(success);
+    LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::didExitFullscreen(%p) - %d", this, success);
+
+    clearMode(HTMLMediaElementEnums::VideoFullscreenModeStandard);
+
+    if (hasMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture)) {
+        [m_window setHidden:YES];
+        [[m_playerViewController view] setHidden:YES];
+    } else {
+        [CATransaction begin];
+        [CATransaction setDisableActions:YES];
+        [m_playerLayerView setBackgroundColor:clearUIColor()];
+        [[m_playerViewController view] setBackgroundColor:clearUIColor()];
+        [CATransaction commit];
+    }
+
+    if (m_enterFullscreenNeedsExitFullscreen)
+        doEnterFullscreen();
+    
+    if (m_exitFullscreenNeedsExitFullscreen)
+        doExitFullscreen();
+}
+
+void VideoFullscreenInterfaceAVKit::enterFullscreenHandler(BOOL success, NSError *)
+{
+    UNUSED_PARAM(success);
+    LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::enterFullscreenStandard - lambda(%p) - success(%s)", this, boolString(success));
+
+    setMode(HTMLMediaElementEnums::VideoFullscreenModeStandard);
+    [m_playerViewController setShowsPlaybackControls:YES];
+
+    m_restoringFullscreenForPictureInPictureStop = false;
+
+    if (m_enterFullscreenNeedsEnterFullscreen)
+        doEnterFullscreen();
+}
+
+void VideoFullscreenInterfaceAVKit::returnToStandby()
+{
+    if (m_hasVideoContentLayer && m_fullscreenChangeObserver) {
+        m_returnToStandbyNeedsReturnVideoContentLayer = true;
+        m_fullscreenChangeObserver->returnVideoContentLayer();
+        return;
+    }
+
+    m_returnToStandbyNeedsReturnVideoContentLayer = false;
+
+    [m_window setHidden:YES];
+    [[m_playerViewController view] setHidden:YES];
+}
+
+#endif // ENABLE(FULLSCREEN_API)
+
 NO_RETURN_DUE_TO_ASSERT void VideoFullscreenInterfaceAVKit::watchdogTimerFired()
 {
     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::watchdogTimerFired(%p) - no exit fullscreen response in %gs; forcing fullscreen hidden.", this, defaultWatchdogTimerInterval.value());
@@ -997,24 +1566,22 @@ NO_RETURN_DUE_TO_ASSERT void VideoFullscreenInterfaceAVKit::watchdogTimerFired()
 
 void VideoFullscreenInterfaceAVKit::setMode(HTMLMediaElementEnums::VideoFullscreenMode mode)
 {
-    HTMLMediaElementEnums::VideoFullscreenMode newMode = m_mode | mode;
-    if (m_mode == newMode)
+    if ((m_currentMode.mode() & mode) == mode)
         return;
 
-    m_mode = newMode;
+    m_currentMode.setMode(mode);
     if (m_videoFullscreenModel)
-        m_videoFullscreenModel->fullscreenModeChanged(m_mode);
+        m_videoFullscreenModel->fullscreenModeChanged(m_currentMode.mode());
 }
 
 void VideoFullscreenInterfaceAVKit::clearMode(HTMLMediaElementEnums::VideoFullscreenMode mode)
 {
-    HTMLMediaElementEnums::VideoFullscreenMode newMode = m_mode & ~mode;
-    if (m_mode == newMode)
+    if ((~m_currentMode.mode() & mode) == mode)
         return;
 
-    m_mode = newMode;
+    m_currentMode.clearMode(mode);
     if (m_videoFullscreenModel)
-        m_videoFullscreenModel->fullscreenModeChanged(m_mode);
+        m_videoFullscreenModel->fullscreenModeChanged(m_currentMode.mode());
 }
 
 #endif // HAVE(AVKIT)
index ffee763..b359bb0 100644 (file)
@@ -122,6 +122,9 @@ private:
     VideoFullscreenControllerContext() { }
 
     // VideoFullscreenChangeObserver
+    void requestUpdateInlineRect() override;
+    void requestVideoContentLayer() override;
+    void returnVideoContentLayer() override;
     void didSetupFullscreen() override;
     void didEnterFullscreen() override { }
     void didExitFullscreen() override;
@@ -207,32 +210,90 @@ private:
 
 #pragma mark VideoFullscreenChangeObserver
 
+void VideoFullscreenControllerContext::requestUpdateInlineRect()
+{
+#if PLATFORM(IOS) && ENABLE(FULLSCREEN_API)
+    ASSERT(isUIThread());
+    WebThreadRun([protectedThis = makeRefPtr(this), this] () mutable {
+        IntRect clientRect = elementRectInWindow(m_videoElement.get());
+        dispatch_async(dispatch_get_main_queue(), [protectedThis = WTFMove(protectedThis), this, clientRect] {
+            m_interface->setInlineRect(clientRect, clientRect != IntRect(0, 0, 0, 0));
+        });
+    });
+#else
+    ASSERT_NOT_REACHED();
+#endif
+}
+
+void VideoFullscreenControllerContext::requestVideoContentLayer()
+{
+#if PLATFORM(IOS) && ENABLE(FULLSCREEN_API)
+    ASSERT(isUIThread());
+    WebThreadRun([protectedThis = makeRefPtr(this), this, videoFullscreenLayer = retainPtr([m_videoFullscreenView layer])] () mutable {
+        [videoFullscreenLayer setBackgroundColor:cachedCGColor(WebCore::Color::transparent)];
+        m_fullscreenModel->setVideoFullscreenLayer(videoFullscreenLayer.get(), [protectedThis = WTFMove(protectedThis), this] () mutable {
+            dispatch_async(dispatch_get_main_queue(), [protectedThis = WTFMove(protectedThis), this] {
+                m_interface->setHasVideoContentLayer(true);
+            });
+        });
+    });
+#else
+    ASSERT_NOT_REACHED();
+#endif
+}
+
+void VideoFullscreenControllerContext::returnVideoContentLayer()
+{
+#if PLATFORM(IOS) && ENABLE(FULLSCREEN_API)
+    ASSERT(isUIThread());
+    WebThreadRun([protectedThis = makeRefPtr(this), this, videoFullscreenLayer = retainPtr([m_videoFullscreenView layer])] () mutable {
+        [videoFullscreenLayer setBackgroundColor:cachedCGColor(WebCore::Color::transparent)];
+        m_fullscreenModel->setVideoFullscreenLayer(nil, [protectedThis = WTFMove(protectedThis), this] () mutable {
+            dispatch_async(dispatch_get_main_queue(), [protectedThis = WTFMove(protectedThis), this] {
+                m_interface->setHasVideoContentLayer(false);
+            });
+        });
+    });
+#else
+    ASSERT_NOT_REACHED();
+#endif
+}
+
 void VideoFullscreenControllerContext::didSetupFullscreen()
 {
     ASSERT(isUIThread());
-    RetainPtr<CALayer> videoFullscreenLayer = [m_videoFullscreenView layer];
-    RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-    WebThreadRun([protectedThis, this, videoFullscreenLayer] {
+#if PLATFORM(IOS) && ENABLE(FULLSCREEN_API)
+    dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), this] {
+        m_interface->enterFullscreen();
+    });
+#else
+    WebThreadRun([protectedThis = makeRefPtr(this), this, videoFullscreenLayer = retainPtr([m_videoFullscreenView layer])] () mutable {
         [videoFullscreenLayer setBackgroundColor:cachedCGColor(WebCore::Color::transparent)];
-        m_fullscreenModel->setVideoFullscreenLayer(videoFullscreenLayer.get(), [protectedThis, this] {
-            dispatch_async(dispatch_get_main_queue(), [protectedThis, this] {
+        m_fullscreenModel->setVideoFullscreenLayer(videoFullscreenLayer.get(), [protectedThis = WTFMove(protectedThis), this] () mutable {
+            dispatch_async(dispatch_get_main_queue(), [protectedThis = WTFMove(protectedThis), this] {
                 m_interface->enterFullscreen();
             });
         });
     });
+#endif
 }
 
 void VideoFullscreenControllerContext::didExitFullscreen()
 {
     ASSERT(isUIThread());
-    RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-    WebThreadRun([protectedThis, this] {
-        m_fullscreenModel->setVideoFullscreenLayer(nil, [protectedThis, this] {
-            dispatch_async(dispatch_get_main_queue(), [protectedThis, this] {
+#if PLATFORM(IOS) && ENABLE(FULLSCREEN_API)
+    dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), this] {
+        m_interface->cleanupFullscreen();
+    });
+#else
+    WebThreadRun([protectedThis = makeRefPtr(this), this] () mutable {
+        m_fullscreenModel->setVideoFullscreenLayer(nil, [protectedThis = WTFMove(protectedThis), this] () mutable {
+            dispatch_async(dispatch_get_main_queue(), [protectedThis = WTFMove(protectedThis), this] {
                 m_interface->cleanupFullscreen();
             });
         });
     });
+#endif
 }
 
 void VideoFullscreenControllerContext::didCleanupFullscreen()
@@ -243,8 +304,7 @@ void VideoFullscreenControllerContext::didCleanupFullscreen()
     m_interface = nullptr;
     m_videoFullscreenView = nil;
 
-    RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-    WebThreadRun([protectedThis, this] {
+    WebThreadRun([protectedThis = makeRefPtr(this), this] {
         m_fullscreenModel->setVideoFullscreenLayer(nil);
         m_fullscreenModel->setVideoElement(nullptr);
         m_playbackModel->setMediaElement(nullptr);
@@ -259,10 +319,9 @@ void VideoFullscreenControllerContext::didCleanupFullscreen()
 void VideoFullscreenControllerContext::fullscreenMayReturnToInline()
 {
     ASSERT(isUIThread());
-    RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-    WebThreadRun([protectedThis, this] {
+    WebThreadRun([protectedThis = makeRefPtr(this), this] () mutable {
         IntRect clientRect = elementRectInWindow(m_videoElement.get());
-        dispatch_async(dispatch_get_main_queue(), [protectedThis, this, clientRect] {
+        dispatch_async(dispatch_get_main_queue(), [protectedThis = WTFMove(protectedThis), this, clientRect] {
             m_interface->preparedToReturnToInline(true, clientRect);
         });
     });
@@ -273,8 +332,7 @@ void VideoFullscreenControllerContext::fullscreenMayReturnToInline()
 void VideoFullscreenControllerContext::durationChanged(double duration)
 {
     if (WebThreadIsCurrent()) {
-        RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-        dispatch_async(dispatch_get_main_queue(), [protectedThis, duration] {
+        dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), duration] {
             protectedThis->durationChanged(duration);
         });
         return;
@@ -287,8 +345,7 @@ void VideoFullscreenControllerContext::durationChanged(double duration)
 void VideoFullscreenControllerContext::currentTimeChanged(double currentTime, double anchorTime)
 {
     if (WebThreadIsCurrent()) {
-        RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-        dispatch_async(dispatch_get_main_queue(), [protectedThis, currentTime, anchorTime] {
+        dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), currentTime, anchorTime] {
             protectedThis->currentTimeChanged(currentTime, anchorTime);
         });
         return;
@@ -301,8 +358,7 @@ void VideoFullscreenControllerContext::currentTimeChanged(double currentTime, do
 void VideoFullscreenControllerContext::bufferedTimeChanged(double bufferedTime)
 {
     if (WebThreadIsCurrent()) {
-        RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-        dispatch_async(dispatch_get_main_queue(), [protectedThis, bufferedTime] {
+        dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), bufferedTime] {
             protectedThis->bufferedTimeChanged(bufferedTime);
         });
         return;
@@ -315,8 +371,7 @@ void VideoFullscreenControllerContext::bufferedTimeChanged(double bufferedTime)
 void VideoFullscreenControllerContext::rateChanged(bool isPlaying, float playbackRate)
 {
     if (WebThreadIsCurrent()) {
-        RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-        dispatch_async(dispatch_get_main_queue(), [protectedThis, isPlaying, playbackRate] {
+        dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), isPlaying, playbackRate] {
             protectedThis->rateChanged(isPlaying, playbackRate);
         });
         return;
@@ -329,8 +384,7 @@ void VideoFullscreenControllerContext::rateChanged(bool isPlaying, float playbac
 void VideoFullscreenControllerContext::hasVideoChanged(bool hasVideo)
 {
     if (WebThreadIsCurrent()) {
-        RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-        dispatch_async(dispatch_get_main_queue(), [protectedThis, hasVideo] {
+        dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), hasVideo] {
             protectedThis->hasVideoChanged(hasVideo);
         });
         return;
@@ -343,8 +397,7 @@ void VideoFullscreenControllerContext::hasVideoChanged(bool hasVideo)
 void VideoFullscreenControllerContext::videoDimensionsChanged(const FloatSize& videoDimensions)
 {
     if (WebThreadIsCurrent()) {
-        RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-        dispatch_async(dispatch_get_main_queue(), [protectedThis, videoDimensions = videoDimensions] {
+        dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), videoDimensions = videoDimensions] {
             protectedThis->videoDimensionsChanged(videoDimensions);
         });
         return;
@@ -357,8 +410,7 @@ void VideoFullscreenControllerContext::videoDimensionsChanged(const FloatSize& v
 void VideoFullscreenControllerContext::seekableRangesChanged(const TimeRanges& timeRanges, double lastModifiedTime, double liveUpdateInterval)
 {
     if (WebThreadIsCurrent()) {
-        RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-        dispatch_async(dispatch_get_main_queue(), [protectedThis, platformTimeRanges = timeRanges.ranges(), lastModifiedTime, liveUpdateInterval] {
+        dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), platformTimeRanges = timeRanges.ranges(), lastModifiedTime, liveUpdateInterval] {
             protectedThis->seekableRangesChanged(TimeRanges::create(platformTimeRanges), lastModifiedTime, liveUpdateInterval);
         });
         return;
@@ -371,8 +423,7 @@ void VideoFullscreenControllerContext::seekableRangesChanged(const TimeRanges& t
 void VideoFullscreenControllerContext::canPlayFastReverseChanged(bool canPlayFastReverse)
 {
     if (WebThreadIsCurrent()) {
-        RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-        dispatch_async(dispatch_get_main_queue(), [protectedThis, canPlayFastReverse] {
+        dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), canPlayFastReverse] {
             protectedThis->canPlayFastReverseChanged(canPlayFastReverse);
         });
         return;
@@ -394,8 +445,7 @@ static Vector<MediaSelectionOption> isolatedCopy(const Vector<MediaSelectionOpti
 void VideoFullscreenControllerContext::audioMediaSelectionOptionsChanged(const Vector<MediaSelectionOption>& options, uint64_t selectedIndex)
 {
     if (WebThreadIsCurrent()) {
-        RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-        dispatch_async(dispatch_get_main_queue(), [protectedThis, options = isolatedCopy(options), selectedIndex] {
+        dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), options = isolatedCopy(options), selectedIndex] {
             protectedThis->audioMediaSelectionOptionsChanged(options, selectedIndex);
         });
         return;
@@ -408,8 +458,7 @@ void VideoFullscreenControllerContext::audioMediaSelectionOptionsChanged(const V
 void VideoFullscreenControllerContext::legibleMediaSelectionOptionsChanged(const Vector<MediaSelectionOption>& options, uint64_t selectedIndex)
 {
     if (WebThreadIsCurrent()) {
-        RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-        dispatch_async(dispatch_get_main_queue(), [protectedThis, options = isolatedCopy(options), selectedIndex] {
+        dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), options = isolatedCopy(options), selectedIndex] {
             protectedThis->legibleMediaSelectionOptionsChanged(options, selectedIndex);
         });
         return;
@@ -436,8 +485,7 @@ void VideoFullscreenControllerContext::externalPlaybackChanged(bool enabled, Pla
 void VideoFullscreenControllerContext::wirelessVideoPlaybackDisabledChanged(bool disabled)
 {
     if (WebThreadIsCurrent()) {
-        RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-        dispatch_async(dispatch_get_main_queue(), [protectedThis, disabled] {
+        dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), disabled] {
             protectedThis->wirelessVideoPlaybackDisabledChanged(disabled);
         });
         return;
@@ -450,8 +498,7 @@ void VideoFullscreenControllerContext::wirelessVideoPlaybackDisabledChanged(bool
 void VideoFullscreenControllerContext::mutedChanged(bool muted)
 {
     if (WebThreadIsCurrent()) {
-        RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-        dispatch_async(dispatch_get_main_queue(), [protectedThis, muted] {
+        dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), muted] {
             protectedThis->mutedChanged(muted);
         });
         return;
@@ -478,8 +525,7 @@ void VideoFullscreenControllerContext::removeClient(VideoFullscreenModelClient&
 void VideoFullscreenControllerContext::requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenMode mode, bool finishedWithMedia)
 {
     ASSERT(isUIThread());
-    RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-    WebThreadRun([protectedThis, this, mode, finishedWithMedia] {
+    WebThreadRun([protectedThis = makeRefPtr(this), this, mode, finishedWithMedia] {
         if (m_fullscreenModel)
             m_fullscreenModel->requestFullscreenMode(mode, finishedWithMedia);
     });
@@ -488,13 +534,11 @@ void VideoFullscreenControllerContext::requestFullscreenMode(HTMLMediaElementEnu
 void VideoFullscreenControllerContext::setVideoLayerFrame(FloatRect frame)
 {
     ASSERT(isUIThread());
-    RefPtr<VideoFullscreenControllerContext> protectedThis(this);
     RetainPtr<CALayer> videoFullscreenLayer = [m_videoFullscreenView layer];
-    
     [videoFullscreenLayer setSublayerTransform:[videoFullscreenLayer transform]];
 
-    dispatch_async(dispatch_get_main_queue(), ^ {
-        WebThreadRun([protectedThis, this, frame, videoFullscreenLayer] {
+    dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), this, frame, videoFullscreenLayer = WTFMove(videoFullscreenLayer)] () mutable {
+        WebThreadRun([protectedThis = WTFMove(protectedThis), this, frame, videoFullscreenLayer = WTFMove(videoFullscreenLayer)] {
             [CATransaction begin];
             [CATransaction setDisableActions:YES];
             [CATransaction setAnimationDuration:0];
@@ -511,8 +555,7 @@ void VideoFullscreenControllerContext::setVideoLayerFrame(FloatRect frame)
 void VideoFullscreenControllerContext::setVideoLayerGravity(VideoFullscreenModel::VideoGravity videoGravity)
 {
     ASSERT(isUIThread());
-    RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-    WebThreadRun([protectedThis, this, videoGravity] {
+    WebThreadRun([protectedThis = makeRefPtr(this), this, videoGravity] {
         if (m_fullscreenModel)
             m_fullscreenModel->setVideoLayerGravity(videoGravity);
     });
@@ -521,8 +564,7 @@ void VideoFullscreenControllerContext::setVideoLayerGravity(VideoFullscreenModel
 void VideoFullscreenControllerContext::fullscreenModeChanged(HTMLMediaElementEnums::VideoFullscreenMode mode)
 {
     ASSERT(isUIThread());
-    RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-    WebThreadRun([protectedThis, this, mode] {
+    WebThreadRun([protectedThis = makeRefPtr(this), this, mode] {
         if (m_fullscreenModel)
             m_fullscreenModel->fullscreenModeChanged(mode);
     });
@@ -569,8 +611,7 @@ void VideoFullscreenControllerContext::removeClient(PlaybackSessionModelClient&
 void VideoFullscreenControllerContext::play()
 {
     ASSERT(isUIThread());
-    RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-    WebThreadRun([protectedThis, this] {
+    WebThreadRun([protectedThis = makeRefPtr(this), this] {
         if (m_playbackModel)
             m_playbackModel->play();
     });
@@ -579,8 +620,7 @@ void VideoFullscreenControllerContext::play()
 void VideoFullscreenControllerContext::pause()
 {
     ASSERT(isUIThread());
-    RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-    WebThreadRun([protectedThis, this] {
+    WebThreadRun([protectedThis = makeRefPtr(this), this] {
         if (m_playbackModel)
             m_playbackModel->pause();
     });
@@ -589,8 +629,7 @@ void VideoFullscreenControllerContext::pause()
 void VideoFullscreenControllerContext::togglePlayState()
 {
     ASSERT(isUIThread());
-    RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-    WebThreadRun([protectedThis, this] {
+    WebThreadRun([protectedThis = makeRefPtr(this), this] {
         if (m_playbackModel)
             m_playbackModel->togglePlayState();
     });
@@ -599,8 +638,7 @@ void VideoFullscreenControllerContext::togglePlayState()
 void VideoFullscreenControllerContext::toggleMuted()
 {
     ASSERT(isUIThread());
-    RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-    WebThreadRun([protectedThis, this] {
+    WebThreadRun([protectedThis = makeRefPtr(this), this] {
         if (m_playbackModel)
             m_playbackModel->toggleMuted();
     });
@@ -618,8 +656,7 @@ void VideoFullscreenControllerContext::setMuted(bool muted)
 void VideoFullscreenControllerContext::beginScrubbing()
 {
     ASSERT(isUIThread());
-    RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-    WebThreadRun([protectedThis, this] {
+    WebThreadRun([protectedThis = makeRefPtr(this), this] {
         if (m_playbackModel)
             m_playbackModel->beginScrubbing();
     });
@@ -628,8 +665,7 @@ void VideoFullscreenControllerContext::beginScrubbing()
 void VideoFullscreenControllerContext::endScrubbing()
 {
     ASSERT(isUIThread());
-    RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-    WebThreadRun([protectedThis, this] {
+    WebThreadRun([protectedThis = makeRefPtr(this), this] {
         if (m_playbackModel)
             m_playbackModel->endScrubbing();
     });
@@ -638,8 +674,7 @@ void VideoFullscreenControllerContext::endScrubbing()
 void VideoFullscreenControllerContext::seekToTime(double time, double toleranceBefore, double toleranceAfter)
 {
     ASSERT(isUIThread());
-    RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-    WebThreadRun([protectedThis, this, time, toleranceBefore, toleranceAfter] {
+    WebThreadRun([protectedThis = makeRefPtr(this), this, time, toleranceBefore, toleranceAfter] {
         if (m_playbackModel)
             m_playbackModel->seekToTime(time, toleranceBefore, toleranceAfter);
     });
@@ -648,8 +683,7 @@ void VideoFullscreenControllerContext::seekToTime(double time, double toleranceB
 void VideoFullscreenControllerContext::fastSeek(double time)
 {
     ASSERT(isUIThread());
-    RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-    WebThreadRun([protectedThis, this, time] {
+    WebThreadRun([protectedThis = makeRefPtr(this), this, time] {
         if (m_playbackModel)
             m_playbackModel->fastSeek(time);
     });
@@ -658,8 +692,7 @@ void VideoFullscreenControllerContext::fastSeek(double time)
 void VideoFullscreenControllerContext::beginScanningForward()
 {
     ASSERT(isUIThread());
-    RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-    WebThreadRun([protectedThis, this] {
+    WebThreadRun([protectedThis = makeRefPtr(this), this] {
         if (m_playbackModel)
             m_playbackModel->beginScanningForward();
     });
@@ -668,8 +701,7 @@ void VideoFullscreenControllerContext::beginScanningForward()
 void VideoFullscreenControllerContext::beginScanningBackward()
 {
     ASSERT(isUIThread());
-    RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-    WebThreadRun([protectedThis, this] {
+    WebThreadRun([protectedThis = makeRefPtr(this), this] {
         if (m_playbackModel)
             m_playbackModel->beginScanningBackward();
     });
@@ -678,8 +710,7 @@ void VideoFullscreenControllerContext::beginScanningBackward()
 void VideoFullscreenControllerContext::endScanning()
 {
     ASSERT(isUIThread());
-    RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-    WebThreadRun([protectedThis, this] {
+    WebThreadRun([protectedThis = makeRefPtr(this), this] {
         if (m_playbackModel)
             m_playbackModel->endScanning();
     });
@@ -688,8 +719,7 @@ void VideoFullscreenControllerContext::endScanning()
 void VideoFullscreenControllerContext::selectAudioMediaOption(uint64_t index)
 {
     ASSERT(isUIThread());
-    RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-    WebThreadRun([protectedThis, this, index] {
+    WebThreadRun([protectedThis = makeRefPtr(this), this, index] {
         if (m_playbackModel)
             m_playbackModel->selectAudioMediaOption(index);
     });
@@ -698,8 +728,7 @@ void VideoFullscreenControllerContext::selectAudioMediaOption(uint64_t index)
 void VideoFullscreenControllerContext::selectLegibleMediaOption(uint64_t index)
 {
     ASSERT(isUIThread());
-    RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-    WebThreadRun([protectedThis, this, index] {
+    WebThreadRun([protectedThis = makeRefPtr(this), this, index] {
         if (m_playbackModel)
             m_playbackModel->selectLegibleMediaOption(index);
     });
@@ -832,8 +861,7 @@ void VideoFullscreenControllerContext::setUpFullscreen(HTMLVideoElement& videoEl
     FloatRect videoLayerFrame = FloatRect(FloatPoint(), videoElementClientRect.size());
     m_fullscreenModel->setVideoLayerFrame(videoLayerFrame);
 
-    RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-    dispatch_async(dispatch_get_main_queue(), [protectedThis, this, videoElementClientRect, viewRef, mode, allowsPictureInPicture] {
+    dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), this, videoElementClientRect, viewRef, mode, allowsPictureInPicture] {
         ASSERT(isUIThread());
 
         Ref<PlaybackSessionInterfaceAVKit> sessionInterface = PlaybackSessionInterfaceAVKit::create(*this);
@@ -844,7 +872,7 @@ void VideoFullscreenControllerContext::setUpFullscreen(HTMLVideoElement& videoEl
 
         m_videoFullscreenView = adoptNS([allocUIViewInstance() init]);
         
-        m_interface->setupFullscreen(*m_videoFullscreenView.get(), videoElementClientRect, viewRef.get(), mode, allowsPictureInPicture);
+        m_interface->setupFullscreen(*m_videoFullscreenView.get(), videoElementClientRect, viewRef.get(), mode, allowsPictureInPicture, false);
     });
 }
 
@@ -852,8 +880,7 @@ void VideoFullscreenControllerContext::exitFullscreen()
 {
     ASSERT(WebThreadIsCurrent() || isMainThread());
     IntRect clientRect = elementRectInWindow(m_videoElement.get());
-    RefPtr<VideoFullscreenControllerContext> protectedThis(this);
-    dispatch_async(dispatch_get_main_queue(), [protectedThis, this, clientRect] {
+    dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), this, clientRect] {
         ASSERT(isUIThread());
         m_interface->exitFullscreen(clientRect);
     });
index a8abfb5..c70d400 100644 (file)
@@ -432,8 +432,7 @@ void VideoFullscreenInterfaceMac::setupFullscreen(NSView& layerHostedView, const
 
     [videoFullscreenInterfaceObjC() setUpPIPForVideoView:&layerHostedView withFrame:(NSRect)initialRect inWindow:parentWindow];
 
-    RefPtr<VideoFullscreenInterfaceMac> protectedThis(this);
-    dispatch_async(dispatch_get_main_queue(), [protectedThis, this] {
+    dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), this] {
         if (m_fullscreenChangeObserver)
             m_fullscreenChangeObserver->didSetupFullscreen();
     });
index 0f22126..7d65554 100644 (file)
@@ -1,3 +1,55 @@
+2017-12-21  Jeremy Jones  <jeremyj@apple.com>
+
+        Enable picture-in-picture from inline element on suspend.
+        https://bugs.webkit.org/show_bug.cgi?id=180942
+        rdar://problem/34745234
+
+        Reviewed by Jer Noble.
+
+        Add support for video fullscreen standby and imporved fullscreen state transition process.
+
+        Video fullscreen standby allows a video element to have its fullscreen interface state created and
+        continuously updated so that it can quickly change presentation state on application state.
+
+        In order to accomplish this, this change allows the fullscreen presentation to decide when it needs
+        an updated inline rect, or the presence of the video layer. 
+
+        This is conditionalized until mac supports this model.
+
+        * UIProcess/Cocoa/VideoFullscreenManagerProxy.h:
+        * UIProcess/Cocoa/VideoFullscreenManagerProxy.messages.in:
+        * UIProcess/Cocoa/VideoFullscreenManagerProxy.mm:
+        (WebKit::VideoFullscreenModelContext::requestUpdateInlineRect):
+        (WebKit::VideoFullscreenModelContext::requestVideoContentLayer):
+        (WebKit::VideoFullscreenModelContext::returnVideoContentLayer):
+        (WebKit::VideoFullscreenManagerProxy::setupFullscreenWithID):
+        (WebKit::VideoFullscreenManagerProxy::setInlineRect):
+        (WebKit::VideoFullscreenManagerProxy::setHasVideoContentLayer):
+        (WebKit::VideoFullscreenManagerProxy::requestUpdateInlineRect):
+        (WebKit::VideoFullscreenManagerProxy::requestVideoContentLayer):
+        (WebKit::VideoFullscreenManagerProxy::returnVideoContentLayer):
+        * WebProcess/FullScreen/WebFullScreenManager.cpp:
+        (WebKit::WebFullScreenManager::didEnterFullScreen):
+        (WebKit::WebFullScreenManager::willExitFullScreen):
+        * WebProcess/FullScreen/WebFullScreenManager.h:
+        * WebProcess/WebCoreSupport/WebChromeClient.cpp:
+        (WebKit::WebChromeClient::supportsVideoFullscreenStandby):
+        (WebKit::WebChromeClient::enterVideoFullscreenForVideoElement):
+        * WebProcess/WebCoreSupport/WebChromeClient.h:
+        * WebProcess/cocoa/VideoFullscreenManager.h:
+        (WebKit::VideoFullscreenInterfaceContext::fullscreenStandby const):
+        (WebKit::VideoFullscreenInterfaceContext::setFullscreenStandby):
+        * WebProcess/cocoa/VideoFullscreenManager.messages.in:
+        * WebProcess/cocoa/VideoFullscreenManager.mm:
+        (WebKit::VideoFullscreenManager::supportsVideoFullscreenStandby const):
+        (WebKit::VideoFullscreenManager::enterVideoFullscreenForVideoElement):
+        (WebKit::VideoFullscreenManager::requestUpdateInlineRect):
+        (WebKit::VideoFullscreenManager::requestVideoContentLayer):
+        (WebKit::VideoFullscreenManager::returnVideoContentLayer):
+        (WebKit::VideoFullscreenManager::didSetupFullscreen):
+        (WebKit::VideoFullscreenManager::didExitFullscreen):
+        (WebKit::VideoFullscreenManager::didCleanupFullscreen):
+
 2017-12-20  Eric Carlson  <eric.carlson@apple.com>
 
         [MediaStream] Add screen capture IDL and stub functions
index c177256..b20aba3 100644 (file)
@@ -87,6 +87,9 @@ private:
     WebCore::FloatSize videoDimensions() const override { return m_videoDimensions; }
 
     // VideoFullscreenChangeObserver
+    void requestUpdateInlineRect() override;
+    void requestVideoContentLayer() override;
+    void returnVideoContentLayer() override;
     void didSetupFullscreen() override;
     void didEnterFullscreen() override;
     void didExitFullscreen() override;
@@ -134,7 +137,9 @@ private:
     void removeClientForContext(uint64_t contextId);
 
     // Messages from VideoFullscreenManager
-    void setupFullscreenWithID(uint64_t contextId, uint32_t videoLayerID, const WebCore::IntRect& initialRect, float hostingScaleFactor, WebCore::HTMLMediaElementEnums::VideoFullscreenMode, bool allowsPictureInPicture);
+    void setupFullscreenWithID(uint64_t contextId, uint32_t videoLayerID, const WebCore::IntRect& initialRect, float hostingScaleFactor, WebCore::HTMLMediaElementEnums::VideoFullscreenMode, bool allowsPictureInPicture, bool standby);
+    void setInlineRect(uint64_t contextId, const WebCore::IntRect& inlineRect, bool visible);
+    void setHasVideoContentLayer(uint64_t contextId, bool value);
     void setHasVideo(uint64_t contextId, bool);
     void setVideoDimensions(uint64_t contextId, const WebCore::FloatSize&);
     void enterFullscreen(uint64_t contextId);
@@ -147,6 +152,9 @@ private:
 
     // Messages to VideoFullscreenManager
     void requestFullscreenMode(uint64_t contextId, WebCore::HTMLMediaElementEnums::VideoFullscreenMode, bool finishedWithMedia = false);
+    void requestUpdateInlineRect(uint64_t contextId);
+    void requestVideoContentLayer(uint64_t contextId);
+    void returnVideoContentLayer(uint64_t contextId);
     void didSetupFullscreen(uint64_t contextId);
     void didExitFullscreen(uint64_t contextId);
     void didEnterFullscreen(uint64_t contextId);
index efc3b50..3a0c77d 100644 (file)
 messages -> VideoFullscreenManagerProxy {
     SetHasVideo(uint64_t contextId, bool hasVideo)
     SetVideoDimensions(uint64_t contextId, WebCore::FloatSize videoDimensions)
-    SetupFullscreenWithID(uint64_t contextId, uint32_t videoLayerID, WebCore::IntRect initialRect, float hostingScaleFactor, WebCore::HTMLMediaElementEnums::VideoFullscreenMode videoFullscreenMode, bool allowsPictureInPicture)
+    SetupFullscreenWithID(uint64_t contextId, uint32_t videoLayerID, WebCore::IntRect initialRect, float hostingScaleFactor, WebCore::HTMLMediaElementEnums::VideoFullscreenMode videoFullscreenMode, bool allowsPictureInPicture, bool standby)
     EnterFullscreen(uint64_t contextId)
     ExitFullscreen(uint64_t contextId, WebCore::IntRect finalRect)
+    SetInlineRect(uint64_t contextId, WebCore::IntRect inlineRect, bool visible)
+    SetHasVideoContentLayer(uint64_t contextId, bool value)
     CleanupFullscreen(uint64_t contextId)
     PreparedToReturnToInline(uint64_t contextId, bool visible, WebCore::IntRect inlineRect)
 #if PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE)
index 4926515..810cd40 100644 (file)
@@ -167,6 +167,24 @@ bool VideoFullscreenModelContext::isVisible() const
     return m_manager ? m_manager->isVisible() : false;
 }
 
+void VideoFullscreenModelContext::requestUpdateInlineRect()
+{
+    if (m_manager)
+        m_manager->requestUpdateInlineRect(m_contextId);
+}
+
+void VideoFullscreenModelContext::requestVideoContentLayer()
+{
+    if (m_manager)
+        m_manager->requestVideoContentLayer(m_contextId);
+}
+
+void VideoFullscreenModelContext::returnVideoContentLayer()
+{
+    if (m_manager)
+        m_manager->returnVideoContentLayer(m_contextId);
+}
+
 void VideoFullscreenModelContext::didSetupFullscreen()
 {
     if (m_manager)
@@ -338,7 +356,7 @@ void VideoFullscreenManagerProxy::removeClientForContext(uint64_t contextId)
 
 #pragma mark Messages from VideoFullscreenManager
 
-void VideoFullscreenManagerProxy::setupFullscreenWithID(uint64_t contextId, uint32_t videoLayerID, const WebCore::IntRect& initialRect, float hostingDeviceScaleFactor, HTMLMediaElementEnums::VideoFullscreenMode videoFullscreenMode, bool allowsPictureInPicture)
+void VideoFullscreenManagerProxy::setupFullscreenWithID(uint64_t contextId, uint32_t videoLayerID, const WebCore::IntRect& initialRect, float hostingDeviceScaleFactor, HTMLMediaElementEnums::VideoFullscreenMode videoFullscreenMode, bool allowsPictureInPicture, bool standby)
 {
     ASSERT(videoLayerID);
     RefPtr<VideoFullscreenModelContext> model;
@@ -364,7 +382,7 @@ void VideoFullscreenManagerProxy::setupFullscreenWithID(uint64_t contextId, uint
 
 #if PLATFORM(IOS)
     UIView *parentView = downcast<RemoteLayerTreeDrawingAreaProxy>(*m_page->drawingArea()).remoteLayerTreeHost().rootLayer();
-    interface->setupFullscreen(*model->layerHostView(), initialRect, parentView, videoFullscreenMode, allowsPictureInPicture);
+    interface->setupFullscreen(*model->layerHostView(), initialRect, parentView, videoFullscreenMode, allowsPictureInPicture, standby);
 #else
     IntRect initialWindowRect;
     m_page->rootViewToWindow(initialRect, initialWindowRect);
@@ -418,6 +436,24 @@ void VideoFullscreenManagerProxy::exitFullscreenWithoutAnimationToMode(uint64_t
 }
 #endif
 
+void VideoFullscreenManagerProxy::setInlineRect(uint64_t contextId, const WebCore::IntRect& inlineRect, bool visible)
+{
+#if PLATFORM(IOS) && ENABLE(FULLSCREEN_API)
+    ensureInterface(contextId).setInlineRect(inlineRect, visible);
+#else
+    ASSERT_NOT_REACHED();
+#endif
+}
+
+void VideoFullscreenManagerProxy::setHasVideoContentLayer(uint64_t contextId, bool value)
+{
+#if PLATFORM(IOS) && ENABLE(FULLSCREEN_API)
+    ensureInterface(contextId).setHasVideoContentLayer(value);
+#else
+    ASSERT_NOT_REACHED();
+#endif
+}
+
 void VideoFullscreenManagerProxy::cleanupFullscreen(uint64_t contextId)
 {
     ensureInterface(contextId).cleanupFullscreen();
@@ -443,6 +479,21 @@ void VideoFullscreenManagerProxy::requestFullscreenMode(uint64_t contextId, WebC
     m_page->send(Messages::VideoFullscreenManager::RequestFullscreenMode(contextId, mode, finishedWithMedia), m_page->pageID());
 }
 
+void VideoFullscreenManagerProxy::requestUpdateInlineRect(uint64_t contextId)
+{
+    m_page->send(Messages::VideoFullscreenManager::RequestUpdateInlineRect(contextId), m_page->pageID());
+}
+
+void VideoFullscreenManagerProxy::requestVideoContentLayer(uint64_t contextId)
+{
+    m_page->send(Messages::VideoFullscreenManager::RequestVideoContentLayer(contextId), m_page->pageID());
+}
+
+void VideoFullscreenManagerProxy::returnVideoContentLayer(uint64_t contextId)
+{
+    m_page->send(Messages::VideoFullscreenManager::ReturnVideoContentLayer(contextId), m_page->pageID());
+}
+
 void VideoFullscreenManagerProxy::didSetupFullscreen(uint64_t contextId)
 {
     m_page->send(Messages::VideoFullscreenManager::DidSetupFullscreen(contextId), m_page->pageID());
index ff6e402..9213788 100644 (file)
@@ -129,6 +129,7 @@ struct WKWebViewState {
 - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
 {
     [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
+    [self contentView].frame = self.view.bounds;
     [(WKWebView *)[self contentView] _overrideLayoutParametersWithMinimumLayoutSize:size maximumUnobscuredSizeOverride:size];
 }
 
index 42e2d2b..a5ad6d9 100644 (file)
@@ -35,6 +35,7 @@
 #include <WebCore/Color.h>
 #include <WebCore/Element.h>
 #include <WebCore/FrameView.h>
+#include <WebCore/HTMLVideoElement.h>
 #include <WebCore/MainFrame.h>
 #include <WebCore/Page.h>
 #include <WebCore/RenderLayer.h>
@@ -42,6 +43,7 @@
 #include <WebCore/RenderObject.h>
 #include <WebCore/RenderView.h>
 #include <WebCore/Settings.h>
+#include <WebCore/TypedElementDescendantIterator.h>
 
 using namespace WebCore;
 
@@ -122,11 +124,20 @@ void WebFullScreenManager::didEnterFullScreen()
 {
     ASSERT(m_element);
     m_element->document().webkitDidEnterFullScreenForElement(m_element.get());
+
+    m_pipStandbyElement = descendantsOfType<HTMLVideoElement>(*m_element).first();
+    if (m_pipStandbyElement)
+        m_pipStandbyElement->setVideoFullscreenStandby(true);
 }
 
 void WebFullScreenManager::willExitFullScreen()
 {
     ASSERT(m_element);
+
+    if (m_pipStandbyElement)
+        m_pipStandbyElement->setVideoFullscreenStandby(false);
+    m_pipStandbyElement = nullptr;
+
     m_finalFrame = screenRectOfContents(m_element.get());
     m_element->document().webkitWillExitFullScreenForElement(m_element.get());
 #if !PLATFORM(IOS)
index b6078a8..b5d55fe 100644 (file)
@@ -40,6 +40,7 @@ namespace WebCore {
 class IntRect;
 class Element;
 class GraphicsLayer;
+class HTMLVideoElement;
 }
 
 namespace WebKit {
@@ -82,6 +83,7 @@ protected:
     float m_topContentInset;
     RefPtr<WebPage> m_page;
     RefPtr<WebCore::Element> m_element;
+    RefPtr<WebCore::HTMLVideoElement> m_pipStandbyElement;
 };
 
 } // namespace WebKit
index d219530..cfe583d 100644 (file)
@@ -941,6 +941,11 @@ bool WebChromeClient::supportsVideoFullscreen(HTMLMediaElementEnums::VideoFullsc
     return m_page.videoFullscreenManager().supportsVideoFullscreen(mode);
 }
 
+bool WebChromeClient::supportsVideoFullscreenStandby()
+{
+    return m_page.videoFullscreenManager().supportsVideoFullscreenStandby();
+}
+
 void WebChromeClient::setUpPlaybackControlsManager(HTMLMediaElement& mediaElement)
 {
     m_page.playbackSessionManager().setUpPlaybackControlsManager(mediaElement);
@@ -951,10 +956,14 @@ void WebChromeClient::clearPlaybackControlsManager()
     m_page.playbackSessionManager().clearPlaybackControlsManager();
 }
 
-void WebChromeClient::enterVideoFullscreenForVideoElement(HTMLVideoElement& videoElement, HTMLMediaElementEnums::VideoFullscreenMode mode)
+void WebChromeClient::enterVideoFullscreenForVideoElement(HTMLVideoElement& videoElement, HTMLMediaElementEnums::VideoFullscreenMode mode, bool standby)
 {
+#if ENABLE(FULLSCREEN_API) && PLATFORM(IOS)
+    ASSERT(standby || mode != HTMLMediaElementEnums::VideoFullscreenModeNone);
+#else
     ASSERT(mode != HTMLMediaElementEnums::VideoFullscreenModeNone);
-    m_page.videoFullscreenManager().enterVideoFullscreenForVideoElement(videoElement, mode);
+#endif
+    m_page.videoFullscreenManager().enterVideoFullscreenForVideoElement(videoElement, mode, standby);
 }
 
 void WebChromeClient::exitVideoFullscreenForVideoElement(HTMLVideoElement& videoElement)
index 50c2e7e..2824049 100644 (file)
@@ -247,9 +247,10 @@ private:
 
 #if (PLATFORM(IOS) && HAVE(AVKIT)) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
     bool supportsVideoFullscreen(WebCore::HTMLMediaElementEnums::VideoFullscreenMode) final;
+    bool supportsVideoFullscreenStandby() final;
     void setUpPlaybackControlsManager(WebCore::HTMLMediaElement&) final;
     void clearPlaybackControlsManager() final;
-    void enterVideoFullscreenForVideoElement(WebCore::HTMLVideoElement&, WebCore::HTMLMediaElementEnums::VideoFullscreenMode) final;
+    void enterVideoFullscreenForVideoElement(WebCore::HTMLVideoElement&, WebCore::HTMLMediaElementEnums::VideoFullscreenMode, bool standby) final;
     void exitVideoFullscreenForVideoElement(WebCore::HTMLVideoElement&) final;
 #endif
 
index f8d3c24..c3cb1df 100644 (file)
@@ -80,6 +80,9 @@ public:
     WebCore::HTMLMediaElementEnums::VideoFullscreenMode fullscreenMode() const { return m_fullscreenMode; }
     void setFullscreenMode(WebCore::HTMLMediaElementEnums::VideoFullscreenMode mode) { m_fullscreenMode = mode; }
 
+    bool fullscreenStandby() const { return m_fullscreenStandby; }
+    void setFullscreenStandby(bool value) { m_fullscreenStandby = value; }
+
     bool isFullscreen() const { return m_isFullscreen; }
     void setIsFullscreen(bool flag) { m_isFullscreen = flag; }
 
@@ -96,6 +99,7 @@ private:
     bool m_isAnimating { false };
     bool m_targetIsFullscreen { false };
     WebCore::HTMLMediaElementEnums::VideoFullscreenMode m_fullscreenMode { WebCore::HTMLMediaElementEnums::VideoFullscreenModeNone };
+    bool m_fullscreenStandby { false };
     bool m_isFullscreen { false };
 };
 
@@ -110,7 +114,8 @@ public:
 
     // Interface to ChromeClient
     bool supportsVideoFullscreen(WebCore::HTMLMediaElementEnums::VideoFullscreenMode) const;
-    void enterVideoFullscreenForVideoElement(WebCore::HTMLVideoElement&, WebCore::HTMLMediaElementEnums::VideoFullscreenMode);
+    bool supportsVideoFullscreenStandby() const;
+    void enterVideoFullscreenForVideoElement(WebCore::HTMLVideoElement&, WebCore::HTMLMediaElementEnums::VideoFullscreenMode, bool standby);
     void exitVideoFullscreenForVideoElement(WebCore::HTMLVideoElement&);
     void exitVideoFullscreenToModeWithoutAnimation(WebCore::HTMLVideoElement&, WebCore::HTMLMediaElementEnums::VideoFullscreenMode);
 
@@ -134,6 +139,9 @@ protected:
 
     // Messages from VideoFullscreenManagerProxy
     void requestFullscreenMode(uint64_t contextId, WebCore::HTMLMediaElementEnums::VideoFullscreenMode, bool finishedWithMedia);
+    void requestUpdateInlineRect(uint64_t contextId);
+    void requestVideoContentLayer(uint64_t contextId);
+    void returnVideoContentLayer(uint64_t contextId);
     void didSetupFullscreen(uint64_t contextId);
     void didExitFullscreen(uint64_t contextId);
     void didEnterFullscreen(uint64_t contextId);
index 5c4b568..a74ac48 100644 (file)
@@ -23,6 +23,9 @@
 #if (PLATFORM(IOS) && HAVE(AVKIT)) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
 messages -> VideoFullscreenManager {
     RequestFullscreenMode(uint64_t contextId, WebCore::HTMLMediaElementEnums::VideoFullscreenMode videoFullscreenMode, bool finishedWithMedia)
+    RequestUpdateInlineRect(uint64_t contextId)
+    RequestVideoContentLayer(uint64_t contextId)
+    ReturnVideoContentLayer(uint64_t contextId)
     DidSetupFullscreen(uint64_t contextId)
     DidExitFullscreen(uint64_t contextId)
     DidEnterFullscreen(uint64_t contextId)
index ca10505..cfa0887 100644 (file)
@@ -49,6 +49,7 @@
 #import <WebCore/RenderView.h>
 #import <WebCore/Settings.h>
 #import <WebCore/TimeRanges.h>
+#import <WebCore/WebActionDisablingCALayerDelegate.h>
 #import <mach/mach_port.h>
 
 using namespace WebCore;
@@ -226,10 +227,19 @@ bool VideoFullscreenManager::supportsVideoFullscreen(WebCore::HTMLMediaElementEn
 #endif
 }
 
-void VideoFullscreenManager::enterVideoFullscreenForVideoElement(HTMLVideoElement& videoElement, HTMLMediaElementEnums::VideoFullscreenMode mode)
+bool VideoFullscreenManager::supportsVideoFullscreenStandby() const
+{
+#if PLATFORM(IOS) && ENABLE(FULLSCREEN_API)
+    return true;
+#else
+    return false;
+#endif
+}
+
+void VideoFullscreenManager::enterVideoFullscreenForVideoElement(HTMLVideoElement& videoElement, HTMLMediaElementEnums::VideoFullscreenMode mode, bool standby)
 {
     ASSERT(m_page);
-    ASSERT(mode != HTMLMediaElementEnums::VideoFullscreenModeNone);
+    ASSERT(standby || mode != HTMLMediaElementEnums::VideoFullscreenModeNone);
     LOG(Fullscreen, "VideoFullscreenManager::enterVideoFullscreenForVideoElement(%p)", this);
 
     uint64_t contextId = m_playbackSessionManager->contextIdForMediaElement(videoElement);
@@ -250,8 +260,9 @@ void VideoFullscreenManager::enterVideoFullscreenForVideoElement(HTMLVideoElemen
     HTMLMediaElementEnums::VideoFullscreenMode oldMode = interface->fullscreenMode();
     interface->setTargetIsFullscreen(true);
     interface->setFullscreenMode(mode);
+    interface->setFullscreenStandby(standby);
     model->setVideoElement(&videoElement);
-    if (oldMode == HTMLMediaElementEnums::VideoFullscreenModeNone)
+    if (oldMode == HTMLMediaElementEnums::VideoFullscreenModeNone && mode != HTMLMediaElementEnums::VideoFullscreenModeNone)
         model->setVideoLayerFrame(videoLayerFrame);
 
     if (interface->isAnimating())
@@ -259,8 +270,24 @@ void VideoFullscreenManager::enterVideoFullscreenForVideoElement(HTMLVideoElemen
     interface->setIsAnimating(true);
 
     bool allowsPictureInPicture = videoElement.webkitSupportsPresentationMode(HTMLVideoElement::VideoPresentationMode::PictureInPicture);
-    
-    m_page->send(Messages::VideoFullscreenManagerProxy::SetupFullscreenWithID(contextId, interface->layerHostingContext()->contextID(), videoRect, m_page->deviceScaleFactor(), interface->fullscreenMode(), allowsPictureInPicture), m_page->pageID());
+
+    if (!interface->layerHostingContext()->rootLayer()) {
+        PlatformLayer* videoLayer = [CALayer layer];
+        [videoLayer setDelegate:[WebActionDisablingCALayerDelegate shared]];
+
+        [videoLayer setName:@"Web video fullscreen manager layer"];
+        [videoLayer setPosition:CGPointMake(0, 0)];
+        [videoLayer setBackgroundColor:cachedCGColor(WebCore::Color::transparent)];
+
+        // Set a scale factor here to make convertRect:toLayer:nil take scale factor into account. <rdar://problem/18316542>.
+        // This scale factor is inverted in the hosting process.
+        float hostingScaleFactor = m_page->deviceScaleFactor();
+        [videoLayer setTransform:CATransform3DMakeScale(hostingScaleFactor, hostingScaleFactor, 1)];
+
+        interface->layerHostingContext()->setRootLayer(videoLayer);
+    }
+
+    m_page->send(Messages::VideoFullscreenManagerProxy::SetupFullscreenWithID(contextId, interface->layerHostingContext()->contextID(), videoRect, m_page->deviceScaleFactor(), interface->fullscreenMode(), allowsPictureInPicture, standby), m_page->pageID());
 }
 
 void VideoFullscreenManager::exitVideoFullscreenForVideoElement(WebCore::HTMLVideoElement& videoElement)
@@ -327,43 +354,74 @@ void VideoFullscreenManager::fullscreenModeChanged(uint64_t contextId, WebCore::
     ensureModel(contextId).fullscreenModeChanged(videoFullscreenMode);
 }
 
-void VideoFullscreenManager::didSetupFullscreen(uint64_t contextId)
+void VideoFullscreenManager::requestUpdateInlineRect(uint64_t contextId)
 {
-    LOG(Fullscreen, "VideoFullscreenManager::didSetupFullscreen(%p, %x)", this, contextId);
+    if (!m_page)
+        return;
 
-    ASSERT(m_page);
-    PlatformLayer* videoLayer = [CALayer layer];
-#ifndef NDEBUG
-    [videoLayer setName:@"Web video fullscreen manager layer"];
-#endif
+    auto& model = ensureModel(contextId);
+    IntRect inlineRect = inlineVideoFrame(*model.videoElement());
+    m_page->send(Messages::VideoFullscreenManagerProxy::SetInlineRect(contextId, inlineRect, inlineRect != IntRect(0, 0, 0, 0)), m_page->pageID());
+}
 
-    [CATransaction begin];
-    [CATransaction setDisableActions:YES];
+void VideoFullscreenManager::requestVideoContentLayer(uint64_t contextId)
+{
+    RefPtr<VideoFullscreenModelVideoElement> model;
+    RefPtr<VideoFullscreenInterfaceContext> interface;
+    std::tie(model, interface) = ensureModelAndInterface(contextId);
 
-    [videoLayer setPosition:CGPointMake(0, 0)];
-    [videoLayer setBackgroundColor:cachedCGColor(WebCore::Color::transparent)];
+    CALayer* videoLayer = interface->layerHostingContext()->rootLayer();
 
-    // Set a scale factor here to make convertRect:toLayer:nil take scale factor into account. <rdar://problem/18316542>.
-    // This scale factor is inverted in the hosting process.
-    float hostingScaleFactor = m_page->deviceScaleFactor();
-    [videoLayer setTransform:CATransform3DMakeScale(hostingScaleFactor, hostingScaleFactor, 1)];
+    model->setVideoFullscreenLayer(videoLayer, [protectedThis = makeRefPtr(this), this, contextId] () mutable {
+        dispatch_async(dispatch_get_main_queue(), [protectedThis = WTFMove(protectedThis), this, contextId] {
+            if (protectedThis->m_page)
+                m_page->send(Messages::VideoFullscreenManagerProxy::SetHasVideoContentLayer(contextId, true), protectedThis->m_page->pageID());
+        });
+    });
+}
 
+void VideoFullscreenManager::returnVideoContentLayer(uint64_t contextId)
+{
     RefPtr<VideoFullscreenModelVideoElement> model;
     RefPtr<VideoFullscreenInterfaceContext> interface;
     std::tie(model, interface) = ensureModelAndInterface(contextId);
 
-    interface->layerHostingContext()->setRootLayer(videoLayer);
+    model->waitForPreparedForInlineThen([protectedThis = makeRefPtr(this), this, contextId, model] () mutable { // need this for return video layer
+        dispatch_async(dispatch_get_main_queue(), [protectedThis = WTFMove(protectedThis), this, contextId, model] () mutable {
+            model->setVideoFullscreenLayer(nil, [protectedThis = WTFMove(protectedThis), this, contextId] () mutable {
+                dispatch_async(dispatch_get_main_queue(), [protectedThis = WTFMove(protectedThis), this, contextId] {
+                    if (protectedThis->m_page)
+                        m_page->send(Messages::VideoFullscreenManagerProxy::SetHasVideoContentLayer(contextId, false), protectedThis->m_page->pageID());
+                });
+            });
+        });
+    });
+}
 
-    RefPtr<VideoFullscreenManager> protectedThis(this);
-    
-    model->setVideoFullscreenLayer(videoLayer, [protectedThis, this, contextId] {
-        dispatch_async(dispatch_get_main_queue(), [protectedThis, this, contextId] {
+void VideoFullscreenManager::didSetupFullscreen(uint64_t contextId)
+{
+    LOG(Fullscreen, "VideoFullscreenManager::didSetupFullscreen(%p, %x)", this, contextId);
+
+    ASSERT(m_page);
+    RefPtr<VideoFullscreenModelVideoElement> model;
+    RefPtr<VideoFullscreenInterfaceContext> interface;
+    std::tie(model, interface) = ensureModelAndInterface(contextId);
+
+#if PLATFORM(IOS) && ENABLE(FULLSCREEN_API)
+    dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), this, contextId] {
+        if (protectedThis->m_page)
+            m_page->send(Messages::VideoFullscreenManagerProxy::EnterFullscreen(contextId), protectedThis->m_page->pageID());
+    });
+#else
+    CALayer* videoLayer = interface->layerHostingContext()->rootLayer();
+
+    model->setVideoFullscreenLayer(videoLayer, [protectedThis = makeRefPtr(this), this, contextId] () mutable {
+        dispatch_async(dispatch_get_main_queue(), [protectedThis = WTFMove(protectedThis), this, contextId] {
             if (protectedThis->m_page)
                 m_page->send(Messages::VideoFullscreenManagerProxy::EnterFullscreen(contextId), protectedThis->m_page->pageID());
         });
     });
-    
-    [CATransaction commit];
+#endif
 }
     
 void VideoFullscreenManager::didEnterFullscreen(uint64_t contextId)
@@ -385,8 +443,7 @@ void VideoFullscreenManager::didEnterFullscreen(uint64_t contextId)
         return;
 
     // exit fullscreen now if it was previously requested during an animation.
-    RefPtr<VideoFullscreenManager> protectedThis(this);
-    dispatch_async(dispatch_get_main_queue(), [protectedThis, videoElement] {
+    dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), videoElement] {
         if (protectedThis->m_page)
             protectedThis->exitVideoFullscreenForVideoElement(*videoElement);
     });
@@ -399,12 +456,17 @@ void VideoFullscreenManager::didExitFullscreen(uint64_t contextId)
     RefPtr<VideoFullscreenModelVideoElement> model;
     RefPtr<VideoFullscreenInterfaceContext> interface;
     std::tie(model, interface) = ensureModelAndInterface(contextId);
-    RefPtr<VideoFullscreenManager> protectedThis(this);
-    
-    model->waitForPreparedForInlineThen([protectedThis, contextId, interface, model] {
-        dispatch_async(dispatch_get_main_queue(), [protectedThis, contextId, interface, model] {
-            model->setVideoFullscreenLayer(nil, [protectedThis, contextId, interface] {
-                dispatch_async(dispatch_get_main_queue(), [protectedThis, contextId, interface] {
+
+#if PLATFORM(IOS) && ENABLE(FULLSCREEN_API)
+    dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), contextId, interface] {
+        if (protectedThis->m_page)
+            protectedThis->m_page->send(Messages::VideoFullscreenManagerProxy::CleanupFullscreen(contextId), protectedThis->m_page->pageID());
+    });
+#else
+    model->waitForPreparedForInlineThen([protectedThis = makeRefPtr(this), contextId, interface, model] () mutable {
+        dispatch_async(dispatch_get_main_queue(), [protectedThis = WTFMove(protectedThis), contextId, interface, model] () mutable {
+            model->setVideoFullscreenLayer(nil, [protectedThis = WTFMove(protectedThis), contextId, interface] () mutable {
+                dispatch_async(dispatch_get_main_queue(), [protectedThis = WTFMove(protectedThis), contextId, interface] {
                     if (interface->layerHostingContext()) {
                         interface->layerHostingContext()->setRootLayer(nullptr);
                         interface->setLayerHostingContext(nullptr);
@@ -415,6 +477,7 @@ void VideoFullscreenManager::didExitFullscreen(uint64_t contextId)
             });
         });
     });
+#endif
 }
     
 void VideoFullscreenManager::didCleanupFullscreen(uint64_t contextId)
@@ -425,24 +488,30 @@ void VideoFullscreenManager::didCleanupFullscreen(uint64_t contextId)
     RefPtr<VideoFullscreenInterfaceContext> interface;
     std::tie(model, interface) = ensureModelAndInterface(contextId);
 
+    if (interface->layerHostingContext()) {
+        interface->layerHostingContext()->setRootLayer(nullptr);
+        interface->setLayerHostingContext(nullptr);
+    }
+
     interface->setIsAnimating(false);
     interface->setIsFullscreen(false);
     HTMLMediaElementEnums::VideoFullscreenMode mode = interface->fullscreenMode();
+    bool standby = interface->fullscreenStandby();
     bool targetIsFullscreen = interface->targetIsFullscreen();
 
     model->setVideoFullscreenLayer(nil);
     RefPtr<HTMLVideoElement> videoElement = model->videoElement();
 
     interface->setFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
+    interface->setFullscreenStandby(false);
     removeClientForContext(contextId);
 
     if (!videoElement || !targetIsFullscreen)
         return;
 
-    RefPtr<VideoFullscreenManager> protectedThis(this);
-    dispatch_async(dispatch_get_main_queue(), [protectedThis, videoElement, mode] {
+    dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), videoElement, mode, standby] {
         if (protectedThis->m_page)
-            protectedThis->enterVideoFullscreenForVideoElement(*videoElement, mode);
+            protectedThis->enterVideoFullscreenForVideoElement(*videoElement, mode, standby);
     });
 }
     
@@ -476,13 +545,10 @@ void VideoFullscreenManager::setVideoLayerFrameFenced(uint64_t contextId, WebCor
         bounds = FloatRect(0, 0, videoRect.width(), videoRect.height());
     }
     
-    [CATransaction begin];
-    [CATransaction setAnimationDuration:0];
     if (interface->layerHostingContext())
         interface->layerHostingContext()->setFencePort(fencePort.port());
     model->setVideoLayerFrame(bounds);
     mach_port_deallocate(mach_task_self(), fencePort.port());
-    [CATransaction commit];
 }
 
 } // namespace WebKit
index 42e2441..56c4340 100644 (file)
@@ -1,3 +1,17 @@
+2017-12-21  Jeremy Jones  <jeremyj@apple.com>
+
+        Enable picture-in-picture from inline element on suspend.
+        https://bugs.webkit.org/show_bug.cgi?id=180942
+        rdar://problem/34745234
+
+        Reviewed by Jer Noble.
+
+        Update signature of enterVideoFullscreenForVideoElement().
+
+        * WebCoreSupport/WebChromeClient.h:
+        * WebCoreSupport/WebChromeClient.mm:
+        (WebChromeClient::enterVideoFullscreenForVideoElement):
+
 2017-12-20  Daniel Bates  <dabates@apple.com>
 
         Remove Alternative Presentation Button
index 62af77d..4ae39d1 100644 (file)
@@ -184,7 +184,7 @@ private:
 
 #if ENABLE(VIDEO)
     bool supportsVideoFullscreen(WebCore::HTMLMediaElementEnums::VideoFullscreenMode) final;
-    void enterVideoFullscreenForVideoElement(WebCore::HTMLVideoElement&, WebCore::HTMLMediaElementEnums::VideoFullscreenMode) final;
+    void enterVideoFullscreenForVideoElement(WebCore::HTMLVideoElement&, WebCore::HTMLMediaElementEnums::VideoFullscreenMode, bool standby) final;
     void exitVideoFullscreenForVideoElement(WebCore::HTMLVideoElement&) final;
     void exitVideoFullscreenToModeWithoutAnimation(WebCore::HTMLVideoElement&, WebCore::HTMLMediaElementEnums::VideoFullscreenMode) final;
 #endif
index e29e932..9b524cb 100644 (file)
@@ -964,8 +964,9 @@ bool WebChromeClient::supportsVideoFullscreen(HTMLMediaElementEnums::VideoFullsc
     return true;
 }
 
-void WebChromeClient::enterVideoFullscreenForVideoElement(HTMLVideoElement& videoElement, HTMLMediaElementEnums::VideoFullscreenMode mode)
+void WebChromeClient::enterVideoFullscreenForVideoElement(HTMLVideoElement& videoElement, HTMLMediaElementEnums::VideoFullscreenMode mode, bool standby)
 {
+    ASSERT_UNUSED(standby, !standby);
     ASSERT(mode != HTMLMediaElementEnums::VideoFullscreenModeNone);
     BEGIN_BLOCK_OBJC_EXCEPTIONS;
     [m_webView _enterVideoFullscreenForVideoElement:&videoElement mode:mode];
index c2f4d5a..ca7fe92 100644 (file)
@@ -1,3 +1,17 @@
+2017-12-21  Jeremy Jones  <jeremyj@apple.com>
+
+        Enable picture-in-picture from inline element on suspend.
+        https://bugs.webkit.org/show_bug.cgi?id=180942
+        rdar://problem/34745234
+
+        Reviewed by Jer Noble.
+
+        Update signature of enterVideoFullscreenForVideoElement.
+
+        * WebCoreSupport/WebChromeClient.cpp:
+        (WebChromeClient::enterVideoFullscreenForVideoElement):
+        * WebCoreSupport/WebChromeClient.h:
+
 2017-12-18  Fujii Hironori  <Hironori.Fujii@sony.com>
 
         [Win] SHOULD NEVER BE REACHED in WebFrameLoaderClient::pageID
index 59f8982..37aeca8 100644 (file)
@@ -758,7 +758,7 @@ bool WebChromeClient::supportsVideoFullscreen(HTMLMediaElementEnums::VideoFullsc
     return true;
 }
 
-void WebChromeClient::enterVideoFullscreenForVideoElement(HTMLVideoElement& videoElement, HTMLMediaElementEnums::VideoFullscreenMode)
+void WebChromeClient::enterVideoFullscreenForVideoElement(HTMLVideoElement& videoElement, HTMLMediaElementEnums::VideoFullscreenMode, bool)
 {
     m_webView->enterVideoFullscreenForVideoElement(videoElement);
 }
index 67dcc31..be1cd2c 100644 (file)
@@ -139,7 +139,7 @@ public:
 
 #if ENABLE(VIDEO)
     bool supportsVideoFullscreen(WebCore::HTMLMediaElementEnums::VideoFullscreenMode) final;
-    void enterVideoFullscreenForVideoElement(WebCore::HTMLVideoElement&, WebCore::HTMLMediaElementEnums::VideoFullscreenMode) final;
+    void enterVideoFullscreenForVideoElement(WebCore::HTMLVideoElement&, WebCore::HTMLMediaElementEnums::VideoFullscreenMode, bool) final;
     void exitVideoFullscreenForVideoElement(WebCore::HTMLVideoElement&) final;
 #endif