[iOS] When simultaneously exiting-and-entering fullscreen, WebVideoFullscreenManager...
authorjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 16 Apr 2015 22:42:58 +0000 (22:42 +0000)
committerjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 16 Apr 2015 22:42:58 +0000 (22:42 +0000)
https://bugs.webkit.org/show_bug.cgi?id=143680

Reviewed by Simon Fraser.

Source/WebCore:

Add getters for the video's fullscreen layer, and be more tolerant about the order in which setVideoElement() and
setWebVideoFullscreenInterface are called.

* html/HTMLMediaElement.h:
(WebCore::HTMLMediaElement::videoFullscreenLayer): Added simple getter.
* platform/ios/WebVideoFullscreenInterfaceAVKit.h:
* platform/ios/WebVideoFullscreenModelVideoElement.h:
(WebCore::WebVideoFullscreenModelVideoElement::videoElement): Added simple getter.
(WebCore::WebVideoFullscreenModelVideoElement::setWebVideoFullscreenInterface): Deleted. Moved to .mm file.
* platform/ios/WebVideoFullscreenModelVideoElement.mm:
(WebVideoFullscreenModelVideoElement::WebVideoFullscreenModelVideoElement): Initialize ivars in the .h file.
(WebVideoFullscreenModelVideoElement::setWebVideoFullscreenInterface): Call those methods skipped in setVideoElement()
    if m_videoFullscreenInterface had not yet been set.
(WebVideoFullscreenModelVideoElement::setVideoElement): Null-check m_videoFullscreenInterface.

Source/WebKit2:

The original assumption of WebVideoFullscreenManager and -Proxy was that the two classes would represent a
single video element and its full screen state. With multiple animations in and out of fullscreen combined with
multiple fullscreen modes, this assumption no longer holds true.

Rather than having a WebVideoFullscreenManager which /isa/ WebVideoFullscreenModelVideoElement, the manager now
/hasa/ WebVideoFullscreenModelVideoElement (or has many such models). Ditto for WebVideoFullscreenManager and
WebVideoFullscreenInterfaceAVKit. The WebVideoFullscreenInterfaceAVKit still needs a WebVideoFullscreenModel to
communicate with, so a new wrapper class is used for that purpose, WebVideoFullscreenModelContext. Ditto for
WebVideoFullscreenModelVideoElement and the new class WebVideoFullscreenInterfaceContext. These context classes
are paired and share a contextId, allowing the manager and its proxy to route messages between the UIProcess's
WebVideoFullscreenInterfaceAVKit to-and-from the WebProcess's WebVideoFullscreenModelVideoElement.

Both the WebVideoFullscreenModelContext and the WebVideoFullscreenInterfaceContext take a back-pointer to their
manager or manager proxy, and each method on the context simply calls the matching method on the manager and
passes its contextId as a parameter.

Both the WebVideoFullscreenManager and the WebVideoFullscreenManagerProxy pass that contextId in each of their
cross-process messages.

On the other side, the manager and proxy also have a map between contextIds and their matching
WebVideoFullscreenModelVideoElement (in the case of WebVideoFullscreenManager) or
WebVideoFullscreenInterfaceAVKit (in the case of WebVideoFullscreenManagerProxy).

While this change is large by LoC, it is almost entirely boilerplate.  The new and interesting pieces are these:

* UIProcess/ios/WebVideoFullscreenManagerProxy.mm:
(WebKit::WebVideoFullscreenManagerProxy::WebVideoFullscreenManagerProxy): No longer a WebVideoFullscreenInterfaceAVKit.
(WebKit::WebVideoFullscreenManagerProxy::invalidate): Walk through the models and interfaces, invalidating each.
(WebKit::WebVideoFullscreenManagerProxy::createModelAndInterface): Added. Return a new model and interface tuple.
(WebKit::WebVideoFullscreenManagerProxy::ensureModelAndInterface): Added. Lazily create, and add to the m_contextMap
    a new model and interface object.
(WebKit::WebVideoFullscreenManagerProxy::ensureModel): Return the model half of ensureModelAndInterface().
(WebKit::WebVideoFullscreenManagerProxy::ensureInterface): Return the interface half of ensureModelAndInterface().
(WebKit::WebVideoFullscreenManagerProxy::enterFullscreen): Walk through the outstanding interface objects, and if
    any have a fullscreen mode which matches the about-to-be-fullscreen interface, request that that other interface
    exit fullscreen.
* WebProcess/ios/WebVideoFullscreenManager.mm:
(WebKit::nextContextId): Static, incrementing counter used as a contextId source.
(WebKit::WebVideoFullscreenManager::WebVideoFullscreenManager): No longer a WebVideoFullscreenModelVideoElement.
(WebKit::WebVideoFullscreenManager::~WebVideoFullscreenManager): Walk through the models and interfaces, invalidating each.
(WebKit::WebVideoFullscreenManager::ensureModelAndInterface): Added. Return a new model and interface tuple.
(WebKit::WebVideoFullscreenManager::ensureModelAndInterface):  Added. Lazily create, and add to the m_contextMap
    a new model and interface object.
(WebKit::WebVideoFullscreenManager::ensureModel): Return the model half of ensureModelAndInterface().
(WebKit::WebVideoFullscreenManager::ensureInterface): Return the interface half of ensureModelAndInterface().

New classes and methods which just forward on to their owning objects:

* UIProcess/ios/WebVideoFullscreenManagerProxy.h:
(WebKit::WebVideoFullscreenModelContext::create):
(WebKit::WebVideoFullscreenModelContext::~WebVideoFullscreenModelContext):
(WebKit::WebVideoFullscreenModelContext::invalidate):
(WebKit::WebVideoFullscreenModelContext::layerHost):
(WebKit::WebVideoFullscreenModelContext::setLayerHost):
(WebKit::WebVideoFullscreenModelContext::setInitialVideoLayerFrame):
(WebKit::WebVideoFullscreenModelContext::WebVideoFullscreenModelContext):
* UIProcess/ios/WebVideoFullscreenManagerProxy.mm:
(WebKit::WebVideoFullscreenModelContext::play):
(WebKit::WebVideoFullscreenModelContext::pause):
(WebKit::WebVideoFullscreenModelContext::togglePlayState):
(WebKit::WebVideoFullscreenModelContext::beginScrubbing):
(WebKit::WebVideoFullscreenModelContext::endScrubbing):
(WebKit::WebVideoFullscreenModelContext::seekToTime):
(WebKit::WebVideoFullscreenModelContext::fastSeek):
(WebKit::WebVideoFullscreenModelContext::beginScanningForward):
(WebKit::WebVideoFullscreenModelContext::beginScanningBackward):
(WebKit::WebVideoFullscreenModelContext::endScanning):
(WebKit::WebVideoFullscreenModelContext::requestExitFullscreen):
(WebKit::WebVideoFullscreenModelContext::setVideoLayerFrame):
(WebKit::WebVideoFullscreenModelContext::videoLayerFrame):
(WebKit::WebVideoFullscreenModelContext::setVideoLayerGravity):
(WebKit::WebVideoFullscreenModelContext::videoLayerGravity):
(WebKit::WebVideoFullscreenModelContext::selectAudioMediaOption):
(WebKit::WebVideoFullscreenModelContext::selectLegibleMediaOption):
(WebKit::WebVideoFullscreenModelContext::fullscreenModeChanged):
(WebKit::WebVideoFullscreenModelContext::didSetupFullscreen):
(WebKit::WebVideoFullscreenModelContext::didEnterFullscreen):
(WebKit::WebVideoFullscreenModelContext::didExitFullscreen):
(WebKit::WebVideoFullscreenModelContext::didCleanupFullscreen):
(WebKit::WebVideoFullscreenModelContext::fullscreenMayReturnToInline):
* WebProcess/ios/WebVideoFullscreenManager.h:
(WebKit::WebVideoFullscreenInterfaceContext::create):
(WebKit::WebVideoFullscreenInterfaceContext::invalidate):
(WebKit::WebVideoFullscreenInterfaceContext::layerHostingContext):
(WebKit::WebVideoFullscreenInterfaceContext::isAnimating):
(WebKit::WebVideoFullscreenInterfaceContext::setIsAnimating):
(WebKit::WebVideoFullscreenInterfaceContext::targetIsFullscreen):
(WebKit::WebVideoFullscreenInterfaceContext::setTargetIsFullscreen):
(WebKit::WebVideoFullscreenInterfaceContext::fullscreenMode):
(WebKit::WebVideoFullscreenInterfaceContext::setFullscreenMode):
(WebKit::WebVideoFullscreenInterfaceContext::isFullscreen):
(WebKit::WebVideoFullscreenInterfaceContext::setIsFullscreen):
* WebProcess/ios/WebVideoFullscreenManager.mm:
(WebKit::WebVideoFullscreenInterfaceContext::WebVideoFullscreenInterfaceContext):
(WebKit::WebVideoFullscreenInterfaceContext::~WebVideoFullscreenInterfaceContext):
(WebKit::WebVideoFullscreenInterfaceContext::setLayerHostingContext):
(WebKit::WebVideoFullscreenInterfaceContext::resetMediaState):
(WebKit::WebVideoFullscreenInterfaceContext::setDuration):
(WebKit::WebVideoFullscreenInterfaceContext::setCurrentTime):
(WebKit::WebVideoFullscreenInterfaceContext::setBufferedTime):
(WebKit::WebVideoFullscreenInterfaceContext::setRate):
(WebKit::WebVideoFullscreenInterfaceContext::setVideoDimensions):
(WebKit::WebVideoFullscreenInterfaceContext::setSeekableRanges):
(WebKit::WebVideoFullscreenInterfaceContext::setCanPlayFastReverse):
(WebKit::WebVideoFullscreenInterfaceContext::setAudioMediaSelectionOptions):
(WebKit::WebVideoFullscreenInterfaceContext::setLegibleMediaSelectionOptions):
(WebKit::WebVideoFullscreenInterfaceContext::setExternalPlayback):

Cross-process methods which now take a contextId parameter:

* UIProcess/ios/WebVideoFullscreenManagerProxy.messages.in:
* UIProcess/ios/WebVideoFullscreenManagerProxy.mm:
(WebKit::WebVideoFullscreenManagerProxy::setupFullscreenWithID):
(WebKit::WebVideoFullscreenManagerProxy::resetMediaState):
(WebKit::WebVideoFullscreenManagerProxy::setCurrentTime):
(WebKit::WebVideoFullscreenManagerProxy::setBufferedTime):
(WebKit::WebVideoFullscreenManagerProxy::setVideoDimensions):
(WebKit::WebVideoFullscreenManagerProxy::setSeekableRangesVector):
(WebKit::WebVideoFullscreenManagerProxy::setCanPlayFastReverse):
(WebKit::WebVideoFullscreenManagerProxy::setAudioMediaSelectionOptions):
(WebKit::WebVideoFullscreenManagerProxy::setLegibleMediaSelectionOptions):
(WebKit::WebVideoFullscreenManagerProxy::setExternalPlaybackProperties):
(WebKit::WebVideoFullscreenManagerProxy::setDuration):
(WebKit::WebVideoFullscreenManagerProxy::setRate):
(WebKit::WebVideoFullscreenManagerProxy::exitFullscreen):
(WebKit::WebVideoFullscreenManagerProxy::cleanupFullscreen):
(WebKit::WebVideoFullscreenManagerProxy::preparedToReturnToInline):
(WebKit::WebVideoFullscreenManagerProxy::play):
(WebKit::WebVideoFullscreenManagerProxy::pause):
(WebKit::WebVideoFullscreenManagerProxy::togglePlayState):
(WebKit::WebVideoFullscreenManagerProxy::beginScrubbing):
(WebKit::WebVideoFullscreenManagerProxy::endScrubbing):
(WebKit::WebVideoFullscreenManagerProxy::seekToTime):
(WebKit::WebVideoFullscreenManagerProxy::fastSeek):
(WebKit::WebVideoFullscreenManagerProxy::beginScanningForward):
(WebKit::WebVideoFullscreenManagerProxy::beginScanningBackward):
(WebKit::WebVideoFullscreenManagerProxy::endScanning):
(WebKit::WebVideoFullscreenManagerProxy::requestExitFullscreen):
(WebKit::WebVideoFullscreenManagerProxy::didSetupFullscreen):
(WebKit::WebVideoFullscreenManagerProxy::didExitFullscreen):
(WebKit::WebVideoFullscreenManagerProxy::didEnterFullscreen):
(WebKit::WebVideoFullscreenManagerProxy::didCleanupFullscreen):
(WebKit::WebVideoFullscreenManagerProxy::setVideoLayerFrame):
(WebKit::WebVideoFullscreenManagerProxy::setVideoLayerGravity):
(WebKit::WebVideoFullscreenManagerProxy::selectAudioMediaOption):
(WebKit::WebVideoFullscreenManagerProxy::selectLegibleMediaOption):
(WebKit::WebVideoFullscreenManagerProxy::fullscreenModeChanged):
(WebKit::WebVideoFullscreenManagerProxy::fullscreenMayReturnToInline):
(WebKit::WebVideoFullscreenManagerProxy::videoLayerFrame): Deleted.
(WebKit::WebVideoFullscreenManagerProxy::videoLayerGravity): Deleted.
* WebProcess/ios/WebVideoFullscreenManager.messages.in:
* WebProcess/ios/WebVideoFullscreenManager.mm:
(WebKit::WebVideoFullscreenManager::enterVideoFullscreenForVideoElement):
(WebKit::WebVideoFullscreenManager::exitVideoFullscreenForVideoElement):
(WebKit::WebVideoFullscreenManager::resetMediaState):
(WebKit::WebVideoFullscreenManager::setDuration):
(WebKit::WebVideoFullscreenManager::setCurrentTime):
(WebKit::WebVideoFullscreenManager::setBufferedTime):
(WebKit::WebVideoFullscreenManager::setRate):
(WebKit::WebVideoFullscreenManager::setVideoDimensions):
(WebKit::WebVideoFullscreenManager::setSeekableRanges):
(WebKit::WebVideoFullscreenManager::setCanPlayFastReverse):
(WebKit::WebVideoFullscreenManager::setAudioMediaSelectionOptions):
(WebKit::WebVideoFullscreenManager::setLegibleMediaSelectionOptions):
(WebKit::WebVideoFullscreenManager::setExternalPlayback):
(WebKit::WebVideoFullscreenManager::play):
(WebKit::WebVideoFullscreenManager::pause):
(WebKit::WebVideoFullscreenManager::togglePlayState):
(WebKit::WebVideoFullscreenManager::beginScrubbing):
(WebKit::WebVideoFullscreenManager::endScrubbing):
(WebKit::WebVideoFullscreenManager::seekToTime):
(WebKit::WebVideoFullscreenManager::fastSeek):
(WebKit::WebVideoFullscreenManager::beginScanningForward):
(WebKit::WebVideoFullscreenManager::beginScanningBackward):
(WebKit::WebVideoFullscreenManager::endScanning):
(WebKit::WebVideoFullscreenManager::requestExitFullscreen):
(WebKit::WebVideoFullscreenManager::selectAudioMediaOption):
(WebKit::WebVideoFullscreenManager::selectLegibleMediaOption):
(WebKit::WebVideoFullscreenManager::fullscreenModeChanged):
(WebKit::WebVideoFullscreenManager::didSetupFullscreen):
(WebKit::WebVideoFullscreenManager::didEnterFullscreen):
(WebKit::WebVideoFullscreenManager::didExitFullscreen):
(WebKit::WebVideoFullscreenManager::didCleanupFullscreen):
(WebKit::WebVideoFullscreenManager::setVideoLayerGravityEnum):
(WebKit::WebVideoFullscreenManager::fullscreenMayReturnToInline):
(WebKit::WebVideoFullscreenManager::setVideoLayerFrameFenced):
(WebKit::WebVideoFullscreenManager::exitVideoFullscreen): Deleted.

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

15 files changed:
Source/WebCore/ChangeLog
Source/WebCore/html/HTMLMediaElement.h
Source/WebCore/platform/ios/WebVideoFullscreenControllerAVKit.mm
Source/WebCore/platform/ios/WebVideoFullscreenInterfaceAVKit.h
Source/WebCore/platform/ios/WebVideoFullscreenInterfaceAVKit.mm
Source/WebCore/platform/ios/WebVideoFullscreenModelVideoElement.h
Source/WebCore/platform/ios/WebVideoFullscreenModelVideoElement.mm
Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit2/UIProcess/ios/WebVideoFullscreenManagerProxy.h
Source/WebKit2/UIProcess/ios/WebVideoFullscreenManagerProxy.messages.in
Source/WebKit2/UIProcess/ios/WebVideoFullscreenManagerProxy.mm
Source/WebKit2/WebProcess/ios/WebVideoFullscreenManager.h
Source/WebKit2/WebProcess/ios/WebVideoFullscreenManager.messages.in
Source/WebKit2/WebProcess/ios/WebVideoFullscreenManager.mm

index 5d71c08..ccde79f 100644 (file)
@@ -1,3 +1,25 @@
+2015-04-13  Jer Noble  <jer.noble@apple.com>
+
+        [iOS] When simultaneously exiting-and-entering fullscreen, WebVideoFullscreenManager/Proxy becomes confused about what video element it represents.
+        https://bugs.webkit.org/show_bug.cgi?id=143680
+
+        Reviewed by Simon Fraser.
+
+        Add getters for the video's fullscreen layer, and be more tolerant about the order in which setVideoElement() and 
+        setWebVideoFullscreenInterface are called.
+
+        * html/HTMLMediaElement.h:
+        (WebCore::HTMLMediaElement::videoFullscreenLayer): Added simple getter.
+        * platform/ios/WebVideoFullscreenInterfaceAVKit.h:
+        * platform/ios/WebVideoFullscreenModelVideoElement.h:
+        (WebCore::WebVideoFullscreenModelVideoElement::videoElement): Added simple getter.
+        (WebCore::WebVideoFullscreenModelVideoElement::setWebVideoFullscreenInterface): Deleted. Moved to .mm file.
+        * platform/ios/WebVideoFullscreenModelVideoElement.mm:
+        (WebVideoFullscreenModelVideoElement::WebVideoFullscreenModelVideoElement): Initialize ivars in the .h file.
+        (WebVideoFullscreenModelVideoElement::setWebVideoFullscreenInterface): Call those methods skipped in setVideoElement()
+            if m_videoFullscreenInterface had not yet been set.
+        (WebVideoFullscreenModelVideoElement::setVideoElement): Null-check m_videoFullscreenInterface.
+
 2015-04-16  Beth Dakin  <bdakin@apple.com>
 
         Force mouse events should go through normal mouse event handling code paths
index 452c343..1409e6b 100644 (file)
@@ -128,6 +128,7 @@ public:
     PlatformLayer* platformLayer() const;
 #if PLATFORM(IOS)
     void setVideoFullscreenLayer(PlatformLayer*);
+    PlatformLayer* videoFullscreenLayer() const { return m_videoFullscreenLayer.get(); }
     void setVideoFullscreenFrame(FloatRect);
     void setVideoFullscreenGravity(MediaPlayer::VideoGravity);
     MediaPlayer::VideoGravity videoFullscreenGravity() const { return m_videoFullscreenGravity; }
index 3f855d0..7a53737 100644 (file)
@@ -125,9 +125,9 @@ public:
 {
     [self retain]; // Balanced by -release in didExitFullscreen:
     
-    _interface = adoptRef(new WebVideoFullscreenInterfaceAVKit);
+    _interface = WebVideoFullscreenInterfaceAVKit::create();
     _interface->setWebVideoFullscreenChangeObserver(&_changeObserver);
-    _model = adoptRef(new WebVideoFullscreenModelVideoElement);
+    _model = WebVideoFullscreenModelVideoElement::create();
     _model->setWebVideoFullscreenInterface(_interface.get());
     _interface->setWebVideoFullscreenModel(_model.get());
     _model->setVideoElement(_videoElement.get());
index 8473f6b..3273148 100644 (file)
@@ -68,7 +68,10 @@ class WEBCORE_EXPORT WebVideoFullscreenInterfaceAVKit
     , public ThreadSafeRefCounted<WebVideoFullscreenInterfaceAVKit> {
 
 public:
-    WEBCORE_EXPORT WebVideoFullscreenInterfaceAVKit();
+    static Ref<WebVideoFullscreenInterfaceAVKit> create()
+    {
+        return adoptRef(*new WebVideoFullscreenInterfaceAVKit());
+    }
     virtual ~WebVideoFullscreenInterfaceAVKit() { }
     WEBCORE_EXPORT void setWebVideoFullscreenModel(WebVideoFullscreenModel*);
     WEBCORE_EXPORT void setWebVideoFullscreenChangeObserver(WebVideoFullscreenChangeObserver*);
@@ -95,7 +98,7 @@ public:
 
     HTMLMediaElement::VideoFullscreenMode mode() const { return m_mode; }
     void setIsOptimized(bool);
-    WEBCORE_EXPORT bool mayAutomaticallyShowVideoOptimized();
+    WEBCORE_EXPORT bool mayAutomaticallyShowVideoOptimized() const;
     void fullscreenMayReturnToInline(std::function<void(bool)> callback);
 
     void willStartOptimizedFullscreen();
@@ -106,7 +109,13 @@ public:
     void didCancelOptimizedFullscreen();
     void prepareForOptimizedFullscreenStopWithCompletionHandler(void (^)(BOOL));
 
+    void setMode(HTMLMediaElement::VideoFullscreenMode);
+    void clearMode(HTMLMediaElement::VideoFullscreenMode);
+    bool hasMode(HTMLMediaElement::VideoFullscreenMode mode) const { return m_mode & mode; }
+    bool isMode(HTMLMediaElement::VideoFullscreenMode mode) const { return m_mode == mode; }
+
 protected:
+    WEBCORE_EXPORT WebVideoFullscreenInterfaceAVKit();
     void beginSession();
     void setupFullscreenInternal(PlatformLayer&, const IntRect& initialRect, UIView *, HTMLMediaElement::VideoFullscreenMode, bool allowOptimizedFullscreen);
     void enterFullscreenOptimized();
@@ -114,11 +123,6 @@ protected:
     void exitFullscreenInternal(const IntRect& finalRect);
     void cleanupFullscreenInternal();
 
-    void setMode(HTMLMediaElement::VideoFullscreenMode);
-    void clearMode(HTMLMediaElement::VideoFullscreenMode);
-    bool hasMode(HTMLMediaElement::VideoFullscreenMode mode) const { return m_mode & mode; }
-    bool isMode(HTMLMediaElement::VideoFullscreenMode mode) const { return m_mode == mode; }
-
     RetainPtr<WebAVPlayerController> m_playerController;
     RetainPtr<AVPlayerViewController> m_playerViewController;
     RetainPtr<CALayer> m_videoLayer;
index 2938ea8..809109a 100644 (file)
@@ -1175,7 +1175,7 @@ void WebVideoFullscreenInterfaceAVKit::preparedToReturnToInline(bool visible, co
     });
 }
 
-bool WebVideoFullscreenInterfaceAVKit::mayAutomaticallyShowVideoOptimized()
+bool WebVideoFullscreenInterfaceAVKit::mayAutomaticallyShowVideoOptimized() const
 {
     return [m_playerController isPlaying] && m_mode == HTMLMediaElement::VideoFullscreenModeStandard && wkIsOptimizedFullscreenSupported();
 }
index 599a74a..d0c7af5 100644 (file)
@@ -45,10 +45,13 @@ class WebVideoFullscreenInterface;
 
 class WebVideoFullscreenModelVideoElement : public WebVideoFullscreenModel, public EventListener {
 public:
-    WEBCORE_EXPORT WebVideoFullscreenModelVideoElement();
+    static RefPtr<WebVideoFullscreenModelVideoElement> create() {
+        return adoptRef(*new WebVideoFullscreenModelVideoElement());
+    }
     WEBCORE_EXPORT virtual ~WebVideoFullscreenModelVideoElement();
-    void setWebVideoFullscreenInterface(WebVideoFullscreenInterface* interface) {m_videoFullscreenInterface = interface;}
+    WEBCORE_EXPORT void setWebVideoFullscreenInterface(WebVideoFullscreenInterface*);
     WEBCORE_EXPORT void setVideoElement(HTMLVideoElement*);
+    WEBCORE_EXPORT HTMLVideoElement* videoElement() const { return m_videoElement.get(); }
     WEBCORE_EXPORT void setVideoFullscreenLayer(PlatformLayer*);
     
     WEBCORE_EXPORT virtual void handleEvent(WebCore::ScriptExecutionContext*, WebCore::Event*) override;
@@ -75,14 +78,17 @@ public:
     WEBCORE_EXPORT virtual void selectLegibleMediaOption(uint64_t index) override;
     WEBCORE_EXPORT virtual void fullscreenModeChanged(HTMLMediaElement::VideoFullscreenMode) override;
 
+protected:
+    WEBCORE_EXPORT WebVideoFullscreenModelVideoElement();
+
 private:
     static const Vector<WTF::AtomicString>& observedEventNames();
     const WTF::AtomicString& eventNameAll();
     
     RefPtr<HTMLVideoElement> m_videoElement;
     RetainPtr<PlatformLayer> m_videoFullscreenLayer;
-    bool m_isListening;
-    WebVideoFullscreenInterface* m_videoFullscreenInterface;
+    bool m_isListening { false };
+    WebVideoFullscreenInterface* m_videoFullscreenInterface { nullptr };
     FloatRect m_videoFrame;
     Vector<RefPtr<TextTrack>> m_legibleTracksForMenu;
     Vector<RefPtr<AudioTrack>> m_audioTracksForMenu;
index 69f7bda..11ed663 100644 (file)
@@ -53,8 +53,6 @@ using namespace WebCore;
 
 WebVideoFullscreenModelVideoElement::WebVideoFullscreenModelVideoElement()
     : EventListener(EventListener::CPPEventListenerType)
-    , m_isListening(false)
-    , m_videoFullscreenInterface(nullptr)
 {
 }
 
@@ -62,6 +60,20 @@ WebVideoFullscreenModelVideoElement::~WebVideoFullscreenModelVideoElement()
 {
 }
 
+void WebVideoFullscreenModelVideoElement::setWebVideoFullscreenInterface(WebVideoFullscreenInterface* interface)
+{
+    if (interface == m_videoFullscreenInterface)
+        return;
+
+    m_videoFullscreenInterface = interface;
+
+    if (m_videoFullscreenInterface) {
+        m_videoFullscreenInterface->resetMediaState();
+        if (m_videoElement)
+            m_videoFullscreenInterface->setVideoDimensions(true, m_videoElement->videoWidth(), m_videoElement->videoHeight());
+    }
+}
+
 void WebVideoFullscreenModelVideoElement::setVideoElement(HTMLVideoElement* videoElement)
 {
     if (m_videoElement == videoElement)
@@ -69,7 +81,13 @@ void WebVideoFullscreenModelVideoElement::setVideoElement(HTMLVideoElement* vide
 
     if (m_videoFullscreenInterface)
         m_videoFullscreenInterface->resetMediaState();
-    
+
+    if (m_videoElement && m_videoElement->fullscreenMode())
+        m_videoElement->fullscreenModeChanged(HTMLMediaElement::VideoFullscreenModeNone);
+
+    if (m_videoElement && m_videoElement->videoFullscreenLayer())
+        m_videoElement->setVideoFullscreenLayer(nullptr);
+
     if (m_videoElement && m_isListening) {
         for (auto eventName : observedEventNames())
             m_videoElement->removeEventListener(eventName, this, false);
@@ -87,7 +105,8 @@ void WebVideoFullscreenModelVideoElement::setVideoElement(HTMLVideoElement* vide
 
     updateForEventName(eventNameAll());
 
-    m_videoFullscreenInterface->setVideoDimensions(true, videoElement->videoWidth(), videoElement->videoHeight());
+    if (m_videoFullscreenInterface)
+        m_videoFullscreenInterface->setVideoDimensions(true, videoElement->videoWidth(), videoElement->videoHeight());
 }
 
 void WebVideoFullscreenModelVideoElement::handleEvent(WebCore::ScriptExecutionContext*, WebCore::Event* event)
index ddc9d87..a4335cb 100644 (file)
@@ -1,3 +1,198 @@
+2015-04-13  Jer Noble  <jer.noble@apple.com>
+
+        [iOS] When simultaneously exiting-and-entering fullscreen, WebVideoFullscreenManager/Proxy becomes confused about what video element it represents.
+        https://bugs.webkit.org/show_bug.cgi?id=143680
+
+        Reviewed by Simon Fraser.
+
+        The original assumption of WebVideoFullscreenManager and -Proxy was that the two classes would represent a
+        single video element and its full screen state. With multiple animations in and out of fullscreen combined with
+        multiple fullscreen modes, this assumption no longer holds true.
+
+        Rather than having a WebVideoFullscreenManager which /isa/ WebVideoFullscreenModelVideoElement, the manager now
+        /hasa/ WebVideoFullscreenModelVideoElement (or has many such models). Ditto for WebVideoFullscreenManager and
+        WebVideoFullscreenInterfaceAVKit. The WebVideoFullscreenInterfaceAVKit still needs a WebVideoFullscreenModel to
+        communicate with, so a new wrapper class is used for that purpose, WebVideoFullscreenModelContext. Ditto for
+        WebVideoFullscreenModelVideoElement and the new class WebVideoFullscreenInterfaceContext. These context classes
+        are paired and share a contextId, allowing the manager and its proxy to route messages between the UIProcess's
+        WebVideoFullscreenInterfaceAVKit to-and-from the WebProcess's WebVideoFullscreenModelVideoElement.
+
+        Both the WebVideoFullscreenModelContext and the WebVideoFullscreenInterfaceContext take a back-pointer to their
+        manager or manager proxy, and each method on the context simply calls the matching method on the manager and
+        passes its contextId as a parameter.
+
+        Both the WebVideoFullscreenManager and the WebVideoFullscreenManagerProxy pass that contextId in each of their
+        cross-process messages.
+
+        On the other side, the manager and proxy also have a map between contextIds and their matching
+        WebVideoFullscreenModelVideoElement (in the case of WebVideoFullscreenManager) or
+        WebVideoFullscreenInterfaceAVKit (in the case of WebVideoFullscreenManagerProxy).
+
+        While this change is large by LoC, it is almost entirely boilerplate.  The new and interesting pieces are these:
+
+        * UIProcess/ios/WebVideoFullscreenManagerProxy.mm:
+        (WebKit::WebVideoFullscreenManagerProxy::WebVideoFullscreenManagerProxy): No longer a WebVideoFullscreenInterfaceAVKit.
+        (WebKit::WebVideoFullscreenManagerProxy::invalidate): Walk through the models and interfaces, invalidating each.
+        (WebKit::WebVideoFullscreenManagerProxy::createModelAndInterface): Added. Return a new model and interface tuple.
+        (WebKit::WebVideoFullscreenManagerProxy::ensureModelAndInterface): Added. Lazily create, and add to the m_contextMap
+            a new model and interface object.
+        (WebKit::WebVideoFullscreenManagerProxy::ensureModel): Return the model half of ensureModelAndInterface().
+        (WebKit::WebVideoFullscreenManagerProxy::ensureInterface): Return the interface half of ensureModelAndInterface().
+        (WebKit::WebVideoFullscreenManagerProxy::enterFullscreen): Walk through the outstanding interface objects, and if 
+            any have a fullscreen mode which matches the about-to-be-fullscreen interface, request that that other interface
+            exit fullscreen.
+        * WebProcess/ios/WebVideoFullscreenManager.mm:
+        (WebKit::nextContextId): Static, incrementing counter used as a contextId source.
+        (WebKit::WebVideoFullscreenManager::WebVideoFullscreenManager): No longer a WebVideoFullscreenModelVideoElement.
+        (WebKit::WebVideoFullscreenManager::~WebVideoFullscreenManager): Walk through the models and interfaces, invalidating each.
+        (WebKit::WebVideoFullscreenManager::ensureModelAndInterface): Added. Return a new model and interface tuple.
+        (WebKit::WebVideoFullscreenManager::ensureModelAndInterface):  Added. Lazily create, and add to the m_contextMap
+            a new model and interface object.
+        (WebKit::WebVideoFullscreenManager::ensureModel): Return the model half of ensureModelAndInterface().
+        (WebKit::WebVideoFullscreenManager::ensureInterface): Return the interface half of ensureModelAndInterface().
+
+        New classes and methods which just forward on to their owning objects:
+
+        * UIProcess/ios/WebVideoFullscreenManagerProxy.h:
+        (WebKit::WebVideoFullscreenModelContext::create):
+        (WebKit::WebVideoFullscreenModelContext::~WebVideoFullscreenModelContext):
+        (WebKit::WebVideoFullscreenModelContext::invalidate):
+        (WebKit::WebVideoFullscreenModelContext::layerHost):
+        (WebKit::WebVideoFullscreenModelContext::setLayerHost):
+        (WebKit::WebVideoFullscreenModelContext::setInitialVideoLayerFrame):
+        (WebKit::WebVideoFullscreenModelContext::WebVideoFullscreenModelContext):
+        * UIProcess/ios/WebVideoFullscreenManagerProxy.mm:
+        (WebKit::WebVideoFullscreenModelContext::play):
+        (WebKit::WebVideoFullscreenModelContext::pause):
+        (WebKit::WebVideoFullscreenModelContext::togglePlayState):
+        (WebKit::WebVideoFullscreenModelContext::beginScrubbing):
+        (WebKit::WebVideoFullscreenModelContext::endScrubbing):
+        (WebKit::WebVideoFullscreenModelContext::seekToTime):
+        (WebKit::WebVideoFullscreenModelContext::fastSeek):
+        (WebKit::WebVideoFullscreenModelContext::beginScanningForward):
+        (WebKit::WebVideoFullscreenModelContext::beginScanningBackward):
+        (WebKit::WebVideoFullscreenModelContext::endScanning):
+        (WebKit::WebVideoFullscreenModelContext::requestExitFullscreen):
+        (WebKit::WebVideoFullscreenModelContext::setVideoLayerFrame):
+        (WebKit::WebVideoFullscreenModelContext::videoLayerFrame):
+        (WebKit::WebVideoFullscreenModelContext::setVideoLayerGravity):
+        (WebKit::WebVideoFullscreenModelContext::videoLayerGravity):
+        (WebKit::WebVideoFullscreenModelContext::selectAudioMediaOption):
+        (WebKit::WebVideoFullscreenModelContext::selectLegibleMediaOption):
+        (WebKit::WebVideoFullscreenModelContext::fullscreenModeChanged):
+        (WebKit::WebVideoFullscreenModelContext::didSetupFullscreen):
+        (WebKit::WebVideoFullscreenModelContext::didEnterFullscreen):
+        (WebKit::WebVideoFullscreenModelContext::didExitFullscreen):
+        (WebKit::WebVideoFullscreenModelContext::didCleanupFullscreen):
+        (WebKit::WebVideoFullscreenModelContext::fullscreenMayReturnToInline):
+        * WebProcess/ios/WebVideoFullscreenManager.h:
+        (WebKit::WebVideoFullscreenInterfaceContext::create):
+        (WebKit::WebVideoFullscreenInterfaceContext::invalidate):
+        (WebKit::WebVideoFullscreenInterfaceContext::layerHostingContext):
+        (WebKit::WebVideoFullscreenInterfaceContext::isAnimating):
+        (WebKit::WebVideoFullscreenInterfaceContext::setIsAnimating):
+        (WebKit::WebVideoFullscreenInterfaceContext::targetIsFullscreen):
+        (WebKit::WebVideoFullscreenInterfaceContext::setTargetIsFullscreen):
+        (WebKit::WebVideoFullscreenInterfaceContext::fullscreenMode):
+        (WebKit::WebVideoFullscreenInterfaceContext::setFullscreenMode):
+        (WebKit::WebVideoFullscreenInterfaceContext::isFullscreen):
+        (WebKit::WebVideoFullscreenInterfaceContext::setIsFullscreen):
+        * WebProcess/ios/WebVideoFullscreenManager.mm:
+        (WebKit::WebVideoFullscreenInterfaceContext::WebVideoFullscreenInterfaceContext):
+        (WebKit::WebVideoFullscreenInterfaceContext::~WebVideoFullscreenInterfaceContext):
+        (WebKit::WebVideoFullscreenInterfaceContext::setLayerHostingContext):
+        (WebKit::WebVideoFullscreenInterfaceContext::resetMediaState):
+        (WebKit::WebVideoFullscreenInterfaceContext::setDuration):
+        (WebKit::WebVideoFullscreenInterfaceContext::setCurrentTime):
+        (WebKit::WebVideoFullscreenInterfaceContext::setBufferedTime):
+        (WebKit::WebVideoFullscreenInterfaceContext::setRate):
+        (WebKit::WebVideoFullscreenInterfaceContext::setVideoDimensions):
+        (WebKit::WebVideoFullscreenInterfaceContext::setSeekableRanges):
+        (WebKit::WebVideoFullscreenInterfaceContext::setCanPlayFastReverse):
+        (WebKit::WebVideoFullscreenInterfaceContext::setAudioMediaSelectionOptions):
+        (WebKit::WebVideoFullscreenInterfaceContext::setLegibleMediaSelectionOptions):
+        (WebKit::WebVideoFullscreenInterfaceContext::setExternalPlayback):
+
+        Cross-process methods which now take a contextId parameter:
+
+        * UIProcess/ios/WebVideoFullscreenManagerProxy.messages.in:
+        * UIProcess/ios/WebVideoFullscreenManagerProxy.mm:
+        (WebKit::WebVideoFullscreenManagerProxy::setupFullscreenWithID):
+        (WebKit::WebVideoFullscreenManagerProxy::resetMediaState):
+        (WebKit::WebVideoFullscreenManagerProxy::setCurrentTime):
+        (WebKit::WebVideoFullscreenManagerProxy::setBufferedTime):
+        (WebKit::WebVideoFullscreenManagerProxy::setVideoDimensions):
+        (WebKit::WebVideoFullscreenManagerProxy::setSeekableRangesVector):
+        (WebKit::WebVideoFullscreenManagerProxy::setCanPlayFastReverse):
+        (WebKit::WebVideoFullscreenManagerProxy::setAudioMediaSelectionOptions):
+        (WebKit::WebVideoFullscreenManagerProxy::setLegibleMediaSelectionOptions):
+        (WebKit::WebVideoFullscreenManagerProxy::setExternalPlaybackProperties):
+        (WebKit::WebVideoFullscreenManagerProxy::setDuration):
+        (WebKit::WebVideoFullscreenManagerProxy::setRate):
+        (WebKit::WebVideoFullscreenManagerProxy::exitFullscreen):
+        (WebKit::WebVideoFullscreenManagerProxy::cleanupFullscreen):
+        (WebKit::WebVideoFullscreenManagerProxy::preparedToReturnToInline):
+        (WebKit::WebVideoFullscreenManagerProxy::play):
+        (WebKit::WebVideoFullscreenManagerProxy::pause):
+        (WebKit::WebVideoFullscreenManagerProxy::togglePlayState):
+        (WebKit::WebVideoFullscreenManagerProxy::beginScrubbing):
+        (WebKit::WebVideoFullscreenManagerProxy::endScrubbing):
+        (WebKit::WebVideoFullscreenManagerProxy::seekToTime):
+        (WebKit::WebVideoFullscreenManagerProxy::fastSeek):
+        (WebKit::WebVideoFullscreenManagerProxy::beginScanningForward):
+        (WebKit::WebVideoFullscreenManagerProxy::beginScanningBackward):
+        (WebKit::WebVideoFullscreenManagerProxy::endScanning):
+        (WebKit::WebVideoFullscreenManagerProxy::requestExitFullscreen):
+        (WebKit::WebVideoFullscreenManagerProxy::didSetupFullscreen):
+        (WebKit::WebVideoFullscreenManagerProxy::didExitFullscreen):
+        (WebKit::WebVideoFullscreenManagerProxy::didEnterFullscreen):
+        (WebKit::WebVideoFullscreenManagerProxy::didCleanupFullscreen):
+        (WebKit::WebVideoFullscreenManagerProxy::setVideoLayerFrame):
+        (WebKit::WebVideoFullscreenManagerProxy::setVideoLayerGravity):
+        (WebKit::WebVideoFullscreenManagerProxy::selectAudioMediaOption):
+        (WebKit::WebVideoFullscreenManagerProxy::selectLegibleMediaOption):
+        (WebKit::WebVideoFullscreenManagerProxy::fullscreenModeChanged):
+        (WebKit::WebVideoFullscreenManagerProxy::fullscreenMayReturnToInline):
+        (WebKit::WebVideoFullscreenManagerProxy::videoLayerFrame): Deleted.
+        (WebKit::WebVideoFullscreenManagerProxy::videoLayerGravity): Deleted.
+        * WebProcess/ios/WebVideoFullscreenManager.messages.in:
+        * WebProcess/ios/WebVideoFullscreenManager.mm:
+        (WebKit::WebVideoFullscreenManager::enterVideoFullscreenForVideoElement):
+        (WebKit::WebVideoFullscreenManager::exitVideoFullscreenForVideoElement):
+        (WebKit::WebVideoFullscreenManager::resetMediaState):
+        (WebKit::WebVideoFullscreenManager::setDuration):
+        (WebKit::WebVideoFullscreenManager::setCurrentTime):
+        (WebKit::WebVideoFullscreenManager::setBufferedTime):
+        (WebKit::WebVideoFullscreenManager::setRate):
+        (WebKit::WebVideoFullscreenManager::setVideoDimensions):
+        (WebKit::WebVideoFullscreenManager::setSeekableRanges):
+        (WebKit::WebVideoFullscreenManager::setCanPlayFastReverse):
+        (WebKit::WebVideoFullscreenManager::setAudioMediaSelectionOptions):
+        (WebKit::WebVideoFullscreenManager::setLegibleMediaSelectionOptions):
+        (WebKit::WebVideoFullscreenManager::setExternalPlayback):
+        (WebKit::WebVideoFullscreenManager::play):
+        (WebKit::WebVideoFullscreenManager::pause):
+        (WebKit::WebVideoFullscreenManager::togglePlayState):
+        (WebKit::WebVideoFullscreenManager::beginScrubbing):
+        (WebKit::WebVideoFullscreenManager::endScrubbing):
+        (WebKit::WebVideoFullscreenManager::seekToTime):
+        (WebKit::WebVideoFullscreenManager::fastSeek):
+        (WebKit::WebVideoFullscreenManager::beginScanningForward):
+        (WebKit::WebVideoFullscreenManager::beginScanningBackward):
+        (WebKit::WebVideoFullscreenManager::endScanning):
+        (WebKit::WebVideoFullscreenManager::requestExitFullscreen):
+        (WebKit::WebVideoFullscreenManager::selectAudioMediaOption):
+        (WebKit::WebVideoFullscreenManager::selectLegibleMediaOption):
+        (WebKit::WebVideoFullscreenManager::fullscreenModeChanged):
+        (WebKit::WebVideoFullscreenManager::didSetupFullscreen):
+        (WebKit::WebVideoFullscreenManager::didEnterFullscreen):
+        (WebKit::WebVideoFullscreenManager::didExitFullscreen):
+        (WebKit::WebVideoFullscreenManager::didCleanupFullscreen):
+        (WebKit::WebVideoFullscreenManager::setVideoLayerGravityEnum):
+        (WebKit::WebVideoFullscreenManager::fullscreenMayReturnToInline):
+        (WebKit::WebVideoFullscreenManager::setVideoLayerFrameFenced):
+        (WebKit::WebVideoFullscreenManager::exitVideoFullscreen): Deleted.
+
 2015-04-16  Beth Dakin  <bdakin@apple.com>
 
         Force mouse events should go through normal mouse event handling code paths
index dfc4b56..7c15f5e 100644 (file)
@@ -242,7 +242,7 @@ static int32_t deviceOrientation()
     if (!_page || !_page->videoFullscreenManager())
         return false;
     
-    return _page->videoFullscreenManager()->mode() & WebCore::HTMLMediaElement::VideoFullscreenModeOptimized;
+    return _page->videoFullscreenManager()->hasMode(WebCore::HTMLMediaElement::VideoFullscreenModeOptimized);
 }
 
 - (BOOL)_mayAutomaticallyShowVideoOptimized
index d9e65ce..b498ae8 100644 (file)
@@ -41,34 +41,31 @@ OBJC_CLASS UIView;
 namespace WebKit {
 
 class WebPageProxy;
+class WebVideoFullscreenManagerProxy;
 
-class WebVideoFullscreenManagerProxy : public WebCore::WebVideoFullscreenInterfaceAVKit, public WebCore::WebVideoFullscreenChangeObserver, public WebCore::WebVideoFullscreenModel, private IPC::MessageReceiver {
+class WebVideoFullscreenModelContext final: public RefCounted<WebVideoFullscreenModelContext>, public WebCore::WebVideoFullscreenModel, public WebCore::WebVideoFullscreenChangeObserver  {
 public:
-    static PassRefPtr<WebVideoFullscreenManagerProxy> create(WebPageProxy&);
-    virtual ~WebVideoFullscreenManagerProxy();
+    static Ref<WebVideoFullscreenModelContext> create(WebVideoFullscreenManagerProxy& manager, uint64_t contextId)
+    {
+        return adoptRef(*new WebVideoFullscreenModelContext(manager, contextId));
+    }
+    virtual ~WebVideoFullscreenModelContext() { }
 
-    virtual void invalidate() override;
-    virtual void requestExitFullscreen() override;
+    void invalidate() { m_manager = nullptr; }
 
-private:
-    explicit WebVideoFullscreenManagerProxy(WebPageProxy&);
-    virtual void didReceiveMessage(IPC::Connection&, IPC::MessageDecoder&) override;
+    PlatformLayer* layerHost() const { return m_layerHost.get(); }
+    void setLayerHost(RetainPtr<PlatformLayer>&& layerHost) { m_layerHost = WTF::move(layerHost); }
 
-    // Translate to FullscreenInterface
-    void setupFullscreenWithID(uint32_t, const WebCore::IntRect& initialRect, float hostingDeviceScaleFactor, WebCore::HTMLMediaElement::VideoFullscreenMode, bool allowOptimizedFullscreen);
-    void setSeekableRangesVector(const Vector<std::pair<double, double>>&);
-    void setExternalPlaybackProperties(bool enabled, uint32_t targetType, String localizedDeviceName);
-    void fullscreenModeChanged(WebCore::HTMLMediaElement::VideoFullscreenMode) override;
-    void preparedToReturnToInline(bool visible, const WebCore::IntRect& inlineRect) override;
+    void setInitialVideoLayerFrame(WebCore::FloatRect frame) { m_videoLayerFrame = frame; }
 
-    // Fullscreen Observer
-    virtual void didSetupFullscreen() override;
-    virtual void didEnterFullscreen() override;
-    virtual void didExitFullscreen() override;
-    virtual void didCleanupFullscreen() override;
-    virtual void fullscreenMayReturnToInline() override;
-    
-    // FullscreenModel
+private:
+    WebVideoFullscreenModelContext(WebVideoFullscreenManagerProxy& manager, uint64_t contextId)
+        : m_manager(&manager)
+        , m_contextId(contextId)
+    {
+    }
+
+    // WebVideoFullscreenModel
     virtual void play() override;
     virtual void pause() override;
     virtual void togglePlayState() override;
@@ -79,18 +76,97 @@ private:
     virtual void beginScanningForward() override;
     virtual void beginScanningBackward() override;
     virtual void endScanning() override;
+    virtual void requestExitFullscreen() override;
     virtual void setVideoLayerFrame(WebCore::FloatRect) override;
     virtual WebCore::FloatRect videoLayerFrame() const override;
-    virtual void setVideoLayerGravity(WebCore::WebVideoFullscreenModel::VideoGravity) override;
+    virtual void setVideoLayerGravity(VideoGravity) override;
     virtual VideoGravity videoLayerGravity() const override;
     virtual void selectAudioMediaOption(uint64_t) override;
     virtual void selectLegibleMediaOption(uint64_t) override;
+    virtual void fullscreenModeChanged(WebCore::HTMLMediaElement::VideoFullscreenMode) override;
 
-    WebPageProxy* m_page;
+    // WebVideoFullscreenChangeObserver
+    virtual void didSetupFullscreen() override;
+    virtual void didEnterFullscreen() override;
+    virtual void didExitFullscreen() override;
+    virtual void didCleanupFullscreen() override;
+    virtual void fullscreenMayReturnToInline() override;
+
+    WebVideoFullscreenManagerProxy* m_manager;
+    uint64_t m_contextId;
     RetainPtr<PlatformLayer> m_layerHost;
     WebCore::FloatRect m_videoLayerFrame;
     VideoGravity m_videoLayerGravity { VideoGravityResize };
 };
+
+class WebVideoFullscreenManagerProxy : public RefCounted<WebVideoFullscreenManagerProxy>, private IPC::MessageReceiver {
+public:
+    static PassRefPtr<WebVideoFullscreenManagerProxy> create(WebPageProxy&);
+    virtual ~WebVideoFullscreenManagerProxy();
+
+    void invalidate();
+
+    void requestHideAndExitFullscreen();
+    bool hasMode(WebCore::HTMLMediaElement::VideoFullscreenMode) const;
+    bool mayAutomaticallyShowVideoOptimized() const;
+
+private:
+    friend class WebVideoFullscreenModelContext;
+
+    explicit WebVideoFullscreenManagerProxy(WebPageProxy&);
+    virtual void didReceiveMessage(IPC::Connection&, IPC::MessageDecoder&) override;
+
+    typedef std::tuple<RefPtr<WebVideoFullscreenModelContext>, RefPtr<WebCore::WebVideoFullscreenInterfaceAVKit>> ModelInterfaceTuple;
+    ModelInterfaceTuple createModelAndInterface(uint64_t contextId);
+    ModelInterfaceTuple& ensureModelAndInterface(uint64_t contextId);
+    WebVideoFullscreenModelContext& ensureModel(uint64_t contextId);
+    WebCore::WebVideoFullscreenInterfaceAVKit& ensureInterface(uint64_t contextId);
+
+    // Messages from WebVideoFullscreenManager
+    void setupFullscreenWithID(uint64_t contextId, uint32_t videoLayerID, const WebCore::IntRect& initialRect, float hostingScaleFactor, WebCore::HTMLMediaElement::VideoFullscreenMode, bool allowOptimizedFullscreen);
+    void resetMediaState(uint64_t contextId);
+    void setCurrentTime(uint64_t contextId, double currentTime, double hostTime);
+    void setBufferedTime(uint64_t contextId, double bufferedTime);
+    void setVideoDimensions(uint64_t contextId, bool hasVideo, unsigned width, unsigned height);
+    void setSeekableRangesVector(uint64_t contextId, Vector<std::pair<double, double>> ranges);
+    void setCanPlayFastReverse(uint64_t contextId, bool value);
+    void setAudioMediaSelectionOptions(uint64_t contextId, Vector<String> options, uint64_t selectedIndex);
+    void setLegibleMediaSelectionOptions(uint64_t contextId, Vector<String> options, uint64_t selectedIndex);
+    void setExternalPlaybackProperties(uint64_t contextId, bool enabled, uint32_t targetType, String localizedDeviceName);
+    void setDuration(uint64_t contextId, double duration);
+    void setRate(uint64_t contextId, bool isPlaying, double rate);
+    void enterFullscreen(uint64_t contextId);
+    void exitFullscreen(uint64_t contextId, WebCore::IntRect finalRect);
+    void cleanupFullscreen(uint64_t contextId);
+    void preparedToReturnToInline(uint64_t contextId, bool visible, WebCore::IntRect inlineRect);
+
+    // Messages to WebVideoFullscreenManager
+    void play(uint64_t contextId);
+    void pause(uint64_t contextId);
+    void togglePlayState(uint64_t contextId);
+    void beginScrubbing(uint64_t contextId);
+    void endScrubbing(uint64_t contextId);
+    void seekToTime(uint64_t contextId, double time);
+    void fastSeek(uint64_t contextId, double time);
+    void beginScanningForward(uint64_t contextId);
+    void beginScanningBackward(uint64_t contextId);
+    void endScanning(uint64_t contextId);
+    void requestExitFullscreen(uint64_t contextId);
+    void didSetupFullscreen(uint64_t contextId);
+    void didExitFullscreen(uint64_t contextId);
+    void didEnterFullscreen(uint64_t contextId);
+    void didCleanupFullscreen(uint64_t contextId);
+    void setVideoLayerFrame(uint64_t contextId, WebCore::FloatRect);
+    void setVideoLayerGravity(uint64_t contextId, WebCore::WebVideoFullscreenModel::VideoGravity);
+    void selectAudioMediaOption(uint64_t contextId, uint64_t index);
+    void selectLegibleMediaOption(uint64_t contextId, uint64_t index);
+    void fullscreenModeChanged(uint64_t contextId, WebCore::HTMLMediaElement::VideoFullscreenMode);
+    void fullscreenMayReturnToInline(uint64_t contextId);
+
+    WebPageProxy* m_page;
+    HashMap<uint64_t, ModelInterfaceTuple> m_contextMap;
+
+};
     
 } // namespace WebKit
 
index 7460402..a4e7c27 100644 (file)
 
 #if PLATFORM(IOS)
 messages -> WebVideoFullscreenManagerProxy {
-    ResetMediaState()
-    SetCurrentTime(double currentTime, double hostTime)
-    SetBufferedTime(double bufferedTime)
-    SetVideoDimensions(bool hasVideo, unsigned width, unsigned height)
-    SetSeekableRangesVector(Vector<std::pair<double, double>> ranges);
-    SetCanPlayFastReverse(bool value);
-    SetAudioMediaSelectionOptions(Vector<String> options, uint64_t selectedIndex);
-    SetLegibleMediaSelectionOptions(Vector<String> options, uint64_t selectedIndex);
-    SetExternalPlaybackProperties(bool enabled, uint32_t targetType, String localizedDeviceName);
-    SetDuration(double duration)
-    SetRate(bool isPlaying, double rate)
-    SetupFullscreenWithID(uint32_t videoLayerID, WebCore::IntRect initialRect, float hostingScaleFactor, WebCore::HTMLMediaElement::VideoFullscreenMode videoFullscreenMode, bool allowOptimizedFullscreen)
-    EnterFullscreen()
-    ExitFullscreen(WebCore::IntRect finalRect)
-    CleanupFullscreen()
-    PreparedToReturnToInline(bool visible, WebCore::IntRect inlineRect)
+    ResetMediaState(uint64_t contextId)
+    SetCurrentTime(uint64_t contextId, double currentTime, double hostTime)
+    SetBufferedTime(uint64_t contextId, double bufferedTime)
+    SetVideoDimensions(uint64_t contextId, bool hasVideo, unsigned width, unsigned height)
+    SetSeekableRangesVector(uint64_t contextId, Vector<std::pair<double, double>> ranges)
+    SetCanPlayFastReverse(uint64_t contextId, bool value)
+    SetAudioMediaSelectionOptions(uint64_t contextId, Vector<String> options, uint64_t selectedIndex)
+    SetLegibleMediaSelectionOptions(uint64_t contextId, Vector<String> options, uint64_t selectedIndex)
+    SetExternalPlaybackProperties(uint64_t contextId, bool enabled, uint32_t targetType, String localizedDeviceName)
+    SetDuration(uint64_t contextId, double duration)
+    SetRate(uint64_t contextId, bool isPlaying, double rate)
+    SetupFullscreenWithID(uint64_t contextId, uint32_t videoLayerID, WebCore::IntRect initialRect, float hostingScaleFactor, WebCore::HTMLMediaElement::VideoFullscreenMode videoFullscreenMode, bool allowOptimizedFullscreen)
+    EnterFullscreen(uint64_t contextId)
+    ExitFullscreen(uint64_t contextId, WebCore::IntRect finalRect)
+    CleanupFullscreen(uint64_t contextId)
+    PreparedToReturnToInline(uint64_t contextId, bool visible, WebCore::IntRect inlineRect)
 }
 #endif
index 0fee743..2f3ba2b 100644 (file)
@@ -53,8 +53,168 @@ PassRefPtr<WebVideoFullscreenManagerProxy> WebVideoFullscreenManagerProxy::creat
     return nullptr;
 }
 
+void WebVideoFullscreenManagerProxy::invalidate()
+{
+}
+
+bool WebVideoFullscreenManagerProxy::hasMode(HTMLMediaElement::VideoFullscreenMode) const
+{
+    return false;
+}
+
+bool WebVideoFullscreenManagerProxy::mayAutomaticallyShowVideoOptimized() const
+{
+    return false;
+}
+
+void WebVideoFullscreenManagerProxy::requestHideAndExitFullscreen()
+{
+
+}
 #else
 
+#pragma mark - WebVideoFullscreenModelContext
+
+void WebVideoFullscreenModelContext::play()
+{
+    if (m_manager)
+        m_manager->play(m_contextId);
+}
+
+void WebVideoFullscreenModelContext::pause()
+{
+    if (m_manager)
+        m_manager->pause(m_contextId);
+}
+
+void WebVideoFullscreenModelContext::togglePlayState()
+{
+    if (m_manager)
+        m_manager->togglePlayState(m_contextId);
+}
+
+void WebVideoFullscreenModelContext::beginScrubbing()
+{
+    if (m_manager)
+        m_manager->beginScrubbing(m_contextId);
+}
+
+void WebVideoFullscreenModelContext::endScrubbing()
+{
+    if (m_manager)
+        m_manager->endScrubbing(m_contextId);
+}
+
+void WebVideoFullscreenModelContext::seekToTime(double time)
+{
+    if (m_manager)
+        m_manager->seekToTime(m_contextId, time);
+}
+
+void WebVideoFullscreenModelContext::fastSeek(double time)
+{
+    if (m_manager)
+        m_manager->fastSeek(m_contextId, time);
+}
+
+void WebVideoFullscreenModelContext::beginScanningForward()
+{
+    if (m_manager)
+        m_manager->beginScanningForward(m_contextId);
+}
+
+void WebVideoFullscreenModelContext::beginScanningBackward()
+{
+    if (m_manager)
+        m_manager->beginScanningBackward(m_contextId);
+}
+
+void WebVideoFullscreenModelContext::endScanning()
+{
+    if (m_manager)
+        m_manager->endScanning(m_contextId);
+}
+
+void WebVideoFullscreenModelContext::requestExitFullscreen()
+{
+    if (m_manager)
+        m_manager->requestExitFullscreen(m_contextId);
+}
+
+void WebVideoFullscreenModelContext::setVideoLayerFrame(WebCore::FloatRect frame)
+{
+    m_videoLayerFrame = frame;
+    if (m_manager)
+        m_manager->setVideoLayerFrame(m_contextId, frame);
+}
+
+WebCore::FloatRect WebVideoFullscreenModelContext::videoLayerFrame() const
+{
+    return m_videoLayerFrame;
+}
+
+void WebVideoFullscreenModelContext::setVideoLayerGravity(WebCore::WebVideoFullscreenModel::VideoGravity gravity)
+{
+    m_videoLayerGravity = gravity;
+    if (m_manager)
+        m_manager->setVideoLayerGravity(m_contextId, gravity);
+}
+
+WebCore::WebVideoFullscreenModel::VideoGravity WebVideoFullscreenModelContext::videoLayerGravity() const
+{
+    return m_videoLayerGravity;
+}
+
+void WebVideoFullscreenModelContext::selectAudioMediaOption(uint64_t optionId)
+{
+    if (m_manager)
+        m_manager->selectAudioMediaOption(m_contextId, optionId);
+}
+
+void WebVideoFullscreenModelContext::selectLegibleMediaOption(uint64_t optionId)
+{
+    if (m_manager)
+        m_manager->selectLegibleMediaOption(m_contextId, optionId);
+}
+
+void WebVideoFullscreenModelContext::fullscreenModeChanged(WebCore::HTMLMediaElement::VideoFullscreenMode mode)
+{
+    if (m_manager)
+        m_manager->fullscreenModeChanged(m_contextId, mode);
+}
+
+void WebVideoFullscreenModelContext::didSetupFullscreen()
+{
+    if (m_manager)
+        m_manager->didSetupFullscreen(m_contextId);
+}
+
+void WebVideoFullscreenModelContext::didEnterFullscreen()
+{
+    if (m_manager)
+        m_manager->didEnterFullscreen(m_contextId);
+}
+
+void WebVideoFullscreenModelContext::didExitFullscreen()
+{
+    if (m_manager)
+        m_manager->didExitFullscreen(m_contextId);
+}
+
+void WebVideoFullscreenModelContext::didCleanupFullscreen()
+{
+    if (m_manager)
+        m_manager->didCleanupFullscreen(m_contextId);
+}
+
+void WebVideoFullscreenModelContext::fullscreenMayReturnToInline()
+{
+    if (m_manager)
+        m_manager->fullscreenMayReturnToInline(m_contextId);
+}
+
+#pragma mark - WebVideoFullscreenManagerProxy
+
 PassRefPtr<WebVideoFullscreenManagerProxy> WebVideoFullscreenManagerProxy::create(WebPageProxy& page)
 {
     return adoptRef(new WebVideoFullscreenManagerProxy(page));
@@ -64,8 +224,6 @@ WebVideoFullscreenManagerProxy::WebVideoFullscreenManagerProxy(WebPageProxy& pag
     : m_page(&page)
 {
     m_page->process().addMessageReceiver(Messages::WebVideoFullscreenManagerProxy::messageReceiverName(), m_page->pageID(), *this);
-    setWebVideoFullscreenModel(this);
-    setWebVideoFullscreenChangeObserver(this);
 }
 
 WebVideoFullscreenManagerProxy::~WebVideoFullscreenManagerProxy()
@@ -77,37 +235,118 @@ WebVideoFullscreenManagerProxy::~WebVideoFullscreenManagerProxy()
 
 void WebVideoFullscreenManagerProxy::invalidate()
 {
-    WebVideoFullscreenInterfaceAVKit::invalidate();
-
     m_page->process().removeMessageReceiver(Messages::WebVideoFullscreenManagerProxy::messageReceiverName(), m_page->pageID());
     m_page = nullptr;
 
-    [m_layerHost removeFromSuperlayer];
-    m_layerHost.clear();
+    for (auto& tuple : m_contextMap.values()) {
+        RefPtr<WebVideoFullscreenModelContext> model;
+        RefPtr<WebCore::WebVideoFullscreenInterfaceAVKit> interface;
+        std::tie(model, interface) = tuple;
+
+        interface->invalidate();
+        [model->layerHost() removeFromSuperlayer];
+        model->setLayerHost(nullptr);
+    }
+
+    m_contextMap.clear();
+}
+
+void WebVideoFullscreenManagerProxy::requestHideAndExitFullscreen()
+{
+    for (auto& tuple : m_contextMap.values())
+        std::get<1>(tuple)->requestHideAndExitFullscreen();
+}
+
+bool WebVideoFullscreenManagerProxy::hasMode(HTMLMediaElement::VideoFullscreenMode mode) const
+{
+    for (auto& tuple : m_contextMap.values()) {
+        if (std::get<1>(tuple)->hasMode(mode))
+            return true;
+    }
+    return false;
 }
 
-void WebVideoFullscreenManagerProxy::setupFullscreenWithID(uint32_t videoLayerID, const WebCore::IntRect& initialRect, float hostingDeviceScaleFactor, HTMLMediaElement::VideoFullscreenMode videoFullscreenMode, bool allowOptimizedFullscreen)
+bool WebVideoFullscreenManagerProxy::mayAutomaticallyShowVideoOptimized() const
+{
+    for (auto& tuple : m_contextMap.values()) {
+        if (std::get<1>(tuple)->mayAutomaticallyShowVideoOptimized())
+            return true;
+    }
+    return false;
+}
+
+WebVideoFullscreenManagerProxy::ModelInterfaceTuple WebVideoFullscreenManagerProxy::createModelAndInterface(uint64_t contextId)
+{
+    Ref<WebVideoFullscreenModelContext> model = WebVideoFullscreenModelContext::create(*this, contextId);
+    Ref<WebCore::WebVideoFullscreenInterfaceAVKit> interface = WebVideoFullscreenInterfaceAVKit::create();
+
+    interface->setWebVideoFullscreenModel(&model.get());
+    interface->setWebVideoFullscreenChangeObserver(&model.get());
+
+    return std::make_tuple(WTF::move(model), WTF::move(interface));
+}
+
+WebVideoFullscreenManagerProxy::ModelInterfaceTuple& WebVideoFullscreenManagerProxy::ensureModelAndInterface(uint64_t contextId)
+{
+    auto addResult = m_contextMap.add(contextId, ModelInterfaceTuple());
+    if (addResult.isNewEntry)
+        addResult.iterator->value = createModelAndInterface(contextId);
+    return addResult.iterator->value;
+}
+
+WebVideoFullscreenModelContext& WebVideoFullscreenManagerProxy::ensureModel(uint64_t contextId)
+{
+    return *std::get<0>(ensureModelAndInterface(contextId));
+}
+
+WebCore::WebVideoFullscreenInterfaceAVKit& WebVideoFullscreenManagerProxy::ensureInterface(uint64_t contextId)
+{
+    return *std::get<1>(ensureModelAndInterface(contextId));
+}
+
+#pragma mark Messages from WebVideoFullscreenManager
+
+void WebVideoFullscreenManagerProxy::setupFullscreenWithID(uint64_t contextId, uint32_t videoLayerID, const WebCore::IntRect& initialRect, float hostingDeviceScaleFactor, HTMLMediaElement::VideoFullscreenMode videoFullscreenMode, bool allowOptimizedFullscreen)
 {
     ASSERT(videoLayerID);
-    m_layerHost = WKMakeRenderLayer(videoLayerID);
+    RefPtr<WebVideoFullscreenModelContext> model;
+    RefPtr<WebCore::WebVideoFullscreenInterfaceAVKit> interface;
+
+    std::tie(model, interface) = ensureModelAndInterface(contextId);
+
+    model->setInitialVideoLayerFrame(initialRect);
+    model->setLayerHost(WKMakeRenderLayer(videoLayerID));
     if (hostingDeviceScaleFactor != 1) {
         // Invert the scale transform added in the WebProcess to fix <rdar://problem/18316542>.
         float inverseScale = 1 / hostingDeviceScaleFactor;
-        [m_layerHost setTransform:CATransform3DMakeScale(inverseScale, inverseScale, 1)];
+        [model->layerHost() setTransform:CATransform3DMakeScale(inverseScale, inverseScale, 1)];
     }
 
-    m_videoLayerFrame = initialRect;
-
     UIView *parentView = downcast<RemoteLayerTreeDrawingAreaProxy>(*m_page->drawingArea()).remoteLayerTreeHost().rootLayer();
-    setupFullscreen(*m_layerHost.get(), initialRect, parentView, videoFullscreenMode, allowOptimizedFullscreen);
+    interface->setupFullscreen(*model->layerHost(), initialRect, parentView, videoFullscreenMode, allowOptimizedFullscreen);
 }
-    
-void WebVideoFullscreenManagerProxy::fullscreenModeChanged(HTMLMediaElement::VideoFullscreenMode mode)
+
+void WebVideoFullscreenManagerProxy::resetMediaState(uint64_t contextId)
 {
-    m_page->send(Messages::WebVideoFullscreenManager::fullscreenModeChanged(mode), m_page->pageID());
+    ensureInterface(contextId).resetMediaState();
 }
-    
-void WebVideoFullscreenManagerProxy::setSeekableRangesVector(const Vector<std::pair<double, double>>& ranges)
+
+void WebVideoFullscreenManagerProxy::setCurrentTime(uint64_t contextId, double currentTime, double hostTime)
+{
+    ensureInterface(contextId).setCurrentTime(currentTime, hostTime);
+}
+
+void WebVideoFullscreenManagerProxy::setBufferedTime(uint64_t contextId, double bufferedTime)
+{
+    ensureInterface(contextId).setBufferedTime(bufferedTime);
+}
+
+void WebVideoFullscreenManagerProxy::setVideoDimensions(uint64_t contextId, bool hasVideo, unsigned width, unsigned height)
+{
+    ensureInterface(contextId).setVideoDimensions(hasVideo, width, height);
+}
+
+void WebVideoFullscreenManagerProxy::setSeekableRangesVector(uint64_t contextId, Vector<std::pair<double, double>> ranges)
 {
     RefPtr<TimeRanges> timeRanges = TimeRanges::create();
     for (const auto& range : ranges)
@@ -118,118 +357,164 @@ void WebVideoFullscreenManagerProxy::setSeekableRangesVector(const Vector<std::p
         timeRanges->add(range.first, range.second);
     }
 
-    setSeekableRanges(*timeRanges);
+    ensureInterface(contextId).setSeekableRanges(*timeRanges);
 }
 
-void WebVideoFullscreenManagerProxy::setExternalPlaybackProperties(bool enabled, uint32_t targetType, String localizedDeviceName)
+void WebVideoFullscreenManagerProxy::setCanPlayFastReverse(uint64_t contextId, bool value)
+{
+    ensureInterface(contextId).setCanPlayFastReverse(value);
+}
+
+void WebVideoFullscreenManagerProxy::setAudioMediaSelectionOptions(uint64_t contextId, Vector<String> options, uint64_t selectedIndex)
+{
+    ensureInterface(contextId).setAudioMediaSelectionOptions(options, selectedIndex);
+}
+
+void WebVideoFullscreenManagerProxy::setLegibleMediaSelectionOptions(uint64_t contextId, Vector<String> options, uint64_t selectedIndex)
+{
+    ensureInterface(contextId).setLegibleMediaSelectionOptions(options, selectedIndex);
+}
+
+void WebVideoFullscreenManagerProxy::setExternalPlaybackProperties(uint64_t contextId, bool enabled, uint32_t targetType, String localizedDeviceName)
 {
     WebVideoFullscreenInterface::ExternalPlaybackTargetType type = static_cast<WebVideoFullscreenInterface::ExternalPlaybackTargetType>(targetType);
-    
     ASSERT(type == WebVideoFullscreenInterface::TargetTypeAirPlay || type == WebVideoFullscreenInterface::TargetTypeTVOut || type == WebVideoFullscreenInterface::TargetTypeNone);
     
-    setExternalPlayback(enabled, type, localizedDeviceName);
+    ensureInterface(contextId).setExternalPlayback(enabled, type, localizedDeviceName);
 }
-    
-void WebVideoFullscreenManagerProxy::fullscreenMayReturnToInline()
+
+void WebVideoFullscreenManagerProxy::setDuration(uint64_t contextId, double duration)
 {
-    bool isViewVisible = m_page->isViewVisible();
-    m_page->send(Messages::WebVideoFullscreenManager::FullscreenMayReturnToInline(isViewVisible), m_page->pageID());
+    ensureInterface(contextId).setDuration(duration);
 }
-    
-void WebVideoFullscreenManagerProxy::preparedToReturnToInline(bool visible, const WebCore::IntRect& inlineRect)
+
+void WebVideoFullscreenManagerProxy::setRate(uint64_t contextId, bool isPlaying, double rate)
 {
-    m_page->fullscreenMayReturnToInline();
-    WebVideoFullscreenInterfaceAVKit::preparedToReturnToInline(visible, inlineRect);
+    ensureInterface(contextId).setRate(isPlaying, rate);
 }
 
-void WebVideoFullscreenManagerProxy::requestExitFullscreen()
+void WebVideoFullscreenManagerProxy::enterFullscreen(uint64_t contextId)
 {
-    m_page->send(Messages::WebVideoFullscreenManager::RequestExitFullscreen(), m_page->pageID());
+    auto& interface = ensureInterface(contextId);
+    interface.enterFullscreen();
+
+    // Only one context can be in a given full screen mode at a time:
+    for (auto& contextPair : m_contextMap) {
+        auto& otherContextId = contextPair.key;
+        if (contextId == otherContextId)
+            continue;
+
+        auto& otherInterface = std::get<1>(contextPair.value);
+        if (otherInterface->hasMode(interface.mode()))
+            otherInterface->requestHideAndExitFullscreen();
+    }
 }
 
-void WebVideoFullscreenManagerProxy::didExitFullscreen()
+void WebVideoFullscreenManagerProxy::exitFullscreen(uint64_t contextId, WebCore::IntRect finalRect)
 {
-    m_page->send(Messages::WebVideoFullscreenManager::DidExitFullscreen(), m_page->pageID());
-    m_page->didExitFullscreen();
+    ensureInterface(contextId).exitFullscreen(finalRect);
 }
-    
-void WebVideoFullscreenManagerProxy::didCleanupFullscreen()
+
+void WebVideoFullscreenManagerProxy::cleanupFullscreen(uint64_t contextId)
 {
-    [CATransaction flush];
-    [m_layerHost removeFromSuperlayer];
-    m_layerHost.clear();
-    m_page->send(Messages::WebVideoFullscreenManager::DidCleanupFullscreen(), m_page->pageID());
+    ensureInterface(contextId).cleanupFullscreen();
 }
 
-void WebVideoFullscreenManagerProxy::didSetupFullscreen()
+void WebVideoFullscreenManagerProxy::preparedToReturnToInline(uint64_t contextId, bool visible, WebCore::IntRect inlineRect)
 {
-    m_page->send(Messages::WebVideoFullscreenManager::DidSetupFullscreen(), m_page->pageID());
+    m_page->fullscreenMayReturnToInline();
+
+    ensureInterface(contextId).preparedToReturnToInline(visible, inlineRect);
 }
 
-void WebVideoFullscreenManagerProxy::didEnterFullscreen()
+#pragma mark Messages to WebVideoFullscreenManager
+
+void WebVideoFullscreenManagerProxy::play(uint64_t contextId)
 {
-    m_page->send(Messages::WebVideoFullscreenManager::DidEnterFullscreen(), m_page->pageID());
-    m_page->didEnterFullscreen();
+    m_page->send(Messages::WebVideoFullscreenManager::Play(contextId), m_page->pageID());
 }
 
-void WebVideoFullscreenManagerProxy::play()
+void WebVideoFullscreenManagerProxy::pause(uint64_t contextId)
 {
-    m_page->send(Messages::WebVideoFullscreenManager::Play(), m_page->pageID());
+    m_page->send(Messages::WebVideoFullscreenManager::Pause(contextId), m_page->pageID());
 }
-    
-void WebVideoFullscreenManagerProxy::pause()
+
+void WebVideoFullscreenManagerProxy::togglePlayState(uint64_t contextId)
 {
-    m_page->send(Messages::WebVideoFullscreenManager::Pause(), m_page->pageID());
+    m_page->send(Messages::WebVideoFullscreenManager::TogglePlayState(contextId), m_page->pageID());
 }
-    
-void WebVideoFullscreenManagerProxy::togglePlayState()
+
+void WebVideoFullscreenManagerProxy::beginScrubbing(uint64_t contextId)
 {
-    m_page->send(Messages::WebVideoFullscreenManager::TogglePlayState(), m_page->pageID());
+    m_page->send(Messages::WebVideoFullscreenManager::BeginScrubbing(contextId), m_page->pageID());
 }
-    
-void WebVideoFullscreenManagerProxy::beginScrubbing()
+
+void WebVideoFullscreenManagerProxy::endScrubbing(uint64_t contextId)
 {
-    m_page->send(Messages::WebVideoFullscreenManager::BeginScrubbing(), m_page->pageID());
+    m_page->send(Messages::WebVideoFullscreenManager::EndScrubbing(contextId), m_page->pageID());
 }
 
-void WebVideoFullscreenManagerProxy::endScrubbing()
+void WebVideoFullscreenManagerProxy::seekToTime(uint64_t contextId, double time)
 {
-    m_page->send(Messages::WebVideoFullscreenManager::EndScrubbing(), m_page->pageID());
+    m_page->send(Messages::WebVideoFullscreenManager::SeekToTime(contextId, time), m_page->pageID());
 }
 
-void WebVideoFullscreenManagerProxy::seekToTime(double time)
+void WebVideoFullscreenManagerProxy::fastSeek(uint64_t contextId, double time)
 {
-    m_page->send(Messages::WebVideoFullscreenManager::SeekToTime(time), m_page->pageID());
+    m_page->send(Messages::WebVideoFullscreenManager::FastSeek(contextId, time), m_page->pageID());
 }
 
-void WebVideoFullscreenManagerProxy::fastSeek(double time)
+void WebVideoFullscreenManagerProxy::beginScanningForward(uint64_t contextId)
 {
-    m_page->send(Messages::WebVideoFullscreenManager::FastSeek(time), m_page->pageID());
+    m_page->send(Messages::WebVideoFullscreenManager::BeginScanningForward(contextId), m_page->pageID());
 }
 
-void WebVideoFullscreenManagerProxy::beginScanningForward()
+void WebVideoFullscreenManagerProxy::beginScanningBackward(uint64_t contextId)
 {
-    m_page->send(Messages::WebVideoFullscreenManager::BeginScanningForward(), m_page->pageID());
+    m_page->send(Messages::WebVideoFullscreenManager::BeginScanningBackward(contextId), m_page->pageID());
 }
 
-void WebVideoFullscreenManagerProxy::beginScanningBackward()
+void WebVideoFullscreenManagerProxy::endScanning(uint64_t contextId)
 {
-    m_page->send(Messages::WebVideoFullscreenManager::BeginScanningBackward(), m_page->pageID());
+    m_page->send(Messages::WebVideoFullscreenManager::EndScanning(contextId), m_page->pageID());
 }
 
-void WebVideoFullscreenManagerProxy::endScanning()
+void WebVideoFullscreenManagerProxy::requestExitFullscreen(uint64_t contextId)
 {
-    m_page->send(Messages::WebVideoFullscreenManager::EndScanning(), m_page->pageID());
+    m_page->send(Messages::WebVideoFullscreenManager::RequestExitFullscreen(contextId), m_page->pageID());
 }
 
-FloatRect WebVideoFullscreenManagerProxy::videoLayerFrame() const
+void WebVideoFullscreenManagerProxy::didSetupFullscreen(uint64_t contextId)
 {
-    return m_videoLayerFrame;
+    m_page->send(Messages::WebVideoFullscreenManager::DidSetupFullscreen(contextId), m_page->pageID());
 }
 
-void WebVideoFullscreenManagerProxy::setVideoLayerFrame(WebCore::FloatRect frame)
+void WebVideoFullscreenManagerProxy::didExitFullscreen(uint64_t contextId)
+{
+    m_page->send(Messages::WebVideoFullscreenManager::DidExitFullscreen(contextId), m_page->pageID());
+    m_page->didExitFullscreen();
+}
+
+void WebVideoFullscreenManagerProxy::didEnterFullscreen(uint64_t contextId)
+{
+    m_page->send(Messages::WebVideoFullscreenManager::DidEnterFullscreen(contextId), m_page->pageID());
+    m_page->didEnterFullscreen();
+}
+
+void WebVideoFullscreenManagerProxy::didCleanupFullscreen(uint64_t contextId)
+{
+    auto& model = ensureModel(contextId);
+
+    [CATransaction flush];
+    [model.layerHost() removeFromSuperlayer];
+    model.setLayerHost(nullptr);
+    m_page->send(Messages::WebVideoFullscreenManager::DidCleanupFullscreen(contextId), m_page->pageID());
+
+    m_contextMap.remove(contextId);
+}
+
+void WebVideoFullscreenManagerProxy::setVideoLayerFrame(uint64_t contextId, WebCore::FloatRect frame)
 {
-    m_videoLayerFrame = frame;
     @autoreleasepool {
 #if __IPHONE_OS_VERSION_MIN_REQUIRED > 90000
         BKSAnimationFenceHandle* synchronizationFence = [UIWindow _synchronizedDrawingFence];
@@ -238,30 +523,36 @@ void WebVideoFullscreenManagerProxy::setVideoLayerFrame(WebCore::FloatRect frame
         mach_port_name_t fencePort = [UIWindow _synchronizeDrawingAcrossProcesses];
 #endif
 
-        m_page->send(Messages::WebVideoFullscreenManager::SetVideoLayerFrameFenced(frame, IPC::Attachment(fencePort, MACH_MSG_TYPE_MOVE_SEND)), m_page->pageID());
+        m_page->send(Messages::WebVideoFullscreenManager::SetVideoLayerFrameFenced(contextId, frame, IPC::Attachment(fencePort, MACH_MSG_TYPE_MOVE_SEND)), m_page->pageID());
     }
 }
 
-WebCore::WebVideoFullscreenModel::VideoGravity WebVideoFullscreenManagerProxy::videoLayerGravity() const
+void WebVideoFullscreenManagerProxy::setVideoLayerGravity(uint64_t contextId, WebCore::WebVideoFullscreenModel::VideoGravity gravity)
 {
-    return m_videoLayerGravity;
+    m_page->send(Messages::WebVideoFullscreenManager::SetVideoLayerGravityEnum(contextId, (unsigned)gravity), m_page->pageID());
 }
 
-void WebVideoFullscreenManagerProxy::setVideoLayerGravity(WebCore::WebVideoFullscreenModel::VideoGravity gravity)
+void WebVideoFullscreenManagerProxy::selectAudioMediaOption(uint64_t contextId, uint64_t index)
 {
-    m_videoLayerGravity = gravity;
-    m_page->send(Messages::WebVideoFullscreenManager::SetVideoLayerGravityEnum((unsigned)gravity), m_page->pageID());
+    m_page->send(Messages::WebVideoFullscreenManager::SelectAudioMediaOption(contextId, index), m_page->pageID());
 }
-    
-void WebVideoFullscreenManagerProxy::selectAudioMediaOption(uint64_t index)
+
+void WebVideoFullscreenManagerProxy::selectLegibleMediaOption(uint64_t contextId, uint64_t index)
 {
-    m_page->send(Messages::WebVideoFullscreenManager::SelectAudioMediaOption(index), m_page->pageID());
+    m_page->send(Messages::WebVideoFullscreenManager::SelectLegibleMediaOption(contextId, index), m_page->pageID());
 }
-    
-void WebVideoFullscreenManagerProxy::selectLegibleMediaOption(uint64_t index)
+
+void WebVideoFullscreenManagerProxy::fullscreenModeChanged(uint64_t contextId, WebCore::HTMLMediaElement::VideoFullscreenMode mode)
+{
+    m_page->send(Messages::WebVideoFullscreenManager::FullscreenModeChanged(contextId, mode), m_page->pageID());
+}
+
+void WebVideoFullscreenManagerProxy::fullscreenMayReturnToInline(uint64_t contextId)
 {
-    m_page->send(Messages::WebVideoFullscreenManager::SelectLegibleMediaOption(index), m_page->pageID());
+    bool isViewVisible = m_page->isViewVisible();
+    m_page->send(Messages::WebVideoFullscreenManager::FullscreenMayReturnToInline(contextId, isViewVisible), m_page->pageID());
 }
+
 #endif
 
 } // namespace WebKit
index d13e622..6ac36b9 100644 (file)
@@ -33,6 +33,7 @@
 #include <WebCore/PlatformCALayer.h>
 #include <WebCore/WebVideoFullscreenInterface.h>
 #include <WebCore/WebVideoFullscreenModelVideoElement.h>
+#include <wtf/HashMap.h>
 #include <wtf/RefCounted.h>
 #include <wtf/RefPtr.h>
 
@@ -51,53 +52,120 @@ namespace WebKit {
 
 class LayerHostingContext;
 class WebPage;
+class WebVideoFullscreenManager;
 
-class WebVideoFullscreenManager : public WebCore::WebVideoFullscreenModelVideoElement, public WebCore::WebVideoFullscreenInterface, private IPC::MessageReceiver {
+class WebVideoFullscreenInterfaceContext : public RefCounted<WebVideoFullscreenInterfaceContext>, public WebCore::WebVideoFullscreenInterface {
+public:
+    static Ref<WebVideoFullscreenInterfaceContext> create(WebVideoFullscreenManager& manager, uint64_t contextId)
+    {
+        return adoptRef(*new WebVideoFullscreenInterfaceContext(manager, contextId));
+    }
+    virtual ~WebVideoFullscreenInterfaceContext();
+
+    void invalidate() { m_manager = nullptr; }
+
+    LayerHostingContext* layerHostingContext() { return m_layerHostingContext.get(); }
+    void setLayerHostingContext(std::unique_ptr<LayerHostingContext>&&);
+
+    bool isAnimating() const { return m_isAnimating; }
+    void setIsAnimating(bool flag) { m_isAnimating = flag; }
+
+    bool targetIsFullscreen() const { return m_targetIsFullscreen; }
+    void setTargetIsFullscreen(bool flag) { m_targetIsFullscreen = flag; }
+
+    WebCore::HTMLMediaElement::VideoFullscreenMode fullscreenMode() const { return m_fullscreenMode; }
+    void setFullscreenMode(WebCore::HTMLMediaElement::VideoFullscreenMode mode) { m_fullscreenMode = mode; }
+
+    bool isFullscreen() const { return m_isFullscreen; }
+    void setIsFullscreen(bool flag) { m_isFullscreen = flag; }
+
+private:
+    // WebVideoFullscreenInterface
+    virtual void resetMediaState() override;
+    virtual void setDuration(double) override;
+    virtual void setCurrentTime(double currentTime, double anchorTime) override;
+    virtual void setBufferedTime(double) override;
+    virtual void setRate(bool isPlaying, float playbackRate) override;
+    virtual void setVideoDimensions(bool hasVideo, float width, float height) override;
+    virtual void setSeekableRanges(const WebCore::TimeRanges&) override;
+    virtual void setCanPlayFastReverse(bool value) override;
+    virtual void setAudioMediaSelectionOptions(const Vector<WTF::String>& options, uint64_t selectedIndex) override;
+    virtual void setLegibleMediaSelectionOptions(const Vector<WTF::String>& options, uint64_t selectedIndex) override;
+    virtual void setExternalPlayback(bool enabled, ExternalPlaybackTargetType, WTF::String localizedDeviceName) override;
+
+    WebVideoFullscreenInterfaceContext(WebVideoFullscreenManager&, uint64_t contextId);
+
+    WebVideoFullscreenManager* m_manager;
+    uint64_t m_contextId;
+    std::unique_ptr<LayerHostingContext> m_layerHostingContext;
+    bool m_isAnimating { false };
+    bool m_targetIsFullscreen { false };
+    WebCore::HTMLMediaElement::VideoFullscreenMode m_fullscreenMode { WebCore::HTMLMediaElement::VideoFullscreenModeNone };
+    bool m_isFullscreen { false };
+};
+
+class WebVideoFullscreenManager : public RefCounted<WebVideoFullscreenManager>, private IPC::MessageReceiver {
 public:
     static PassRefPtr<WebVideoFullscreenManager> create(PassRefPtr<WebPage>);
     virtual ~WebVideoFullscreenManager();
     
     void didReceiveMessage(IPC::Connection&, IPC::MessageDecoder&) override;
-    
+
+    // Interface to ChromeClient
     bool supportsVideoFullscreen() const;
     void enterVideoFullscreenForVideoElement(WebCore::HTMLVideoElement&, WebCore::HTMLMediaElement::VideoFullscreenMode);
     void exitVideoFullscreenForVideoElement(WebCore::HTMLVideoElement&);
     
 protected:
+    friend class WebVideoFullscreenInterfaceContext;
+
     explicit WebVideoFullscreenManager(PassRefPtr<WebPage>);
-    virtual bool operator==(const EventListener& rhs) override { return static_cast<WebCore::EventListener*>(this) == &rhs; }
-    
-    // FullscreenInterface
-    virtual void resetMediaState() override;
-    virtual void setDuration(double) override;
-    virtual void setCurrentTime(double currentTime, double anchorTime) override;
-    virtual void setBufferedTime(double bufferedTime) override;
-    virtual void setRate(bool isPlaying, float playbackRate) override;
-    virtual void setVideoDimensions(bool hasVideo, float width, float height) override;
-    virtual void setSeekableRanges(const WebCore::TimeRanges&) override;
-    virtual void setCanPlayFastReverse(bool value) override;
 
-    virtual void setAudioMediaSelectionOptions(const Vector<String>& options, uint64_t selectedIndex) override;
-    virtual void setLegibleMediaSelectionOptions(const Vector<String>& options, uint64_t selectedIndex) override;
-    virtual void setExternalPlayback(bool enabled, WebVideoFullscreenInterface::ExternalPlaybackTargetType, String localizedDeviceName) override;
-
-    // additional incoming
-    virtual void didSetupFullscreen();
-    virtual void didEnterFullscreen();
-    virtual void didExitFullscreen();
-    virtual void didCleanupFullscreen();
-    virtual void setVideoLayerGravityEnum(unsigned);
-    virtual void fullscreenMayReturnToInline(bool isPageVisible);
-    void setVideoLayerFrameFenced(WebCore::FloatRect bounds, IPC::Attachment fencePort);
+    typedef std::tuple<RefPtr<WebCore::WebVideoFullscreenModelVideoElement>, RefPtr<WebVideoFullscreenInterfaceContext>> ModelInterfaceTuple;
+    ModelInterfaceTuple createModelAndInterface(uint64_t contextId);
+    ModelInterfaceTuple& ensureModelAndInterface(uint64_t contextId);
+    WebCore::WebVideoFullscreenModelVideoElement& ensureModel(uint64_t contextId);
+    WebVideoFullscreenInterfaceContext& ensureInterface(uint64_t contextId);
+
+    // Interface to WebVideoFullscreenInterfaceContext
+    void resetMediaState(uint64_t contextId);
+    void setDuration(uint64_t contextId, double);
+    void setCurrentTime(uint64_t contextId, double currentTime, double anchorTime);
+    void setBufferedTime(uint64_t contextId, double bufferedTime);
+    void setRate(uint64_t contextId, bool isPlaying, float playbackRate);
+    void setVideoDimensions(uint64_t contextId, bool hasVideo, float width, float height);
+    void setSeekableRanges(uint64_t contextId, const WebCore::TimeRanges&);
+    void setCanPlayFastReverse(uint64_t contextId, bool value);
+    void setAudioMediaSelectionOptions(uint64_t contextId, const Vector<String>& options, uint64_t selectedIndex);
+    void setLegibleMediaSelectionOptions(uint64_t contextId, const Vector<String>& options, uint64_t selectedIndex);
+    void setExternalPlayback(uint64_t contextId, bool enabled, WebCore::WebVideoFullscreenInterface::ExternalPlaybackTargetType, String localizedDeviceName);
+
+    // Messages from WebVideoFullscreenManagerProxy
+    void play(uint64_t contextId);
+    void pause(uint64_t contextId);
+    void togglePlayState(uint64_t contextId);
+    void beginScrubbing(uint64_t contextId);
+    void endScrubbing(uint64_t contextId);
+    void seekToTime(uint64_t contextId, double time);
+    void fastSeek(uint64_t contextId, double time);
+    void beginScanningForward(uint64_t contextId);
+    void beginScanningBackward(uint64_t contextId);
+    void endScanning(uint64_t contextId);
+    void requestExitFullscreen(uint64_t contextId);
+    void didSetupFullscreen(uint64_t contextId);
+    void didExitFullscreen(uint64_t contextId);
+    void didEnterFullscreen(uint64_t contextId);
+    void didCleanupFullscreen(uint64_t contextId);
+    void setVideoLayerFrameFenced(uint64_t contextId, WebCore::FloatRect bounds, IPC::Attachment fencePort);
+    void setVideoLayerGravityEnum(uint64_t contextId, unsigned gravity);
+    void selectAudioMediaOption(uint64_t contextId, uint64_t index);
+    void selectLegibleMediaOption(uint64_t contextId, uint64_t index);
+    void fullscreenModeChanged(uint64_t contextId, WebCore::HTMLMediaElement::VideoFullscreenMode);
+    void fullscreenMayReturnToInline(uint64_t contextId, bool isPageVisible);
     
     WebPage* m_page;
-    RefPtr<WebCore::HTMLVideoElement> m_videoElement;
-    std::unique_ptr<LayerHostingContext> m_layerHostingContext;
-    
-    bool m_isAnimating;
-    bool m_targetIsFullscreen;
-    WebCore::HTMLMediaElement::VideoFullscreenMode m_fullscreenMode;
-    bool m_isFullscreen;
+    HashMap<WebCore::HTMLVideoElement*, uint64_t> m_videoElements;
+    HashMap<uint64_t, ModelInterfaceTuple> m_contextMap;
 };
     
 } // namespace WebKit
index d3c68a3..013da3e 100644 (file)
 
 #if PLATFORM(IOS)
 messages -> WebVideoFullscreenManager {
-    Play()
-    Pause()
-    TogglePlayState()
-    BeginScrubbing()
-    EndScrubbing()
-    SeekToTime(double time)
-    FastSeek(double time)
-    BeginScanningForward()
-    BeginScanningBackward()
-    EndScanning()
-    RequestExitFullscreen()
-    DidSetupFullscreen()
-    DidExitFullscreen()
-    DidEnterFullscreen()
-    DidCleanupFullscreen()
-    SetVideoLayerFrameFenced(WebCore::FloatRect bounds, IPC::Attachment fencePort)
-    SetVideoLayerGravityEnum(unsigned gravity)
-    SelectAudioMediaOption(uint64_t index)
-    SelectLegibleMediaOption(uint64_t index)
-    fullscreenModeChanged(WebCore::HTMLMediaElement::VideoFullscreenMode videoFullscreenMode)
-    FullscreenMayReturnToInline(bool isPageVisible)
+    Play(uint64_t contextId)
+    Pause(uint64_t contextId)
+    TogglePlayState(uint64_t contextId)
+    BeginScrubbing(uint64_t contextId)
+    EndScrubbing(uint64_t contextId)
+    SeekToTime(uint64_t contextId, double time)
+    FastSeek(uint64_t contextId, double time)
+    BeginScanningForward(uint64_t contextId)
+    BeginScanningBackward(uint64_t contextId)
+    EndScanning(uint64_t contextId)
+    RequestExitFullscreen(uint64_t contextId)
+    DidSetupFullscreen(uint64_t contextId)
+    DidExitFullscreen(uint64_t contextId)
+    DidEnterFullscreen(uint64_t contextId)
+    DidCleanupFullscreen(uint64_t contextId)
+    SetVideoLayerFrameFenced(uint64_t contextId, WebCore::FloatRect bounds, IPC::Attachment fencePort)
+    SetVideoLayerGravityEnum(uint64_t contextId, unsigned gravity)
+    SelectAudioMediaOption(uint64_t contextId, uint64_t index)
+    SelectLegibleMediaOption(uint64_t contextId, uint64_t index)
+    FullscreenModeChanged(uint64_t contextId, WebCore::HTMLMediaElement::VideoFullscreenMode videoFullscreenMode)
+    FullscreenMayReturnToInline(uint64_t contextId, bool isPageVisible)
 }
 #endif
index 45a3e29..9aaefc8 100644 (file)
@@ -60,6 +60,97 @@ static IntRect clientRectForElement(HTMLElement* element)
     return element->clientRect();
 }
 
+static uint64_t nextContextId()
+{
+    static uint64_t contextId = 0;
+    return ++contextId;
+}
+
+#pragma mark - WebVideoFullscreenInterfaceContext
+
+WebVideoFullscreenInterfaceContext::WebVideoFullscreenInterfaceContext(WebVideoFullscreenManager& manager, uint64_t contextId)
+    : m_manager(&manager)
+    , m_contextId(contextId)
+{
+}
+
+WebVideoFullscreenInterfaceContext::~WebVideoFullscreenInterfaceContext()
+{
+}
+
+void WebVideoFullscreenInterfaceContext::setLayerHostingContext(std::unique_ptr<LayerHostingContext>&& context)
+{
+    m_layerHostingContext = WTF::move(context);
+}
+
+void WebVideoFullscreenInterfaceContext::resetMediaState()
+{
+    if (m_manager)
+        m_manager->resetMediaState(m_contextId);
+}
+
+void WebVideoFullscreenInterfaceContext::setDuration(double duration)
+{
+    if (m_manager)
+        m_manager->setDuration(m_contextId, duration);
+}
+
+void WebVideoFullscreenInterfaceContext::setCurrentTime(double currentTime, double anchorTime)
+{
+    if (m_manager)
+        m_manager->setCurrentTime(m_contextId, currentTime, anchorTime);
+}
+
+void WebVideoFullscreenInterfaceContext::setBufferedTime(double bufferedTime)
+{
+    if (m_manager)
+        m_manager->setBufferedTime(m_contextId, bufferedTime);
+}
+
+void WebVideoFullscreenInterfaceContext::setRate(bool isPlaying, float playbackRate)
+{
+    if (m_manager)
+        m_manager->setRate(m_contextId, isPlaying, playbackRate);
+}
+
+void WebVideoFullscreenInterfaceContext::setVideoDimensions(bool hasVideo, float width, float height)
+{
+    if (m_manager)
+        m_manager->setVideoDimensions(m_contextId, hasVideo, width, height);
+}
+
+void WebVideoFullscreenInterfaceContext::setSeekableRanges(const WebCore::TimeRanges& ranges)
+{
+    if (m_manager)
+        m_manager->setSeekableRanges(m_contextId, ranges);
+}
+
+void WebVideoFullscreenInterfaceContext::setCanPlayFastReverse(bool value)
+{
+    if (m_manager)
+        m_manager->setCanPlayFastReverse(m_contextId, value);
+}
+
+void WebVideoFullscreenInterfaceContext::setAudioMediaSelectionOptions(const Vector<WTF::String>& options, uint64_t selectedIndex)
+{
+    if (m_manager)
+        m_manager->setAudioMediaSelectionOptions(m_contextId, options, selectedIndex);
+}
+
+void WebVideoFullscreenInterfaceContext::setLegibleMediaSelectionOptions(const Vector<WTF::String>& options, uint64_t selectedIndex)
+{
+    if (m_manager)
+        m_manager->setLegibleMediaSelectionOptions(m_contextId, options, selectedIndex);
+}
+
+void WebVideoFullscreenInterfaceContext::setExternalPlayback(bool enabled, ExternalPlaybackTargetType type, WTF::String localizedDeviceName)
+{
+    if (m_manager)
+        m_manager->setExternalPlayback(m_contextId, enabled, type, localizedDeviceName);
+}
+
+#pragma mark - WebVideoFullscreenManager
+
 PassRefPtr<WebVideoFullscreenManager> WebVideoFullscreenManager::create(PassRefPtr<WebPage> page)
 {
     return adoptRef(new WebVideoFullscreenManager(page));
@@ -67,20 +158,60 @@ PassRefPtr<WebVideoFullscreenManager> WebVideoFullscreenManager::create(PassRefP
 
 WebVideoFullscreenManager::WebVideoFullscreenManager(PassRefPtr<WebPage> page)
     : m_page(page.get())
-    , m_isAnimating(false)
-    , m_targetIsFullscreen(false)
-    , m_fullscreenMode(HTMLMediaElement::VideoFullscreenModeNone)
-    , m_isFullscreen(false)
 {
-    setWebVideoFullscreenInterface(this);
     WebProcess::singleton().addMessageReceiver(Messages::WebVideoFullscreenManager::messageReceiverName(), page->pageID(), *this);
 }
 
 WebVideoFullscreenManager::~WebVideoFullscreenManager()
 {
+    for (auto& tuple : m_contextMap.values()) {
+        RefPtr<WebVideoFullscreenModelVideoElement> model;
+        RefPtr<WebVideoFullscreenInterfaceContext> interface;
+        std::tie(model, interface) = tuple;
+
+        model->setWebVideoFullscreenInterface(nullptr);
+        model->setVideoElement(nullptr);
+
+        interface->invalidate();
+    }
+
+    m_contextMap.clear();
+    m_videoElements.clear();
+
     WebProcess::singleton().removeMessageReceiver(Messages::WebVideoFullscreenManager::messageReceiverName(), m_page->pageID());
 }
 
+WebVideoFullscreenManager::ModelInterfaceTuple WebVideoFullscreenManager::createModelAndInterface(uint64_t contextId)
+{
+    RefPtr<WebVideoFullscreenModelVideoElement> model = WebVideoFullscreenModelVideoElement::create();
+    RefPtr<WebVideoFullscreenInterfaceContext> interface = WebVideoFullscreenInterfaceContext::create(*this, contextId);
+
+    interface->setLayerHostingContext(LayerHostingContext::createForExternalHostingProcess());
+    model->setWebVideoFullscreenInterface(interface.get());
+
+    return std::make_tuple(WTF::move(model), WTF::move(interface));
+}
+
+WebVideoFullscreenManager::ModelInterfaceTuple& WebVideoFullscreenManager::ensureModelAndInterface(uint64_t contextId)
+{
+    auto addResult = m_contextMap.add(contextId, ModelInterfaceTuple());
+    if (addResult.isNewEntry)
+        addResult.iterator->value = createModelAndInterface(contextId);
+    return addResult.iterator->value;
+}
+
+WebCore::WebVideoFullscreenModelVideoElement& WebVideoFullscreenManager::ensureModel(uint64_t contextId)
+{
+    return *std::get<0>(ensureModelAndInterface(contextId));
+}
+
+WebVideoFullscreenInterfaceContext& WebVideoFullscreenManager::ensureInterface(uint64_t contextId)
+{
+    return *std::get<1>(ensureModelAndInterface(contextId));
+}
+
+#pragma mark Interface to ChromeClient:
+
 bool WebVideoFullscreenManager::supportsVideoFullscreen() const
 {
     return Settings::avKitEnabled();
@@ -90,66 +221,79 @@ void WebVideoFullscreenManager::enterVideoFullscreenForVideoElement(HTMLVideoEle
 {
     ASSERT(mode != HTMLMediaElement::VideoFullscreenModeNone);
 
-    m_videoElement = &videoElement;
+    uint64_t contextId;
 
-    m_targetIsFullscreen = true;
-    m_fullscreenMode = mode;
+    auto addResult = m_videoElements.add(&videoElement, 0);
+    if (addResult.isNewEntry)
+        addResult.iterator->value = nextContextId();
+    contextId = addResult.iterator->value;
 
-    if (m_isAnimating)
-        return;
+    RefPtr<WebVideoFullscreenModelVideoElement> model;
+    RefPtr<WebVideoFullscreenInterfaceContext> interface;
+    std::tie(model, interface) = ensureModelAndInterface(contextId);
 
-    m_isAnimating = true;
-    setVideoElement(&videoElement);
+    interface->setTargetIsFullscreen(true);
+    interface->setFullscreenMode(mode);
+    model->setVideoElement(&videoElement);
 
-    m_layerHostingContext = LayerHostingContext::createForExternalHostingProcess();
-    bool allowOptimizedFullscreen = m_videoElement->mediaSession().allowsAlternateFullscreen(*m_videoElement.get());
+    if (interface->isAnimating())
+        return;
+    interface->setIsAnimating(true);
+
+    bool allowOptimizedFullscreen = videoElement.mediaSession().allowsAlternateFullscreen(videoElement);
     
-    m_page->send(Messages::WebVideoFullscreenManagerProxy::SetupFullscreenWithID(m_layerHostingContext->contextID(), clientRectForElement(&videoElement), m_page->deviceScaleFactor(), m_fullscreenMode, allowOptimizedFullscreen), m_page->pageID());
+    m_page->send(Messages::WebVideoFullscreenManagerProxy::SetupFullscreenWithID(contextId, interface->layerHostingContext()->contextID(), clientRectForElement(&videoElement), m_page->deviceScaleFactor(), interface->fullscreenMode(), allowOptimizedFullscreen), m_page->pageID());
 }
 
-void WebVideoFullscreenManager::exitVideoFullscreenForVideoElement(WebCore::HTMLVideoElement&)
+void WebVideoFullscreenManager::exitVideoFullscreenForVideoElement(WebCore::HTMLVideoElement& videoElement)
 {
-    RefPtr<HTMLVideoElement> videoElement = m_videoElement.release();
-    m_targetIsFullscreen = false;
+    ASSERT(m_videoElements.contains(&videoElement));
+
+    uint64_t contextId = m_videoElements.get(&videoElement);
+    auto& interface = ensureInterface(contextId);
 
-    if (m_isAnimating)
+    interface.setTargetIsFullscreen(false);
+
+    if (interface.isAnimating())
         return;
 
-    m_isAnimating = true;
-    m_page->send(Messages::WebVideoFullscreenManagerProxy::ExitFullscreen(clientRectForElement(videoElement.get())), m_page->pageID());
+    interface.setIsAnimating(true);
+    m_page->send(Messages::WebVideoFullscreenManagerProxy::ExitFullscreen(contextId, clientRectForElement(&videoElement)), m_page->pageID());
 }
 
-void WebVideoFullscreenManager::resetMediaState()
+#pragma mark Interface to WebVideoFullscreenInterfaceContext:
+
+void WebVideoFullscreenManager::resetMediaState(uint64_t contextId)
 {
-    m_page->send(Messages::WebVideoFullscreenManagerProxy::ResetMediaState(), m_page->pageID());
+    m_page->send(Messages::WebVideoFullscreenManagerProxy::ResetMediaState(contextId), m_page->pageID());
 }
     
-void WebVideoFullscreenManager::setDuration(double duration)
+void WebVideoFullscreenManager::setDuration(uint64_t contextId, double duration)
 {
-    m_page->send(Messages::WebVideoFullscreenManagerProxy::SetDuration(duration), m_page->pageID());
+    m_page->send(Messages::WebVideoFullscreenManagerProxy::SetDuration(contextId, duration), m_page->pageID());
 }
 
-void WebVideoFullscreenManager::setCurrentTime(double currentTime, double anchorTime)
+void WebVideoFullscreenManager::setCurrentTime(uint64_t contextId, double currentTime, double anchorTime)
 {
-    m_page->send(Messages::WebVideoFullscreenManagerProxy::SetCurrentTime(currentTime, anchorTime), m_page->pageID());
+    m_page->send(Messages::WebVideoFullscreenManagerProxy::SetCurrentTime(contextId, currentTime, anchorTime), m_page->pageID());
 }
 
-void WebVideoFullscreenManager::setBufferedTime(double bufferedTime)
+void WebVideoFullscreenManager::setBufferedTime(uint64_t contextId, double bufferedTime)
 {
-    m_page->send(Messages::WebVideoFullscreenManagerProxy::SetBufferedTime(bufferedTime), m_page->pageID());
+    m_page->send(Messages::WebVideoFullscreenManagerProxy::SetBufferedTime(contextId, bufferedTime), m_page->pageID());
 }
 
-void WebVideoFullscreenManager::setRate(bool isPlaying, float playbackRate)
+void WebVideoFullscreenManager::setRate(uint64_t contextId, bool isPlaying, float playbackRate)
 {
-    m_page->send(Messages::WebVideoFullscreenManagerProxy::SetRate(isPlaying, playbackRate), m_page->pageID());
+    m_page->send(Messages::WebVideoFullscreenManagerProxy::SetRate(contextId, isPlaying, playbackRate), m_page->pageID());
 }
 
-void WebVideoFullscreenManager::setVideoDimensions(bool hasVideo, float width, float height)
+void WebVideoFullscreenManager::setVideoDimensions(uint64_t contextId, bool hasVideo, float width, float height)
 {
-    m_page->send(Messages::WebVideoFullscreenManagerProxy::SetVideoDimensions(hasVideo, width, height), m_page->pageID());
+    m_page->send(Messages::WebVideoFullscreenManagerProxy::SetVideoDimensions(contextId, hasVideo, width, height), m_page->pageID());
 }
     
-void WebVideoFullscreenManager::setSeekableRanges(const WebCore::TimeRanges& timeRanges)
+void WebVideoFullscreenManager::setSeekableRanges(uint64_t contextId, const WebCore::TimeRanges& timeRanges)
 {
     Vector<std::pair<double, double>> rangesVector;
     
@@ -160,30 +304,104 @@ void WebVideoFullscreenManager::setSeekableRanges(const WebCore::TimeRanges& tim
         rangesVector.append(std::pair<double,double>(start, end));
     }
 
-    m_page->send(Messages::WebVideoFullscreenManagerProxy::SetSeekableRangesVector(WTF::move(rangesVector)), m_page->pageID());
+    m_page->send(Messages::WebVideoFullscreenManagerProxy::SetSeekableRangesVector(contextId, WTF::move(rangesVector)), m_page->pageID());
 }
 
-void WebVideoFullscreenManager::setCanPlayFastReverse(bool value)
+void WebVideoFullscreenManager::setCanPlayFastReverse(uint64_t contextId, bool value)
 {
-    m_page->send(Messages::WebVideoFullscreenManagerProxy::SetCanPlayFastReverse(value), m_page->pageID());
+    m_page->send(Messages::WebVideoFullscreenManagerProxy::SetCanPlayFastReverse(contextId, value), m_page->pageID());
 }
 
-void WebVideoFullscreenManager::setAudioMediaSelectionOptions(const Vector<String>& options, uint64_t selectedIndex)
+void WebVideoFullscreenManager::setAudioMediaSelectionOptions(uint64_t contextId, const Vector<String>& options, uint64_t selectedIndex)
 {
-    m_page->send(Messages::WebVideoFullscreenManagerProxy::SetAudioMediaSelectionOptions(options, selectedIndex), m_page->pageID());
+    m_page->send(Messages::WebVideoFullscreenManagerProxy::SetAudioMediaSelectionOptions(contextId, options, selectedIndex), m_page->pageID());
 }
 
-void WebVideoFullscreenManager::setLegibleMediaSelectionOptions(const Vector<String>& options, uint64_t selectedIndex)
+void WebVideoFullscreenManager::setLegibleMediaSelectionOptions(uint64_t contextId, const Vector<String>& options, uint64_t selectedIndex)
 {
-    m_page->send(Messages::WebVideoFullscreenManagerProxy::SetLegibleMediaSelectionOptions(options, selectedIndex), m_page->pageID());
+    m_page->send(Messages::WebVideoFullscreenManagerProxy::SetLegibleMediaSelectionOptions(contextId, options, selectedIndex), m_page->pageID());
 }
 
-void WebVideoFullscreenManager::setExternalPlayback(bool enabled, WebVideoFullscreenInterface::ExternalPlaybackTargetType targetType, String localizedDeviceName)
+void WebVideoFullscreenManager::setExternalPlayback(uint64_t contextId, bool enabled, WebVideoFullscreenInterface::ExternalPlaybackTargetType targetType, String localizedDeviceName)
 {
-    m_page->send(Messages::WebVideoFullscreenManagerProxy::SetExternalPlaybackProperties(enabled, static_cast<uint32_t>(targetType), localizedDeviceName), m_page->pageID());
+    m_page->send(Messages::WebVideoFullscreenManagerProxy::SetExternalPlaybackProperties(contextId, enabled, static_cast<uint32_t>(targetType), localizedDeviceName), m_page->pageID());
 }
-    
-void WebVideoFullscreenManager::didSetupFullscreen()
+
+#pragma mark Messages from WebVideoFullscreenManagerProxy:
+
+void WebVideoFullscreenManager::play(uint64_t contextId)
+{
+    ensureModel(contextId).play();
+}
+
+void WebVideoFullscreenManager::pause(uint64_t contextId)
+{
+    ensureModel(contextId).pause();
+}
+
+void WebVideoFullscreenManager::togglePlayState(uint64_t contextId)
+{
+    ensureModel(contextId).togglePlayState();
+}
+
+void WebVideoFullscreenManager::beginScrubbing(uint64_t contextId)
+{
+    ensureModel(contextId).beginScrubbing();
+}
+
+void WebVideoFullscreenManager::endScrubbing(uint64_t contextId)
+{
+    ensureModel(contextId).endScrubbing();
+}
+
+void WebVideoFullscreenManager::seekToTime(uint64_t contextId, double time)
+{
+    ensureModel(contextId).seekToTime(time);
+}
+
+void WebVideoFullscreenManager::fastSeek(uint64_t contextId, double time)
+{
+    ensureModel(contextId).fastSeek(time);
+}
+
+void WebVideoFullscreenManager::beginScanningForward(uint64_t contextId)
+{
+    ensureModel(contextId).beginScanningForward();
+}
+
+void WebVideoFullscreenManager::beginScanningBackward(uint64_t contextId)
+{
+    ensureModel(contextId).beginScanningBackward();
+}
+
+void WebVideoFullscreenManager::endScanning(uint64_t contextId)
+{
+    ensureModel(contextId).endScanning();
+}
+
+void WebVideoFullscreenManager::requestExitFullscreen(uint64_t contextId)
+{
+    ensureModel(contextId).requestExitFullscreen();
+}
+
+void WebVideoFullscreenManager::selectAudioMediaOption(uint64_t contextId, uint64_t index)
+{
+    ensureModel(contextId).selectAudioMediaOption(index);
+}
+
+void WebVideoFullscreenManager::selectLegibleMediaOption(uint64_t contextId, uint64_t index)
+{
+    ensureModel(contextId).selectLegibleMediaOption(index);
+}
+
+void WebVideoFullscreenManager::fullscreenModeChanged(uint64_t contextId, WebCore::HTMLMediaElement::VideoFullscreenMode videoFullscreenMode)
+{
+    ensureModel(contextId).fullscreenModeChanged(videoFullscreenMode);
+}
+
+#pragma mark Messages from WebVideoFullscreenManager:
+
+void WebVideoFullscreenManager::didSetupFullscreen(uint64_t contextId)
 {
     PlatformLayer* videoLayer = [CALayer layer];
 #ifndef NDEBUG
@@ -200,83 +418,118 @@ void WebVideoFullscreenManager::didSetupFullscreen()
     // This scale factor is inverted in the hosting process.
     float hostingScaleFactor = m_page->deviceScaleFactor();
     [videoLayer setTransform:CATransform3DMakeScale(hostingScaleFactor, hostingScaleFactor, 1)];
-    m_layerHostingContext->setRootLayer(videoLayer);
 
-    setVideoFullscreenLayer(videoLayer);
+    RefPtr<WebVideoFullscreenModelVideoElement> model;
+    RefPtr<WebVideoFullscreenInterfaceContext> interface;
+    std::tie(model, interface) = ensureModelAndInterface(contextId);
+
+    interface->layerHostingContext()->setRootLayer(videoLayer);
+    model->setVideoFullscreenLayer(videoLayer);
+
     [CATransaction commit];
 
-    m_page->send(Messages::WebVideoFullscreenManagerProxy::EnterFullscreen(), m_page->pageID());
+    m_page->send(Messages::WebVideoFullscreenManagerProxy::EnterFullscreen(contextId), m_page->pageID());
 }
     
-void WebVideoFullscreenManager::didEnterFullscreen()
+void WebVideoFullscreenManager::didEnterFullscreen(uint64_t contextId)
 {
-    m_isAnimating = false;
-    m_isFullscreen = false;
+    RefPtr<WebVideoFullscreenModelVideoElement> model;
+    RefPtr<WebVideoFullscreenInterfaceContext> interface;
+    std::tie(model, interface) = ensureModelAndInterface(contextId);
+
+    interface->setIsAnimating(false);
+    interface->setIsFullscreen(false);
+
+    if (interface->targetIsFullscreen())
+        return;
 
-    if (m_targetIsFullscreen)
+    RefPtr<HTMLVideoElement> videoElement = model->videoElement();
+    if (!videoElement)
         return;
 
     // exit fullscreen now if it was previously requested during an animation.
-    __block RefPtr<WebVideoFullscreenModelVideoElement> protect(this);
-    WebThreadRun(^ {
-        exitVideoFullscreenForVideoElement(*m_videoElement);
-        protect.clear();
+    RefPtr<WebVideoFullscreenManager> strongThis(this);
+    WebThreadRun([strongThis, videoElement] {
+        strongThis->exitVideoFullscreenForVideoElement(*videoElement);
     });
 }
 
-void WebVideoFullscreenManager::didExitFullscreen()
+void WebVideoFullscreenManager::didExitFullscreen(uint64_t contextId)
 {
-    setVideoFullscreenLayer(nil);
-    __block RefPtr<WebVideoFullscreenModelVideoElement> protect(this);
+    RefPtr<WebVideoFullscreenModelVideoElement> model;
+    RefPtr<WebVideoFullscreenInterfaceContext> interface;
+    std::tie(model, interface) = ensureModelAndInterface(contextId);
+
+    model->setVideoFullscreenLayer(nil);
 
-    dispatch_async(dispatch_get_main_queue(), ^{
-        if (m_layerHostingContext) {
-            m_layerHostingContext->setRootLayer(nullptr);
-            m_layerHostingContext = nullptr;
+    RefPtr<WebVideoFullscreenManager> strongThis(this);
+    dispatch_async(dispatch_get_main_queue(), [strongThis, contextId, interface] {
+        if (interface->layerHostingContext()) {
+            interface->layerHostingContext()->setRootLayer(nullptr);
+            interface->setLayerHostingContext(nullptr);
         }
-        if (m_page)
-            m_page->send(Messages::WebVideoFullscreenManagerProxy::CleanupFullscreen(), m_page->pageID());
-        protect.clear();
+        if (strongThis->m_page)
+            strongThis->m_page->send(Messages::WebVideoFullscreenManagerProxy::CleanupFullscreen(contextId), strongThis->m_page->pageID());
     });
 }
     
-void WebVideoFullscreenManager::didCleanupFullscreen()
+void WebVideoFullscreenManager::didCleanupFullscreen(uint64_t contextId)
 {
-    m_isAnimating = false;
-    m_isFullscreen = false;
-    
-    setVideoElement(nullptr);
+    RefPtr<WebVideoFullscreenModelVideoElement> model;
+    RefPtr<WebVideoFullscreenInterfaceContext> interface;
+    std::tie(model, interface) = ensureModelAndInterface(contextId);
+
+    interface->setIsAnimating(false);
+    interface->setIsFullscreen(false);
+    HTMLMediaElement::VideoFullscreenMode mode = interface->fullscreenMode();
+
+    model->setVideoFullscreenLayer(nil);
+    RefPtr<HTMLVideoElement> videoElement = model->videoElement();
+
+    if (!interface->targetIsFullscreen()) {
+        model->setVideoElement(nullptr);
+        model->setWebVideoFullscreenInterface(nullptr);
+        interface->invalidate();
+        m_videoElements.remove(videoElement.get());
+        m_contextMap.remove(contextId);
+        return;
+    }
 
-    if (!m_targetIsFullscreen)
+    if (!videoElement)
         return;
 
-    // enter fullscreen now if it was previously requested during an animation.
-    __block RefPtr<WebVideoFullscreenModelVideoElement> protect(this);
-    WebThreadRun(^ {
-        enterVideoFullscreenForVideoElement(*m_videoElement, m_fullscreenMode);
-        protect.clear();
+    // exit fullscreen now if it was previously requested during an animation.
+    RefPtr<WebVideoFullscreenManager> strongThis(this);
+    WebThreadRun([strongThis, videoElement, mode] {
+        strongThis->enterVideoFullscreenForVideoElement(*videoElement, mode);
     });
 }
     
-void WebVideoFullscreenManager::setVideoLayerGravityEnum(unsigned gravity)
+void WebVideoFullscreenManager::setVideoLayerGravityEnum(uint64_t contextId, unsigned gravity)
 {
-    setVideoLayerGravity((WebVideoFullscreenModel::VideoGravity)gravity);
+    ensureModel(contextId).setVideoLayerGravity((WebVideoFullscreenModel::VideoGravity)gravity);
 }
     
-void WebVideoFullscreenManager::fullscreenMayReturnToInline(bool isPageVisible)
+void WebVideoFullscreenManager::fullscreenMayReturnToInline(uint64_t contextId, bool isPageVisible)
 {
+    auto& model = ensureModel(contextId);
+
     if (!isPageVisible)
-        m_videoElement->scrollIntoViewIfNotVisible(false);
-    m_page->send(Messages::WebVideoFullscreenManagerProxy::PreparedToReturnToInline(true, clientRectForElement(m_videoElement.get())), m_page->pageID());
+        model.videoElement()->scrollIntoViewIfNotVisible(false);
+    m_page->send(Messages::WebVideoFullscreenManagerProxy::PreparedToReturnToInline(contextId, true, clientRectForElement(model.videoElement())), m_page->pageID());
 }
     
-void WebVideoFullscreenManager::setVideoLayerFrameFenced(WebCore::FloatRect bounds, IPC::Attachment fencePort)
+void WebVideoFullscreenManager::setVideoLayerFrameFenced(uint64_t contextId, WebCore::FloatRect bounds, IPC::Attachment fencePort)
 {
+    RefPtr<WebVideoFullscreenModelVideoElement> model;
+    RefPtr<WebVideoFullscreenInterfaceContext> interface;
+    std::tie(model, interface) = ensureModelAndInterface(contextId);
+
     [CATransaction begin];
     [CATransaction setAnimationDuration:0];
-    if (m_layerHostingContext)
-        m_layerHostingContext->setFencePort(fencePort.port());
-    setVideoLayerFrame(bounds);
+    if (interface->layerHostingContext())
+        interface->layerHostingContext()->setFencePort(fencePort.port());
+    model->setVideoLayerFrame(bounds);
     mach_port_deallocate(mach_task_self(), fencePort.port());
     [CATransaction commit];
 }