Refactoring: eliminate raw pointer usage in Fullscreen code
authorjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 28 Sep 2018 18:39:51 +0000 (18:39 +0000)
committerjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 28 Sep 2018 18:39:51 +0000 (18:39 +0000)
https://bugs.webkit.org/show_bug.cgi?id=188747
<rdar://problem/43541164>

Reviewed by Alex Christensen.

Source/WebCore:

Two sources of raw pointers in the Fullscreen code:
- Model classes (PlaybackSessionModel and VideoFullscreenModel) aren't ref-able, so
  they are passed around as raw references.
- Observer classes (PlaybackSessionModelClient and VideoFullscreenModelClient, and
  VideoFullscreenChangeObserver) are also passed around as raw pointers, but shouldn't
  be ref-able.

Make Model classes ref-able by adding ref() and deref() which call virtual refModel and
derefModel methods, overridden by implementing subclasses. Make every concrete observer
inherit from CanMakeWeakPtr, and every registration method take WeakPtr wrappers around
the client interface.

Since every Interface class now holds a strong reference to its Model classes, and each
Model class holds a weak reference to all its clients, no explicit invalidate() method
is necessary.

Notes:

- Since the weak pointer methods need to be able to downcast to the abstract base class,
  observers need to inherit publically (rather than privately) from those base classes.
- Media element Models should compose EventListener rather than inheriting from it, since
  EventListener has its own RefCount.
- WeakPtrs can't be held in HashSets (because they change value, and therefore hash, when
  their underlying object is destroyed), so clients should be stored in a Vector instead.
- Interfaces should be given all required Refs at creation time, so that they can store
  those parameters as Refs instead of RefPtrs.

* platform/cocoa/PlaybackSessionInterface.h:
(WebCore::PlaybackSessionInterface::~PlaybackSessionInterface): Deleted.
* platform/cocoa/PlaybackSessionModel.h:
(WebCore::PlaybackSessionModel::ref):
(WebCore::PlaybackSessionModel::deref):
(WebCore::PlaybackSessionModel::~PlaybackSessionModel): Deleted.
* platform/cocoa/PlaybackSessionModelMediaElement.h:
* platform/cocoa/PlaybackSessionModelMediaElement.mm:
(WebCore::PlaybackSessionModelMediaElement::PlaybackSessionModelMediaElement):
(WebCore::PlaybackSessionModelMediaElement::~PlaybackSessionModelMediaElement):
(WebCore::PlaybackSessionModelMediaElement::setMediaElement):
(WebCore::PlaybackSessionModelMediaElement::updateForEventName):
(WebCore::PlaybackSessionModelMediaElement::addClient):
(WebCore::PlaybackSessionModelMediaElement::removeClient):
(WebCore::PlaybackSessionModelMediaElement::updateMediaSelectionOptions):
(WebCore::PlaybackSessionModelMediaElement::updateMediaSelectionIndices):
(WebCore::PlaybackSessionModelMediaElement::handleEvent): Deleted.
* platform/cocoa/VideoFullscreenChangeObserver.h:
(WebCore::VideoFullscreenChangeObserver::~VideoFullscreenChangeObserver): Deleted.
* platform/cocoa/VideoFullscreenModel.h:
(WebCore::VideoFullscreenModel::ref):
(WebCore::VideoFullscreenModel::deref):
(WebCore::VideoFullscreenModel::~VideoFullscreenModel): Deleted.
* platform/cocoa/VideoFullscreenModelVideoElement.h:
* platform/cocoa/VideoFullscreenModelVideoElement.mm:
(VideoFullscreenModelVideoElement::VideoFullscreenModelVideoElement):
(VideoFullscreenModelVideoElement::setVideoElement):
(VideoFullscreenModelVideoElement::addClient):
(VideoFullscreenModelVideoElement::removeClient):
(VideoFullscreenModelVideoElement::setHasVideo):
(VideoFullscreenModelVideoElement::setVideoDimensions):
(VideoFullscreenModelVideoElement::willEnterPictureInPicture):
(VideoFullscreenModelVideoElement::didEnterPictureInPicture):
(VideoFullscreenModelVideoElement::failedToEnterPictureInPicture):
(VideoFullscreenModelVideoElement::willExitPictureInPicture):
(VideoFullscreenModelVideoElement::didExitPictureInPicture):
(VideoFullscreenModelVideoElement::handleEvent): Deleted.
* platform/ios/PlaybackSessionInterfaceAVKit.h:
(WebCore::PlaybackSessionInterfaceAVKit::create):
(WebCore::PlaybackSessionInterfaceAVKit::playbackSessionModel const):
(): Deleted.
* platform/ios/PlaybackSessionInterfaceAVKit.mm:
(WebCore::PlaybackSessionInterfaceAVKit::PlaybackSessionInterfaceAVKit):
(WebCore::PlaybackSessionInterfaceAVKit::~PlaybackSessionInterfaceAVKit):
(WebCore::PlaybackSessionInterfaceAVKit::invalidate): Deleted.
* platform/ios/VideoFullscreenInterfaceAVKit.h:
* platform/ios/VideoFullscreenInterfaceAVKit.mm:
(-[WebAVPlayerLayer layoutSublayers]):
(-[WebAVPlayerLayer resolveBounds]):
(-[WebAVPlayerLayer setVideoGravity:]):
(VideoFullscreenInterfaceAVKit::create):
(VideoFullscreenInterfaceAVKit::VideoFullscreenInterfaceAVKit):
(VideoFullscreenInterfaceAVKit::~VideoFullscreenInterfaceAVKit):
(VideoFullscreenInterfaceAVKit::setVideoFullscreenChangeObserver):
(VideoFullscreenInterfaceAVKit::applicationDidBecomeActive):
(VideoFullscreenInterfaceAVKit::setupFullscreen):
(VideoFullscreenInterfaceAVKit::presentingViewController):
(VideoFullscreenInterfaceAVKit::requestHideAndExitFullscreen):
(VideoFullscreenInterfaceAVKit::preparedToExitFullscreen):
(VideoFullscreenInterfaceAVKit::willStartPictureInPicture):
(VideoFullscreenInterfaceAVKit::didStartPictureInPicture):
(VideoFullscreenInterfaceAVKit::failedToStartPictureInPicture):
(VideoFullscreenInterfaceAVKit::willStopPictureInPicture):
(VideoFullscreenInterfaceAVKit::didStopPictureInPicture):
(VideoFullscreenInterfaceAVKit::shouldExitFullscreenWithReason):
(VideoFullscreenInterfaceAVKit::doSetup):
(VideoFullscreenInterfaceAVKit::setMode):
(VideoFullscreenInterfaceAVKit::clearMode):
(VideoFullscreenInterfaceAVKit::setVideoFullscreenModel): Deleted.
(VideoFullscreenInterfaceAVKit::invalidate): Deleted.
* platform/ios/WebAVPlayerController.h:
* platform/ios/WebAVPlayerController.mm:
(-[WebAVPlayerController delegate]):
(-[WebAVPlayerController playbackSessionInterface]):
(-[WebAVPlayerController setPlaybackSessionInterface:]):
* platform/ios/WebVideoFullscreenControllerAVKit.mm:
(VideoFullscreenControllerContext::didCleanupFullscreen):
(VideoFullscreenControllerContext::addClient):
(VideoFullscreenControllerContext::removeClient):
(VideoFullscreenControllerContext::willEnterPictureInPicture):
(VideoFullscreenControllerContext::didEnterPictureInPicture):
(VideoFullscreenControllerContext::failedToEnterPictureInPicture):
(VideoFullscreenControllerContext::willExitPictureInPicture):
(VideoFullscreenControllerContext::didExitPictureInPicture):
(VideoFullscreenControllerContext::setUpFullscreen):
* platform/mac/PlaybackSessionInterfaceMac.h:
* platform/mac/PlaybackSessionInterfaceMac.mm:
(WebCore::PlaybackSessionInterfaceMac::create):
(WebCore::PlaybackSessionInterfaceMac::PlaybackSessionInterfaceMac):
(WebCore::PlaybackSessionInterfaceMac::playbackSessionModel const):
(WebCore::PlaybackSessionInterfaceMac::rateChanged):
(WebCore::PlaybackSessionInterfaceMac::beginScrubbing):
(WebCore::PlaybackSessionInterfaceMac::endScrubbing):
(WebCore::PlaybackSessionInterfaceMac::setPlayBackControlsManager):
(WebCore::PlaybackSessionInterfaceMac::updatePlaybackControlsManagerTiming):
(WebCore::PlaybackSessionInterfaceMac::~PlaybackSessionInterfaceMac): Deleted.
(WebCore::PlaybackSessionInterfaceMac::invalidate): Deleted.
* platform/mac/VideoFullscreenInterfaceMac.h:
(WebCore::VideoFullscreenInterfaceMac::create):
(WebCore::VideoFullscreenInterfaceMac::videoFullscreenModel const):
(WebCore::VideoFullscreenInterfaceMac::playbackSessionModel const):
(WebCore::VideoFullscreenInterfaceMac::videoFullscreenChangeObserver const):
* platform/mac/VideoFullscreenInterfaceMac.mm:
(-[WebVideoFullscreenInterfaceMacObjC setUpPIPForVideoView:withFrame:inWindow:]):
(-[WebVideoFullscreenInterfaceMacObjC boundsDidChangeForVideoViewContainer:]):
(-[WebVideoFullscreenInterfaceMacObjC pipDidClose:]):
(-[WebVideoFullscreenInterfaceMacObjC pipActionPlay:]):
(-[WebVideoFullscreenInterfaceMacObjC pipActionPause:]):
(-[WebVideoFullscreenInterfaceMacObjC pipActionStop:]):
(WebCore::VideoFullscreenInterfaceMac::VideoFullscreenInterfaceMac):
(WebCore::VideoFullscreenInterfaceMac::~VideoFullscreenInterfaceMac):
(WebCore::VideoFullscreenInterfaceMac::setVideoFullscreenChangeObserver):
(WebCore::VideoFullscreenInterfaceMac::setMode):
(WebCore::VideoFullscreenInterfaceMac::clearMode):
(WebCore::VideoFullscreenInterfaceMac::invalidate):
(WebCore::VideoFullscreenInterfaceMac::requestHideAndExitPiP):
(WebCore::VideoFullscreenInterfaceMac::setVideoFullscreenModel): Deleted.
* platform/mac/WebPlaybackControlsManager.mm:
(-[WebPlaybackControlsManager seekToTime:toleranceBefore:toleranceAfter:]):
(-[WebPlaybackControlsManager setCurrentAudioTouchBarMediaSelectionOption:]):
(-[WebPlaybackControlsManager setCurrentLegibleTouchBarMediaSelectionOption:]):
(-[WebPlaybackControlsManager togglePlayback]):
(-[WebPlaybackControlsManager setPlaying:]):
(-[WebPlaybackControlsManager isPlaying]):
(-[WebPlaybackControlsManager togglePictureInPicture]):

Source/WebKit:

Adopt those Ref and WeakPtr changes made in WebCore.

* UIProcess/Cocoa/PlaybackSessionManagerProxy.h:
* UIProcess/Cocoa/PlaybackSessionManagerProxy.mm:
(WebKit::PlaybackSessionModelContext::addClient):
(WebKit::PlaybackSessionModelContext::removeClient):
(WebKit::PlaybackSessionModelContext::durationChanged):
(WebKit::PlaybackSessionModelContext::currentTimeChanged):
(WebKit::PlaybackSessionModelContext::bufferedTimeChanged):
(WebKit::PlaybackSessionModelContext::rateChanged):
(WebKit::PlaybackSessionModelContext::seekableRangesChanged):
(WebKit::PlaybackSessionModelContext::canPlayFastReverseChanged):
(WebKit::PlaybackSessionModelContext::audioMediaSelectionOptionsChanged):
(WebKit::PlaybackSessionModelContext::legibleMediaSelectionOptionsChanged):
(WebKit::PlaybackSessionModelContext::audioMediaSelectionIndexChanged):
(WebKit::PlaybackSessionModelContext::legibleMediaSelectionIndexChanged):
(WebKit::PlaybackSessionModelContext::externalPlaybackChanged):
(WebKit::PlaybackSessionModelContext::wirelessVideoPlaybackDisabledChanged):
(WebKit::PlaybackSessionModelContext::mutedChanged):
(WebKit::PlaybackSessionModelContext::volumeChanged):
(WebKit::PlaybackSessionModelContext::pictureInPictureActiveChanged):
(WebKit::PlaybackSessionManagerProxy::invalidate):
(WebKit::PlaybackSessionManagerProxy::createModelAndInterface):
(WebKit::PlaybackSessionManagerProxy::removeClientForContext):
* UIProcess/Cocoa/VideoFullscreenManagerProxy.h:
* UIProcess/Cocoa/VideoFullscreenManagerProxy.mm:
(WebKit::VideoFullscreenModelContext::create):
(WebKit::VideoFullscreenModelContext::VideoFullscreenModelContext):
(WebKit::VideoFullscreenModelContext::addClient):
(WebKit::VideoFullscreenModelContext::removeClient):
(WebKit::VideoFullscreenModelContext::willEnterPictureInPicture):
(WebKit::VideoFullscreenModelContext::didEnterPictureInPicture):
(WebKit::VideoFullscreenModelContext::failedToEnterPictureInPicture):
(WebKit::VideoFullscreenModelContext::willExitPictureInPicture):
(WebKit::VideoFullscreenModelContext::didExitPictureInPicture):
(WebKit::VideoFullscreenManagerProxy::invalidate):
(WebKit::VideoFullscreenManagerProxy::createModelAndInterface):
(WebKit::VideoFullscreenManagerProxy::removeClientForContext):
(WebKit::VideoFullscreenModelContext::~VideoFullscreenModelContext): Deleted.
* UIProcess/ios/fullscreen/WKFullScreenViewController.mm:
(WKFullScreenViewControllerPlaybackSessionModelClient::setInterface):
(WKFullScreenViewControllerVideoFullscreenModelClient::setInterface):
(-[WKFullScreenViewController videoControlsManagerDidChange]):
(-[WKFullScreenViewController _togglePiPAction:]):
* UIProcess/mac/WKFullScreenWindowController.mm:
(WebKit::WKFullScreenWindowControllerVideoFullscreenModelClient::setInterface):
* WebProcess/cocoa/PlaybackSessionManager.h:
* WebProcess/cocoa/PlaybackSessionManager.mm:
(WebKit::PlaybackSessionInterfaceContext::PlaybackSessionInterfaceContext):
(WebKit::PlaybackSessionManager::~PlaybackSessionManager):
(WebKit::PlaybackSessionManager::createModelAndInterface):
(WebKit::PlaybackSessionManager::removeContext):
(WebKit::PlaybackSessionInterfaceContext::~PlaybackSessionInterfaceContext): Deleted.
* WebProcess/cocoa/VideoFullscreenManager.h:
(WebKit::VideoFullscreenInterfaceContext::create):
(WebKit::VideoFullscreenInterfaceContext::createWeakPtr):
* WebProcess/cocoa/VideoFullscreenManager.mm:
(WebKit::VideoFullscreenInterfaceContext::VideoFullscreenInterfaceContext):
(WebKit::VideoFullscreenManager::~VideoFullscreenManager):
(WebKit::VideoFullscreenManager::createModelAndInterface):
(WebKit::VideoFullscreenManager::removeContext):

Source/WebKitLegacy/mac:

PlaybackSessionInterface no longer has an invalidate() method.

* WebView/WebView.mm:
(-[WebView _clearPlaybackControlsManager]):

Source/WTF:

* WTF.xcodeproj/project.pbxproj:
* wtf/WeakPtrContainer.h: Added.

LayoutTests:

Test was causing false pass results due to the webkitPresentationMode being correctly set
to "inline" during the close() operation; modify the test to only perform the close()
operation when the presetation mode is changed to "picture-in-picture".

* media/controls/ipad/close-page-with-picture-in-picture-video-assertion-failure.html:
* media/controls/ipad/resources/picture-in-picture.html:

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

40 files changed:
LayoutTests/ChangeLog
LayoutTests/media/controls/ipad/close-page-with-picture-in-picture-video-assertion-failure.html
LayoutTests/media/controls/ipad/resources/picture-in-picture.html
Source/WTF/ChangeLog
Source/WTF/WTF.xcodeproj/project.pbxproj
Source/WTF/wtf/WeakPtrContainer.h [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/platform/cocoa/PlaybackSessionInterface.h
Source/WebCore/platform/cocoa/PlaybackSessionModel.h
Source/WebCore/platform/cocoa/PlaybackSessionModelMediaElement.h
Source/WebCore/platform/cocoa/PlaybackSessionModelMediaElement.mm
Source/WebCore/platform/cocoa/VideoFullscreenChangeObserver.h
Source/WebCore/platform/cocoa/VideoFullscreenModel.h
Source/WebCore/platform/cocoa/VideoFullscreenModelVideoElement.h
Source/WebCore/platform/cocoa/VideoFullscreenModelVideoElement.mm
Source/WebCore/platform/ios/PlaybackSessionInterfaceAVKit.h
Source/WebCore/platform/ios/PlaybackSessionInterfaceAVKit.mm
Source/WebCore/platform/ios/VideoFullscreenInterfaceAVKit.h
Source/WebCore/platform/ios/VideoFullscreenInterfaceAVKit.mm
Source/WebCore/platform/ios/WebAVPlayerController.h
Source/WebCore/platform/ios/WebAVPlayerController.mm
Source/WebCore/platform/ios/WebVideoFullscreenControllerAVKit.mm
Source/WebCore/platform/mac/PlaybackSessionInterfaceMac.h
Source/WebCore/platform/mac/PlaybackSessionInterfaceMac.mm
Source/WebCore/platform/mac/VideoFullscreenInterfaceMac.h
Source/WebCore/platform/mac/VideoFullscreenInterfaceMac.mm
Source/WebCore/platform/mac/WebPlaybackControlsManager.mm
Source/WebKit/ChangeLog
Source/WebKit/UIProcess/Cocoa/PlaybackSessionManagerProxy.h
Source/WebKit/UIProcess/Cocoa/PlaybackSessionManagerProxy.mm
Source/WebKit/UIProcess/Cocoa/VideoFullscreenManagerProxy.h
Source/WebKit/UIProcess/Cocoa/VideoFullscreenManagerProxy.mm
Source/WebKit/UIProcess/ios/fullscreen/WKFullScreenViewController.mm
Source/WebKit/UIProcess/mac/WKFullScreenWindowController.mm
Source/WebKit/WebProcess/cocoa/PlaybackSessionManager.h
Source/WebKit/WebProcess/cocoa/PlaybackSessionManager.mm
Source/WebKit/WebProcess/cocoa/VideoFullscreenManager.h
Source/WebKit/WebProcess/cocoa/VideoFullscreenManager.mm
Source/WebKitLegacy/mac/ChangeLog
Source/WebKitLegacy/mac/WebView/WebView.mm

index 2c0c229..7b84449 100644 (file)
@@ -1,3 +1,18 @@
+2018-09-28  Jer Noble  <jer.noble@apple.com>
+
+        Refactoring: eliminate raw pointer usage in Fullscreen code
+        https://bugs.webkit.org/show_bug.cgi?id=188747
+        <rdar://problem/43541164>
+
+        Reviewed by Alex Christensen.
+
+        Test was causing false pass results due to the webkitPresentationMode being correctly set
+        to "inline" during the close() operation; modify the test to only perform the close()
+        operation when the presetation mode is changed to "picture-in-picture".
+
+        * media/controls/ipad/close-page-with-picture-in-picture-video-assertion-failure.html:
+        * media/controls/ipad/resources/picture-in-picture.html:
+
 2018-09-28  Chris Dumez  <cdumez@apple.com>
 
         REGRESSION (r236573): [iOS] Layout test editing/pasteboard/emacs-ctrl-a-k-y.html is failing
index 71940c9..7e08add 100644 (file)
@@ -13,8 +13,11 @@ if (window.testRunner) {
 }
 
 // Called by resources/picture-in-picture.html
-function notifyDidChangePresentationMode()
+function notifyDidChangePresentationMode(mode)
 {
+    if (mode !== 'picture-in-picture')
+        return;
+
     // For some reason waiting ~200ms to allow the video to transition from the page to its
     // picture-in-picture window seems to make triggering the assertion more reliable (why?).
     function closeWindowAndDone()
index b1d02b9..7a376d0 100644 (file)
@@ -9,9 +9,9 @@
 if (window.internals)
     internals.settings.setAllowsPictureInPictureMediaPlayback(true);
 
-function dispatchDidChangePresentationMode()
+function dispatchDidChangePresentationMode(event)
 {
-    window.opener.notifyDidChangePresentationMode();
+    window.opener.notifyDidChangePresentationMode(event.target.webkitPresentationMode);
 }
 
 var video = document.querySelector("video");
index dbd9a15..88d3fa3 100644 (file)
@@ -1,3 +1,14 @@
+2018-09-28  Jer Noble  <jer.noble@apple.com>
+
+        Refactoring: eliminate raw pointer usage in Fullscreen code
+        https://bugs.webkit.org/show_bug.cgi?id=188747
+        <rdar://problem/43541164>
+
+        Reviewed by Alex Christensen.
+
+        * WTF.xcodeproj/project.pbxproj:
+        * wtf/WeakPtrContainer.h: Added.
+
 2018-09-28  Koby Boyango  <koby.b@mce.systems>
 
         [WTF] Add ExternalStringImpl, a StringImpl for user controlled buffers
index 9df1a5e..8271409 100644 (file)
                C6F050790D9C432A99085E75 /* ASCIILiteral.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASCIILiteral.cpp; sourceTree = "<group>"; };
                C8F597CA2A57417FBAB92FD6 /* RandomDevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RandomDevice.cpp; sourceTree = "<group>"; };
                CD00360D21501F7800F4ED4C /* StringToIntegerConversion.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StringToIntegerConversion.h; sourceTree = "<group>"; };
+               CD2D0D10212C76E60018C784 /* WeakPtrContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakPtrContainer.h; sourceTree = "<group>"; };
                CD5497AA15857D0300B5BC30 /* MediaTime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MediaTime.cpp; sourceTree = "<group>"; };
                CD5497AB15857D0300B5BC30 /* MediaTime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaTime.h; sourceTree = "<group>"; };
                CD6D9FCD1EEF3AD4008B0671 /* Algorithms.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Algorithms.h; sourceTree = "<group>"; };
                                0F66B2891DC97BAB004A1D3F /* WallTime.h */,
                                83ABB3C020B3823200BA3306 /* WeakObjCPtr.h */,
                                974CFC8D16A4F327006D5404 /* WeakPtr.h */,
+                               CD2D0D10212C76E60018C784 /* WeakPtrContainer.h */,
                                0F3501631BB258C800F0A2A3 /* WeakRandom.h */,
                                0FE4479A1B7AAA03009498EB /* WordLock.cpp */,
                                0FE4479B1B7AAA03009498EB /* WordLock.h */,
diff --git a/Source/WTF/wtf/WeakPtrContainer.h b/Source/WTF/wtf/WeakPtrContainer.h
new file mode 100644 (file)
index 0000000..8c85bfe
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/Vector.h>
+#include <wtf/WeakPtr.h>
+
+namespace WTF {
+
+template <typename T>
+class WeakPtrContainer {
+public:
+    void add(WeakPtr<T>&& ptr)
+    {
+        m_members.append(WTFMove(ptr));
+    }
+    
+    void remove(T& ptr)
+    {
+        m_members.removeAll(&ptr);
+    }
+
+    void clear()
+    {
+        m_members.clear();
+    }
+
+    bool isEmpty() const
+    {
+        return m_members.isEmpty();
+    }
+    
+    template <typename F>
+    void forEachNonNullMember(F&& f)
+    {
+        m_members.removeAllMatching([f = WTFMove(f)] (auto& member) {
+            if (!member)
+                return false;
+            f(*member);
+            return true;
+        });
+    }
+private:
+    Vector<WeakPtr<T>> m_members;
+};
+
+}
+
+using WTF::WeakPtrContainer;
index 9c016d5..f57f0ba 100644 (file)
@@ -1,3 +1,164 @@
+2018-09-28  Jer Noble  <jer.noble@apple.com>
+
+        Refactoring: eliminate raw pointer usage in Fullscreen code
+        https://bugs.webkit.org/show_bug.cgi?id=188747
+        <rdar://problem/43541164>
+
+        Reviewed by Alex Christensen.
+
+        Two sources of raw pointers in the Fullscreen code:
+        - Model classes (PlaybackSessionModel and VideoFullscreenModel) aren't ref-able, so
+          they are passed around as raw references.
+        - Observer classes (PlaybackSessionModelClient and VideoFullscreenModelClient, and
+          VideoFullscreenChangeObserver) are also passed around as raw pointers, but shouldn't
+          be ref-able.
+
+        Make Model classes ref-able by adding ref() and deref() which call virtual refModel and
+        derefModel methods, overridden by implementing subclasses. Make every concrete observer
+        inherit from CanMakeWeakPtr, and every registration method take WeakPtr wrappers around
+        the client interface.
+
+        Since every Interface class now holds a strong reference to its Model classes, and each
+        Model class holds a weak reference to all its clients, no explicit invalidate() method
+        is necessary.
+
+        Notes:
+
+        - Since the weak pointer methods need to be able to downcast to the abstract base class,
+          observers need to inherit publically (rather than privately) from those base classes.
+        - Media element Models should compose EventListener rather than inheriting from it, since
+          EventListener has its own RefCount.
+        - WeakPtrs can't be held in HashSets (because they change value, and therefore hash, when
+          their underlying object is destroyed), so clients should be stored in a Vector instead.
+        - Interfaces should be given all required Refs at creation time, so that they can store
+          those parameters as Refs instead of RefPtrs.
+
+        * platform/cocoa/PlaybackSessionInterface.h:
+        (WebCore::PlaybackSessionInterface::~PlaybackSessionInterface): Deleted.
+        * platform/cocoa/PlaybackSessionModel.h:
+        (WebCore::PlaybackSessionModel::ref):
+        (WebCore::PlaybackSessionModel::deref):
+        (WebCore::PlaybackSessionModel::~PlaybackSessionModel): Deleted.
+        * platform/cocoa/PlaybackSessionModelMediaElement.h:
+        * platform/cocoa/PlaybackSessionModelMediaElement.mm:
+        (WebCore::PlaybackSessionModelMediaElement::PlaybackSessionModelMediaElement):
+        (WebCore::PlaybackSessionModelMediaElement::~PlaybackSessionModelMediaElement):
+        (WebCore::PlaybackSessionModelMediaElement::setMediaElement):
+        (WebCore::PlaybackSessionModelMediaElement::updateForEventName):
+        (WebCore::PlaybackSessionModelMediaElement::addClient):
+        (WebCore::PlaybackSessionModelMediaElement::removeClient):
+        (WebCore::PlaybackSessionModelMediaElement::updateMediaSelectionOptions):
+        (WebCore::PlaybackSessionModelMediaElement::updateMediaSelectionIndices):
+        (WebCore::PlaybackSessionModelMediaElement::handleEvent): Deleted.
+        * platform/cocoa/VideoFullscreenChangeObserver.h:
+        (WebCore::VideoFullscreenChangeObserver::~VideoFullscreenChangeObserver): Deleted.
+        * platform/cocoa/VideoFullscreenModel.h:
+        (WebCore::VideoFullscreenModel::ref):
+        (WebCore::VideoFullscreenModel::deref):
+        (WebCore::VideoFullscreenModel::~VideoFullscreenModel): Deleted.
+        * platform/cocoa/VideoFullscreenModelVideoElement.h:
+        * platform/cocoa/VideoFullscreenModelVideoElement.mm:
+        (VideoFullscreenModelVideoElement::VideoFullscreenModelVideoElement):
+        (VideoFullscreenModelVideoElement::setVideoElement):
+        (VideoFullscreenModelVideoElement::addClient):
+        (VideoFullscreenModelVideoElement::removeClient):
+        (VideoFullscreenModelVideoElement::setHasVideo):
+        (VideoFullscreenModelVideoElement::setVideoDimensions):
+        (VideoFullscreenModelVideoElement::willEnterPictureInPicture):
+        (VideoFullscreenModelVideoElement::didEnterPictureInPicture):
+        (VideoFullscreenModelVideoElement::failedToEnterPictureInPicture):
+        (VideoFullscreenModelVideoElement::willExitPictureInPicture):
+        (VideoFullscreenModelVideoElement::didExitPictureInPicture):
+        (VideoFullscreenModelVideoElement::handleEvent): Deleted.
+        * platform/ios/PlaybackSessionInterfaceAVKit.h:
+        (WebCore::PlaybackSessionInterfaceAVKit::create):
+        (WebCore::PlaybackSessionInterfaceAVKit::playbackSessionModel const):
+        (): Deleted.
+        * platform/ios/PlaybackSessionInterfaceAVKit.mm:
+        (WebCore::PlaybackSessionInterfaceAVKit::PlaybackSessionInterfaceAVKit):
+        (WebCore::PlaybackSessionInterfaceAVKit::~PlaybackSessionInterfaceAVKit):
+        (WebCore::PlaybackSessionInterfaceAVKit::invalidate): Deleted.
+        * platform/ios/VideoFullscreenInterfaceAVKit.h:
+        * platform/ios/VideoFullscreenInterfaceAVKit.mm:
+        (-[WebAVPlayerLayer layoutSublayers]):
+        (-[WebAVPlayerLayer resolveBounds]):
+        (-[WebAVPlayerLayer setVideoGravity:]):
+        (VideoFullscreenInterfaceAVKit::create):
+        (VideoFullscreenInterfaceAVKit::VideoFullscreenInterfaceAVKit):
+        (VideoFullscreenInterfaceAVKit::~VideoFullscreenInterfaceAVKit):
+        (VideoFullscreenInterfaceAVKit::setVideoFullscreenChangeObserver):
+        (VideoFullscreenInterfaceAVKit::applicationDidBecomeActive):
+        (VideoFullscreenInterfaceAVKit::setupFullscreen):
+        (VideoFullscreenInterfaceAVKit::presentingViewController):
+        (VideoFullscreenInterfaceAVKit::requestHideAndExitFullscreen):
+        (VideoFullscreenInterfaceAVKit::preparedToExitFullscreen):
+        (VideoFullscreenInterfaceAVKit::willStartPictureInPicture):
+        (VideoFullscreenInterfaceAVKit::didStartPictureInPicture):
+        (VideoFullscreenInterfaceAVKit::failedToStartPictureInPicture):
+        (VideoFullscreenInterfaceAVKit::willStopPictureInPicture):
+        (VideoFullscreenInterfaceAVKit::didStopPictureInPicture):
+        (VideoFullscreenInterfaceAVKit::shouldExitFullscreenWithReason):
+        (VideoFullscreenInterfaceAVKit::doSetup):
+        (VideoFullscreenInterfaceAVKit::setMode):
+        (VideoFullscreenInterfaceAVKit::clearMode):
+        (VideoFullscreenInterfaceAVKit::setVideoFullscreenModel): Deleted.
+        (VideoFullscreenInterfaceAVKit::invalidate): Deleted.
+        * platform/ios/WebAVPlayerController.h:
+        * platform/ios/WebAVPlayerController.mm:
+        (-[WebAVPlayerController delegate]):
+        (-[WebAVPlayerController playbackSessionInterface]):
+        (-[WebAVPlayerController setPlaybackSessionInterface:]):
+        * platform/ios/WebVideoFullscreenControllerAVKit.mm:
+        (VideoFullscreenControllerContext::didCleanupFullscreen):
+        (VideoFullscreenControllerContext::addClient):
+        (VideoFullscreenControllerContext::removeClient):
+        (VideoFullscreenControllerContext::willEnterPictureInPicture):
+        (VideoFullscreenControllerContext::didEnterPictureInPicture):
+        (VideoFullscreenControllerContext::failedToEnterPictureInPicture):
+        (VideoFullscreenControllerContext::willExitPictureInPicture):
+        (VideoFullscreenControllerContext::didExitPictureInPicture):
+        (VideoFullscreenControllerContext::setUpFullscreen):
+        * platform/mac/PlaybackSessionInterfaceMac.h:
+        * platform/mac/PlaybackSessionInterfaceMac.mm:
+        (WebCore::PlaybackSessionInterfaceMac::create):
+        (WebCore::PlaybackSessionInterfaceMac::PlaybackSessionInterfaceMac):
+        (WebCore::PlaybackSessionInterfaceMac::playbackSessionModel const):
+        (WebCore::PlaybackSessionInterfaceMac::rateChanged):
+        (WebCore::PlaybackSessionInterfaceMac::beginScrubbing):
+        (WebCore::PlaybackSessionInterfaceMac::endScrubbing):
+        (WebCore::PlaybackSessionInterfaceMac::setPlayBackControlsManager):
+        (WebCore::PlaybackSessionInterfaceMac::updatePlaybackControlsManagerTiming):
+        (WebCore::PlaybackSessionInterfaceMac::~PlaybackSessionInterfaceMac): Deleted.
+        (WebCore::PlaybackSessionInterfaceMac::invalidate): Deleted.
+        * platform/mac/VideoFullscreenInterfaceMac.h:
+        (WebCore::VideoFullscreenInterfaceMac::create):
+        (WebCore::VideoFullscreenInterfaceMac::videoFullscreenModel const):
+        (WebCore::VideoFullscreenInterfaceMac::playbackSessionModel const):
+        (WebCore::VideoFullscreenInterfaceMac::videoFullscreenChangeObserver const):
+        * platform/mac/VideoFullscreenInterfaceMac.mm:
+        (-[WebVideoFullscreenInterfaceMacObjC setUpPIPForVideoView:withFrame:inWindow:]):
+        (-[WebVideoFullscreenInterfaceMacObjC boundsDidChangeForVideoViewContainer:]):
+        (-[WebVideoFullscreenInterfaceMacObjC pipDidClose:]):
+        (-[WebVideoFullscreenInterfaceMacObjC pipActionPlay:]):
+        (-[WebVideoFullscreenInterfaceMacObjC pipActionPause:]):
+        (-[WebVideoFullscreenInterfaceMacObjC pipActionStop:]):
+        (WebCore::VideoFullscreenInterfaceMac::VideoFullscreenInterfaceMac):
+        (WebCore::VideoFullscreenInterfaceMac::~VideoFullscreenInterfaceMac):
+        (WebCore::VideoFullscreenInterfaceMac::setVideoFullscreenChangeObserver):
+        (WebCore::VideoFullscreenInterfaceMac::setMode):
+        (WebCore::VideoFullscreenInterfaceMac::clearMode):
+        (WebCore::VideoFullscreenInterfaceMac::invalidate):
+        (WebCore::VideoFullscreenInterfaceMac::requestHideAndExitPiP):
+        (WebCore::VideoFullscreenInterfaceMac::setVideoFullscreenModel): Deleted.
+        * platform/mac/WebPlaybackControlsManager.mm:
+        (-[WebPlaybackControlsManager seekToTime:toleranceBefore:toleranceAfter:]):
+        (-[WebPlaybackControlsManager setCurrentAudioTouchBarMediaSelectionOption:]):
+        (-[WebPlaybackControlsManager setCurrentLegibleTouchBarMediaSelectionOption:]):
+        (-[WebPlaybackControlsManager togglePlayback]):
+        (-[WebPlaybackControlsManager setPlaying:]):
+        (-[WebPlaybackControlsManager isPlaying]):
+        (-[WebPlaybackControlsManager togglePictureInPicture]):
+
 2018-09-28  Chris Dumez  <cdumez@apple.com>
 
         Drop iOS specific quirk in SettingsBase::scriptEnabledChanged()
index cdf2bbf..db7b58f 100644 (file)
 
 #if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
 
-#include <wtf/Forward.h>
-#include <wtf/Vector.h>
-
 namespace WebCore {
 
-class TimeRanges;
-
 class PlaybackSessionInterface {
 public:
-    virtual ~PlaybackSessionInterface() { };
+    virtual ~PlaybackSessionInterface() = default;
     virtual void resetMediaState() = 0;
 };
 
index c43f732..1553639 100644 (file)
@@ -30,6 +30,7 @@
 #include <wtf/Forward.h>
 #include <wtf/Ref.h>
 #include <wtf/Vector.h>
+#include <wtf/WeakPtr.h>
 
 namespace WebCore {
 
@@ -39,8 +40,12 @@ struct MediaSelectionOption;
 
 class PlaybackSessionModel {
 public:
-    virtual ~PlaybackSessionModel() { };
-    virtual void addClient(PlaybackSessionModelClient&) = 0;
+    virtual ~PlaybackSessionModel() = default;
+
+    void ref() { refPlaybackSessionModel(); }
+    void deref() { derefPlaybackSessionModel(); }
+
+    virtual void addClient(WeakPtr<PlaybackSessionModelClient>&&) = 0;
     virtual void removeClient(PlaybackSessionModelClient&) = 0;
 
     virtual void play() = 0;
@@ -86,6 +91,10 @@ public:
     virtual double volume() const = 0;
     virtual bool isPictureInPictureSupported() const = 0;
     virtual bool isPictureInPictureActive() const = 0;
+
+private:
+    virtual void refPlaybackSessionModel() = 0;
+    virtual void derefPlaybackSessionModel() = 0;
 };
 
 class PlaybackSessionModelClient {
index 9eefd10..204629b 100644 (file)
@@ -30,9 +30,8 @@
 #include "EventListener.h"
 #include "HTMLMediaElementEnums.h"
 #include "PlaybackSessionModel.h"
-#include <wtf/HashSet.h>
 #include <wtf/RefPtr.h>
-#include <wtf/Vector.h>
+#include <wtf/WeakPtrContainer.h>
 
 namespace WebCore {
 
@@ -41,7 +40,10 @@ class HTMLMediaElement;
 class TextTrack;
 class PlaybackSessionInterface;
 
-class PlaybackSessionModelMediaElement final : public PlaybackSessionModel, public EventListener {
+class PlaybackSessionModelMediaElement final
+    : public RefCounted<PlaybackSessionModelMediaElement>
+    , public CanMakeWeakPtr<PlaybackSessionModelMediaElement>
+    , public PlaybackSessionModel {
 public:
     static Ref<PlaybackSessionModelMediaElement> create()
     {
@@ -51,11 +53,9 @@ public:
     WEBCORE_EXPORT void setMediaElement(HTMLMediaElement*);
     HTMLMediaElement* mediaElement() const { return m_mediaElement.get(); }
 
-    WEBCORE_EXPORT void handleEvent(WebCore::ScriptExecutionContext&, WebCore::Event&) final;
     void updateForEventName(const WTF::AtomicString&);
-    bool operator==(const EventListener& rhs) const final { return static_cast<const WebCore::EventListener*>(this) == &rhs; }
 
-    WEBCORE_EXPORT void addClient(PlaybackSessionModelClient&);
+    WEBCORE_EXPORT void addClient(WeakPtr<PlaybackSessionModelClient>&&);
     WEBCORE_EXPORT void removeClient(PlaybackSessionModelClient&);
     WEBCORE_EXPORT void play() final;
     WEBCORE_EXPORT void pause() final;
@@ -98,19 +98,27 @@ public:
     bool isPictureInPictureSupported() const final;
     bool isPictureInPictureActive() const final;
 
+    using RefCounted::ref;
+    using RefCounted::deref;
+
 protected:
     WEBCORE_EXPORT PlaybackSessionModelMediaElement();
 
 private:
+    void refPlaybackSessionModel() final { ref(); }
+    void derefPlaybackSessionModel() final { deref(); }
+    
     void progressEventTimerFired();
     static const Vector<WTF::AtomicString>& observedEventNames();
     const WTF::AtomicString& eventNameAll();
 
+    class MediaElementEventListener;
+
     RefPtr<HTMLMediaElement> m_mediaElement;
-    bool m_isListening { false };
-    HashSet<PlaybackSessionModelClient*> m_clients;
+    WeakPtrContainer<PlaybackSessionModelClient> m_clients;
     Vector<RefPtr<TextTrack>> m_legibleTracksForMenu;
     Vector<RefPtr<AudioTrack>> m_audioTracksForMenu;
+    Ref<MediaElementEventListener> m_eventListener;
 
     double playbackStartedTime() const;
     void updateMediaSelectionOptions();
index c017921..d60a443 100644 (file)
 
 namespace WebCore {
 
+class PlaybackSessionModelMediaElement::MediaElementEventListener final : public EventListener {
+public:
+    MediaElementEventListener(WeakPtr<PlaybackSessionModelMediaElement>&& parent)
+        : EventListener(CPPEventListenerType)
+        , m_parent(WTFMove(parent))
+    {
+    }
+private:
+    void handleEvent(WebCore::ScriptExecutionContext&, WebCore::Event& event) final
+    {
+        if (m_parent)
+            m_parent->updateForEventName(event.type());
+    }
+    bool operator==(const EventListener& rhs) const final { return static_cast<const WebCore::EventListener*>(this) == &rhs; }
+
+    WeakPtr<PlaybackSessionModelMediaElement> m_parent;
+};
+
 PlaybackSessionModelMediaElement::PlaybackSessionModelMediaElement()
-    : EventListener(EventListener::CPPEventListenerType)
+    : m_eventListener(adoptRef(*new MediaElementEventListener(makeWeakPtr(*this))))
 {
 }
 
 PlaybackSessionModelMediaElement::~PlaybackSessionModelMediaElement()
 {
+    m_clients.clear();
+    setMediaElement(nullptr);
 }
 
 void PlaybackSessionModelMediaElement::setMediaElement(HTMLMediaElement* mediaElement)
@@ -63,52 +83,45 @@ void PlaybackSessionModelMediaElement::setMediaElement(HTMLMediaElement* mediaEl
 
     auto& events = eventNames();
 
-    if (m_mediaElement && m_isListening) {
+    if (m_mediaElement) {
         for (auto& eventName : observedEventNames())
-            m_mediaElement->removeEventListener(eventName, *this, false);
+            m_mediaElement->removeEventListener(eventName, m_eventListener.copyRef(), false);
         if (auto* audioTracks = m_mediaElement->audioTracks()) {
-            audioTracks->removeEventListener(events.addtrackEvent, *this, false);
-            audioTracks->removeEventListener(events.changeEvent, *this, false);
-            audioTracks->removeEventListener(events.removetrackEvent, *this, false);
+            audioTracks->removeEventListener(events.addtrackEvent, m_eventListener.copyRef(), false);
+            audioTracks->removeEventListener(events.changeEvent, m_eventListener.copyRef(), false);
+            audioTracks->removeEventListener(events.removetrackEvent, m_eventListener.copyRef(), false);
         }
 
         if (auto* textTracks = m_mediaElement->audioTracks()) {
-            textTracks->removeEventListener(events.addtrackEvent, *this, false);
-            textTracks->removeEventListener(events.changeEvent, *this, false);
-            textTracks->removeEventListener(events.removetrackEvent, *this, false);
+            textTracks->removeEventListener(events.addtrackEvent, m_eventListener.copyRef(), false);
+            textTracks->removeEventListener(events.changeEvent, m_eventListener.copyRef(), false);
+            textTracks->removeEventListener(events.removetrackEvent, m_eventListener.copyRef(), false);
         }
-    }
-    m_isListening = false;
-
-    if (m_mediaElement)
         m_mediaElement->resetPlaybackSessionState();
+    }
 
     m_mediaElement = mediaElement;
 
     if (m_mediaElement) {
         for (auto& eventName : observedEventNames())
-            m_mediaElement->addEventListener(eventName, *this, false);
+            m_mediaElement->addEventListener(eventName, m_eventListener.copyRef(), false);
 
         auto& audioTracks = m_mediaElement->ensureAudioTracks();
-        audioTracks.addEventListener(events.addtrackEvent, *this, false);
-        audioTracks.addEventListener(events.changeEvent, *this, false);
-        audioTracks.addEventListener(events.removetrackEvent, *this, false);
+        audioTracks.addEventListener(events.addtrackEvent, m_eventListener.copyRef(), false);
+        audioTracks.addEventListener(events.changeEvent, m_eventListener.copyRef(), false);
+        audioTracks.addEventListener(events.removetrackEvent, m_eventListener.copyRef(), false);
 
         auto& textTracks = m_mediaElement->ensureTextTracks();
-        textTracks.addEventListener(events.addtrackEvent, *this, false);
-        textTracks.addEventListener(events.changeEvent, *this, false);
-        textTracks.addEventListener(events.removetrackEvent, *this, false);
+        textTracks.addEventListener(events.addtrackEvent, m_eventListener.copyRef(), false);
+        textTracks.addEventListener(events.changeEvent, m_eventListener.copyRef(), false);
+        textTracks.addEventListener(events.removetrackEvent, m_eventListener.copyRef(), false);
     }
 
     updateForEventName(eventNameAll());
 
-    for (auto client : m_clients)
-        client->isPictureInPictureSupportedChanged(isPictureInPictureSupported());
-}
-
-void PlaybackSessionModelMediaElement::handleEvent(WebCore::ScriptExecutionContext&, WebCore::Event& event)
-{
-    updateForEventName(event.type());
+    m_clients.forEachNonNullMember([isPictureInPictureSupported = isPictureInPictureSupported()] (auto& client) {
+        client.isPictureInPictureSupportedChanged(isPictureInPictureSupported);
+    });
 }
 
 void PlaybackSessionModelMediaElement::updateForEventName(const WTF::AtomicString& eventName)
@@ -120,51 +133,46 @@ void PlaybackSessionModelMediaElement::updateForEventName(const WTF::AtomicStrin
 
     if (all
         || eventName == eventNames().durationchangeEvent) {
-        double duration = this->duration();
-        for (auto client : m_clients)
-            client->durationChanged(duration);
+        m_clients.forEachNonNullMember([duration = duration()] (auto& client) {
+            client.durationChanged(duration);
+        });
         // These is no standard event for minFastReverseRateChange; duration change is a reasonable proxy for it.
         // It happens every time a new item becomes ready to play.
-        bool canPlayFastReverse = this->canPlayFastReverse();
-        for (auto client : m_clients)
-            client->canPlayFastReverseChanged(canPlayFastReverse);
+        m_clients.forEachNonNullMember([canPlayFastReverse = canPlayFastReverse()] (auto& client) {
+            client.canPlayFastReverseChanged(canPlayFastReverse);
+        });
     }
 
     if (all
         || eventName == eventNames().playEvent
         || eventName == eventNames().playingEvent) {
-        for (auto client : m_clients)
-            client->playbackStartedTimeChanged(playbackStartedTime());
+        m_clients.forEachNonNullMember([playbackStartedTime = playbackStartedTime()] (auto& client) {
+            client.playbackStartedTimeChanged(playbackStartedTime);
+        });
     }
 
     if (all
         || eventName == eventNames().pauseEvent
         || eventName == eventNames().playEvent
         || eventName == eventNames().ratechangeEvent) {
-        bool isPlaying = this->isPlaying();
-        float playbackRate = this->playbackRate();
-        for (auto client : m_clients)
-            client->rateChanged(isPlaying, playbackRate);
+        m_clients.forEachNonNullMember([isPlaying = isPlaying(), playbackRate = playbackRate()] (auto& client) {
+            client.rateChanged(isPlaying, playbackRate);
+        });
     }
 
     if (all
         || eventName == eventNames().timeupdateEvent) {
-        auto currentTime = this->currentTime();
-        auto anchorTime = [[NSProcessInfo processInfo] systemUptime];
-        for (auto client : m_clients)
-            client->currentTimeChanged(currentTime, anchorTime);
+        m_clients.forEachNonNullMember([currentTime = currentTime(), anchorTime = [[NSProcessInfo processInfo] systemUptime]] (auto& client) {
+            client.currentTimeChanged(currentTime, anchorTime);
+        });
     }
 
     if (all
         || eventName == eventNames().progressEvent) {
-        auto bufferedTime = this->bufferedTime();
-        auto seekableRanges = this->seekableRanges();
-        auto seekableTimeRangesLastModifiedTime = this->seekableTimeRangesLastModifiedTime();
-        auto liveUpdateInterval = this->liveUpdateInterval();
-        for (auto client : m_clients) {
-            client->bufferedTimeChanged(bufferedTime);
-            client->seekableRangesChanged(seekableRanges, seekableTimeRangesLastModifiedTime, liveUpdateInterval);
-        }
+        m_clients.forEachNonNullMember([bufferedTime = bufferedTime(), seekableRanges = seekableRanges(), seekableTimeRangesLastModifiedTime = seekableTimeRangesLastModifiedTime(), liveUpdateInterval = liveUpdateInterval()] (auto& client) {
+            client.bufferedTimeChanged(bufferedTime);
+            client.seekableRangesChanged(seekableRanges, seekableTimeRangesLastModifiedTime, liveUpdateInterval);
+        });
     }
 
     if (all
@@ -174,24 +182,17 @@ void PlaybackSessionModelMediaElement::updateForEventName(const WTF::AtomicStrin
 
     if (all
         || eventName == eventNames().webkitcurrentplaybacktargetiswirelesschangedEvent) {
-        bool enabled = externalPlaybackEnabled();
-        ExternalPlaybackTargetType targetType = externalPlaybackTargetType();
-        String localizedDeviceName = externalPlaybackLocalizedDeviceName();
-
-        bool wirelessVideoPlaybackDisabled = this->wirelessVideoPlaybackDisabled();
-
-        for (auto client : m_clients) {
-            client->externalPlaybackChanged(enabled, targetType, localizedDeviceName);
-            client->wirelessVideoPlaybackDisabledChanged(wirelessVideoPlaybackDisabled);
-        }
+        m_clients.forEachNonNullMember([enabled = externalPlaybackEnabled(), targetType = externalPlaybackTargetType(), localizedDeviceName = externalPlaybackLocalizedDeviceName(), wirelessVideoPlaybackDisabled = wirelessVideoPlaybackDisabled()] (auto& client) {
+            client.externalPlaybackChanged(enabled, targetType, localizedDeviceName);
+            client.wirelessVideoPlaybackDisabledChanged(wirelessVideoPlaybackDisabled);
+        });
     }
 
     if (all
         || eventName == eventNames().webkitpresentationmodechangedEvent) {
-        bool isPictureInPictureActive = this->isPictureInPictureActive();
-
-        for (auto client : m_clients)
-            client->pictureInPictureActiveChanged(isPictureInPictureActive);
+        m_clients.forEachNonNullMember([isPictureInPictureActive = isPictureInPictureActive()] (auto& client) {
+            client.pictureInPictureActiveChanged(isPictureInPictureActive);
+        });
     }
 
 
@@ -202,22 +203,20 @@ void PlaybackSessionModelMediaElement::updateForEventName(const WTF::AtomicStrin
 
     if (all
         || eventName == eventNames().volumechangeEvent) {
-        for (auto client : m_clients) {
-            client->mutedChanged(isMuted());
-            client->volumeChanged(volume());
-        }
+        m_clients.forEachNonNullMember([isMuted = isMuted(), volume = volume()] (auto& client) {
+            client.mutedChanged(isMuted);
+            client.volumeChanged(volume);
+        });
     }
 }
-void PlaybackSessionModelMediaElement::addClient(PlaybackSessionModelClient& client)
+void PlaybackSessionModelMediaElement::addClient(WeakPtr<PlaybackSessionModelClient>&& client)
 {
-    ASSERT(!m_clients.contains(&client));
-    m_clients.add(&client);
+    m_clients.add(WTFMove(client));
 }
 
 void PlaybackSessionModelMediaElement::removeClient(PlaybackSessionModelClient& client)
 {
-    ASSERT(m_clients.contains(&client));
-    m_clients.remove(&client);
+    m_clients.remove(client);
 }
 
 void PlaybackSessionModelMediaElement::play()
@@ -355,26 +354,18 @@ void PlaybackSessionModelMediaElement::updateMediaSelectionOptions()
     else
         m_audioTracksForMenu.clear();
 
-    auto audioOptions = audioMediaSelectionOptions();
-    auto audioIndex = audioMediaSelectedIndex();
-    auto legibleOptions = legibleMediaSelectionOptions();
-    auto legibleIndex = legibleMediaSelectedIndex();
-
-    for (auto client : m_clients) {
-        client->audioMediaSelectionOptionsChanged(audioOptions, audioIndex);
-        client->legibleMediaSelectionOptionsChanged(legibleOptions, legibleIndex);
-    }
+    m_clients.forEachNonNullMember([audioOptions = audioMediaSelectionOptions(), audioIndex = audioMediaSelectedIndex(), legibleOptions = legibleMediaSelectionOptions(), legibleIndex = legibleMediaSelectedIndex()] (auto& client) {
+        client.audioMediaSelectionOptionsChanged(audioOptions, audioIndex);
+        client.legibleMediaSelectionOptionsChanged(legibleOptions, legibleIndex);
+    });
 }
 
 void PlaybackSessionModelMediaElement::updateMediaSelectionIndices()
 {
-    auto audioIndex = audioMediaSelectedIndex();
-    auto legibleIndex = legibleMediaSelectedIndex();
-
-    for (auto client : m_clients) {
-        client->audioMediaSelectionIndexChanged(audioIndex);
-        client->legibleMediaSelectionIndexChanged(legibleIndex);
-    }
+    m_clients.forEachNonNullMember([audioIndex = audioMediaSelectedIndex(), legibleIndex = legibleMediaSelectedIndex()] (auto& client) {
+        client.audioMediaSelectionIndexChanged(audioIndex);
+        client.legibleMediaSelectionIndexChanged(legibleIndex);
+    });
 }
 
 double PlaybackSessionModelMediaElement::playbackStartedTime() const
index 4eb0580..4990813 100644 (file)
@@ -32,7 +32,7 @@ namespace WebCore {
 
 class VideoFullscreenChangeObserver {
 public:
-    virtual ~VideoFullscreenChangeObserver() { };
+    virtual ~VideoFullscreenChangeObserver() = default;
     virtual void requestUpdateInlineRect() = 0;
     virtual void requestVideoContentLayer() = 0;
     virtual void returnVideoContentLayer() = 0;
index ce51354..6d1b7e9 100644 (file)
@@ -30,7 +30,7 @@
 
 #include "FloatRect.h"
 #include "HTMLMediaElementEnums.h"
-#include "PlaybackSessionModel.h"
+#include <wtf/WeakPtr.h>
 
 #if PLATFORM(IOS)
 OBJC_CLASS AVPlayerViewController;
@@ -43,8 +43,15 @@ class VideoFullscreenModelClient;
 
 class VideoFullscreenModel {
 public:
-    virtual ~VideoFullscreenModel() { };
-    virtual void addClient(VideoFullscreenModelClient&) = 0;
+    virtual ~VideoFullscreenModel() = default;
+
+    void ref() { refVideoFullscreenModel(); }
+    void deref() { derefVideoFullscreenModel(); }
+
+    virtual void refVideoFullscreenModel() = 0;
+    virtual void derefVideoFullscreenModel() = 0;
+
+    virtual void addClient(WeakPtr<VideoFullscreenModelClient>&&) = 0;
     virtual void removeClient(VideoFullscreenModelClient&)= 0;
 
     virtual void requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenMode, bool finishedWithMedia = false) = 0;
index 037dd02..8268da5 100644 (file)
 
 #if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
 
-#include "EventListener.h"
 #include "FloatRect.h"
 #include "HTMLMediaElementEnums.h"
 #include "PlatformLayer.h"
 #include "VideoFullscreenModel.h"
 #include <wtf/Function.h>
-#include <wtf/HashSet.h>
 #include <wtf/RefPtr.h>
 #include <wtf/RetainPtr.h>
-#include <wtf/Vector.h>
+#include <wtf/WeakPtrContainer.h>
 
 namespace WebCore {
 class AudioTrack;
@@ -45,7 +43,10 @@ class HTMLVideoElement;
 class TextTrack;
 class PlaybackSessionModelMediaElement;
 
-class VideoFullscreenModelVideoElement : public VideoFullscreenModel, public EventListener {
+class VideoFullscreenModelVideoElement 
+    : public RefCounted<VideoFullscreenModelVideoElement>
+    , public CanMakeWeakPtr<VideoFullscreenModelVideoElement>
+    , public VideoFullscreenModel {
 public:
     static RefPtr<VideoFullscreenModelVideoElement> create()
     {
@@ -58,11 +59,9 @@ public:
     WEBCORE_EXPORT void willExitFullscreen();
     WEBCORE_EXPORT void waitForPreparedForInlineThen(WTF::Function<void()>&& completionHandler = [] { });
     
-    WEBCORE_EXPORT void handleEvent(WebCore::ScriptExecutionContext&, WebCore::Event&) override;
     void updateForEventName(const WTF::AtomicString&);
-    bool operator==(const EventListener& rhs) const override { return static_cast<const WebCore::EventListener*>(this) == &rhs; }
 
-    WEBCORE_EXPORT void addClient(VideoFullscreenModelClient&) override;
+    WEBCORE_EXPORT void addClient(WeakPtr<VideoFullscreenModelClient>&&) override;
     WEBCORE_EXPORT void removeClient(VideoFullscreenModelClient&) override;
     WEBCORE_EXPORT void requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenMode, bool finishedWithMedia = false) override;
     WEBCORE_EXPORT void setVideoLayerFrame(FloatRect) override;
@@ -72,6 +71,8 @@ public:
     FloatSize videoDimensions() const override { return m_videoDimensions; }
     bool hasVideo() const override { return m_hasVideo; }
 
+    using RefCounted::ref;
+    using RefCounted::deref;
 
 protected:
     WEBCORE_EXPORT VideoFullscreenModelVideoElement();
@@ -80,6 +81,8 @@ private:
     void setHasVideo(bool);
     void setVideoDimensions(const FloatSize&);
 
+    void refVideoFullscreenModel() final { ref(); }
+    void derefVideoFullscreenModel() final { deref(); }
     void willEnterPictureInPicture() override;
     void didEnterPictureInPicture() override;
     void failedToEnterPictureInPicture() override;
@@ -89,15 +92,17 @@ private:
     static const Vector<WTF::AtomicString>& observedEventNames();
     const WTF::AtomicString& eventNameAll();
 
+    class MediaElementEventListener;
+
     RefPtr<HTMLVideoElement> m_videoElement;
     RetainPtr<PlatformLayer> m_videoFullscreenLayer;
-    bool m_isListening { false };
-    HashSet<VideoFullscreenModelClient*> m_clients;
+    WeakPtrContainer<VideoFullscreenModelClient> m_clients;
     bool m_hasVideo { false };
     FloatSize m_videoDimensions;
     FloatRect m_videoFrame;
     Vector<RefPtr<TextTrack>> m_legibleTracksForMenu;
     Vector<RefPtr<AudioTrack>> m_audioTracksForMenu;
+    Ref<MediaElementEventListener> m_eventListener;
 };
 
 }
index 409f622..c315b65 100644 (file)
 
 namespace WebCore {
 
+
+class VideoFullscreenModelVideoElement::MediaElementEventListener final : public EventListener {
+public:
+    MediaElementEventListener(WeakPtr<VideoFullscreenModelVideoElement>&& parent)
+        : EventListener(CPPEventListenerType)
+        , m_parent(WTFMove(parent))
+    {
+    }
+private:
+    void handleEvent(WebCore::ScriptExecutionContext&, WebCore::Event& event) final
+    {
+        if (m_parent)
+            m_parent->updateForEventName(event.type());
+    }
+    bool operator==(const EventListener& rhs) const final { return static_cast<const WebCore::EventListener*>(this) == &rhs; }
+
+    WeakPtr<VideoFullscreenModelVideoElement> m_parent;
+};
+
 VideoFullscreenModelVideoElement::VideoFullscreenModelVideoElement()
-    : EventListener(EventListener::CPPEventListenerType)
+    : m_eventListener(adoptRef(*new MediaElementEventListener(makeWeakPtr(*this))))
 {
     LOG(Fullscreen, "VideoFullscreenModelVideoElement %p ctor", this);
 }
@@ -68,28 +87,21 @@ void VideoFullscreenModelVideoElement::setVideoElement(HTMLVideoElement* videoEl
     if (m_videoElement && m_videoElement->videoFullscreenLayer())
         m_videoElement->setVideoFullscreenLayer(nullptr);
 
-    if (m_videoElement && m_isListening) {
+    if (m_videoElement) {
         for (auto& eventName : observedEventNames())
-            m_videoElement->removeEventListener(eventName, *this, false);
+            m_videoElement->removeEventListener(eventName, m_eventListener.copyRef(), false);
     }
-    m_isListening = false;
 
     m_videoElement = videoElement;
 
     if (m_videoElement) {
         for (auto& eventName : observedEventNames())
-            m_videoElement->addEventListener(eventName, *this, false);
-        m_isListening = true;
+            m_videoElement->addEventListener(eventName, m_eventListener.copyRef(), false);
     }
 
     updateForEventName(eventNameAll());
 }
 
-void VideoFullscreenModelVideoElement::handleEvent(WebCore::ScriptExecutionContext&, WebCore::Event& event)
-{
-    updateForEventName(event.type());
-}
-
 void VideoFullscreenModelVideoElement::updateForEventName(const WTF::AtomicString& eventName)
 {
     if (m_clients.isEmpty())
@@ -199,16 +211,14 @@ void VideoFullscreenModelVideoElement::fullscreenModeChanged(HTMLMediaElementEnu
         m_videoElement->fullscreenModeChanged(videoFullscreenMode);
 }
 
-void VideoFullscreenModelVideoElement::addClient(VideoFullscreenModelClient& client)
+void VideoFullscreenModelVideoElement::addClient(WeakPtr<VideoFullscreenModelClient>&& client)
 {
-    ASSERT(!m_clients.contains(&client));
-    m_clients.add(&client);
+    m_clients.add(WTFMove(client));
 }
 
 void VideoFullscreenModelVideoElement::removeClient(VideoFullscreenModelClient& client)
 {
-    ASSERT(m_clients.contains(&client));
-    m_clients.remove(&client);
+    m_clients.remove(client);
 }
 
 bool VideoFullscreenModelVideoElement::isVisible() const
@@ -229,8 +239,9 @@ void VideoFullscreenModelVideoElement::setHasVideo(bool hasVideo)
 
     m_hasVideo = hasVideo;
 
-    for (auto& client : m_clients)
-        client->hasVideoChanged(m_hasVideo);
+    m_clients.forEachNonNullMember([hasVideo] (auto& client) {
+        client.hasVideoChanged(hasVideo);
+    });
 }
 
 void VideoFullscreenModelVideoElement::setVideoDimensions(const FloatSize& videoDimensions)
@@ -240,38 +251,44 @@ void VideoFullscreenModelVideoElement::setVideoDimensions(const FloatSize& video
 
     m_videoDimensions = videoDimensions;
 
-    for (auto& client : m_clients)
-        client->videoDimensionsChanged(m_videoDimensions);
+    m_clients.forEachNonNullMember([videoDimensions] (auto& client) {
+        client.videoDimensionsChanged(videoDimensions);
+    });
 }
 
 void VideoFullscreenModelVideoElement::willEnterPictureInPicture()
 {
-    for (auto& client : m_clients)
-        client->willEnterPictureInPicture();
+    m_clients.forEachNonNullMember([] (auto& client) {
+        client.willEnterPictureInPicture();
+    });
 }
 
 void VideoFullscreenModelVideoElement::didEnterPictureInPicture()
 {
-    for (auto& client : m_clients)
-        client->didEnterPictureInPicture();
+    m_clients.forEachNonNullMember([] (auto& client) {
+        client.didEnterPictureInPicture();
+    });
 }
 
 void VideoFullscreenModelVideoElement::failedToEnterPictureInPicture()
 {
-    for (auto& client : m_clients)
-        client->failedToEnterPictureInPicture();
+    m_clients.forEachNonNullMember([] (auto& client) {
+        client.failedToEnterPictureInPicture();
+    });
 }
 
 void VideoFullscreenModelVideoElement::willExitPictureInPicture()
 {
-    for (auto& client : m_clients)
-        client->willExitPictureInPicture();
+    m_clients.forEachNonNullMember([] (auto& client) {
+        client.willExitPictureInPicture();
+    });
 }
 
 void VideoFullscreenModelVideoElement::didExitPictureInPicture()
 {
-    for (auto& client : m_clients)
-        client->didExitPictureInPicture();
+    m_clients.forEachNonNullMember([] (auto& client) {
+        client.didExitPictureInPicture();
+    });
 }
 
 } // namespace WebCore
index 8580191..a574f58 100644 (file)
@@ -51,18 +51,14 @@ class IntRect;
 class PlaybackSessionModel;
 class WebPlaybackSessionChangeObserver;
 
-class WEBCORE_EXPORT PlaybackSessionInterfaceAVKit
+class PlaybackSessionInterfaceAVKit
     : public PlaybackSessionInterface
     , public PlaybackSessionModelClient
     , public RefCounted<PlaybackSessionInterfaceAVKit> {
-
 public:
-    static Ref<PlaybackSessionInterfaceAVKit> create(PlaybackSessionModel& model)
-    {
-        return adoptRef(*new PlaybackSessionInterfaceAVKit(model));
-    }
+    WEBCORE_EXPORT static Ref<PlaybackSessionInterfaceAVKit> create(Ref<PlaybackSessionModel>&&);
     virtual ~PlaybackSessionInterfaceAVKit();
-    PlaybackSessionModel* playbackSessionModel() const { return m_playbackSessionModel; }
+    PlaybackSessionModel& playbackSessionModel() const { return m_playbackSessionModel; }
 
     // PlaybackSessionInterface
     WEBCORE_EXPORT void resetMediaState() override;
@@ -81,15 +77,14 @@ public:
     WEBCORE_EXPORT void mutedChanged(bool) override;
     WEBCORE_EXPORT void volumeChanged(double) override;
 
-    WEBCORE_EXPORT virtual void invalidate();
-
     WebAVPlayerController *playerController() const { return m_playerController.get(); }
 
 protected:
-    WEBCORE_EXPORT PlaybackSessionInterfaceAVKit(PlaybackSessionModel&);
+    WEBCORE_EXPORT PlaybackSessionInterfaceAVKit(Ref<PlaybackSessionModel>&&);
 
     RetainPtr<WebAVPlayerController> m_playerController;
-    PlaybackSessionModel* m_playbackSessionModel { nullptr };
+    Ref<PlaybackSessionModel> m_playbackSessionModel;
+    WeakPtrFactory<PlaybackSessionModelClient> m_weakPtrFactory;
 };
 
 }
index 0a28548..ddb1631 100644 (file)
@@ -49,32 +49,36 @@ SOFT_LINK_CLASS_OPTIONAL(AVKit, AVValueTiming)
 namespace WebCore {
 using namespace PAL;
 
-PlaybackSessionInterfaceAVKit::PlaybackSessionInterfaceAVKit(PlaybackSessionModel& model)
+Ref<PlaybackSessionInterfaceAVKit> PlaybackSessionInterfaceAVKit::create(Ref<PlaybackSessionModel>&& model)
+{
+    auto interface = adoptRef(*new PlaybackSessionInterfaceAVKit(WTFMove(model)));
+    [interface->playerController() setPlaybackSessionInterface:interface.ptr()];
+    return interface;
+}
+
+PlaybackSessionInterfaceAVKit::PlaybackSessionInterfaceAVKit(Ref<PlaybackSessionModel>&& model)
     : m_playerController(adoptNS([[WebAVPlayerController alloc] init]))
-    , m_playbackSessionModel(&model)
+    , m_playbackSessionModel(WTFMove(model))
 {
-    model.addClient(*this);
-    [m_playerController setPlaybackSessionInterface:this];
-    [m_playerController setDelegate:&model];
+    m_playbackSessionModel->addClient(m_weakPtrFactory.createWeakPtr(*this));
 
-    durationChanged(model.duration());
-    currentTimeChanged(model.currentTime(), [[NSProcessInfo processInfo] systemUptime]);
-    bufferedTimeChanged(model.bufferedTime());
-    rateChanged(model.isPlaying(), model.playbackRate());
-    seekableRangesChanged(model.seekableRanges(), model.seekableTimeRangesLastModifiedTime(), model.liveUpdateInterval());
-    canPlayFastReverseChanged(model.canPlayFastReverse());
-    audioMediaSelectionOptionsChanged(model.audioMediaSelectionOptions(), model.audioMediaSelectedIndex());
-    legibleMediaSelectionOptionsChanged(model.legibleMediaSelectionOptions(), model.legibleMediaSelectedIndex());
-    externalPlaybackChanged(model.externalPlaybackEnabled(), model.externalPlaybackTargetType(), model.externalPlaybackLocalizedDeviceName());
-    wirelessVideoPlaybackDisabledChanged(model.wirelessVideoPlaybackDisabled());
+    durationChanged(m_playbackSessionModel->duration());
+    currentTimeChanged(m_playbackSessionModel->currentTime(), [[NSProcessInfo processInfo] systemUptime]);
+    bufferedTimeChanged(m_playbackSessionModel->bufferedTime());
+    rateChanged(m_playbackSessionModel->isPlaying(), m_playbackSessionModel->playbackRate());
+    seekableRangesChanged(m_playbackSessionModel->seekableRanges(), m_playbackSessionModel->seekableTimeRangesLastModifiedTime(), m_playbackSessionModel->liveUpdateInterval());
+    canPlayFastReverseChanged(m_playbackSessionModel->canPlayFastReverse());
+    audioMediaSelectionOptionsChanged(m_playbackSessionModel->audioMediaSelectionOptions(), m_playbackSessionModel->audioMediaSelectedIndex());
+    legibleMediaSelectionOptionsChanged(m_playbackSessionModel->legibleMediaSelectionOptions(), m_playbackSessionModel->legibleMediaSelectedIndex());
+    externalPlaybackChanged(m_playbackSessionModel->externalPlaybackEnabled(), m_playbackSessionModel->externalPlaybackTargetType(), m_playbackSessionModel->externalPlaybackLocalizedDeviceName());
+    wirelessVideoPlaybackDisabledChanged(m_playbackSessionModel->wirelessVideoPlaybackDisabled());
 }
 
 PlaybackSessionInterfaceAVKit::~PlaybackSessionInterfaceAVKit()
 {
+    m_playbackSessionModel->removeClient(*this);
     [m_playerController setPlaybackSessionInterface:nullptr];
     [m_playerController setExternalPlaybackActive:false];
-
-    invalidate();
 }
 
 void PlaybackSessionInterfaceAVKit::resetMediaState()
@@ -206,16 +210,6 @@ void PlaybackSessionInterfaceAVKit::volumeChanged(double volume)
     [m_playerController volumeChanged:volume];
 }
 
-void PlaybackSessionInterfaceAVKit::invalidate()
-{
-    if (!m_playbackSessionModel)
-        return;
-
-    [m_playerController setDelegate:nullptr];
-    m_playbackSessionModel->removeClient(*this);
-    m_playbackSessionModel = nullptr;
-}
-
 }
 
 #endif // HAVE(AVKIT)
index c6d2ead..8ee2a95 100644 (file)
@@ -40,6 +40,7 @@
 #include <wtf/RefPtr.h>
 #include <wtf/RetainPtr.h>
 #include <wtf/RunLoop.h>
+#include <wtf/WeakPtr.h>
 
 OBJC_CLASS UIViewController;
 OBJC_CLASS UIWindow;
@@ -64,12 +65,11 @@ class VideoFullscreenInterfaceAVKit final
     , public ThreadSafeRefCounted<VideoFullscreenInterfaceAVKit> {
 
 public:
-    WEBCORE_EXPORT static Ref<VideoFullscreenInterfaceAVKit> create(PlaybackSessionInterfaceAVKit&);
+    WEBCORE_EXPORT static Ref<VideoFullscreenInterfaceAVKit> create(Ref<PlaybackSessionInterfaceAVKit>&&, Ref<VideoFullscreenModel>&&);
     virtual ~VideoFullscreenInterfaceAVKit();
-    WEBCORE_EXPORT void setVideoFullscreenModel(VideoFullscreenModel*);
-    WEBCORE_EXPORT void setVideoFullscreenChangeObserver(VideoFullscreenChangeObserver*);
+    WEBCORE_EXPORT void setVideoFullscreenChangeObserver(WeakPtr<VideoFullscreenChangeObserver>);
     PlaybackSessionInterfaceAVKit& playbackSessionInterface() const { return m_playbackSessionInterface.get(); }
-    PlaybackSessionModel* playbackSessionModel() const { return m_playbackSessionInterface->playbackSessionModel(); }
+    PlaybackSessionModel& playbackSessionModel() const { return m_playbackSessionInterface->playbackSessionModel(); }
 
     // VideoFullscreenModelClient
     WEBCORE_EXPORT void hasVideoChanged(bool) final;
@@ -82,7 +82,6 @@ public:
     WEBCORE_EXPORT void enterFullscreen();
     WEBCORE_EXPORT void exitFullscreen(const IntRect& finalRect);
     WEBCORE_EXPORT void cleanupFullscreen();
-    WEBCORE_EXPORT void invalidate();
     WEBCORE_EXPORT void requestHideAndExitFullscreen();
     WEBCORE_EXPORT void preparedToReturnToInline(bool visible, const IntRect& inlineRect);
     WEBCORE_EXPORT void preparedToExitFullscreen();
@@ -131,7 +130,7 @@ public:
     Mode m_targetMode;
 #endif
 
-    VideoFullscreenModel* videoFullscreenModel() const { return m_videoFullscreenModel; }
+    VideoFullscreenModel& videoFullscreenModel() const { return m_videoFullscreenModel; }
     bool shouldExitFullscreenWithReason(ExitFullScreenReason);
     HTMLMediaElementEnums::VideoFullscreenMode mode() const { return m_currentMode.mode(); }
     bool allowsPictureInPicturePlayback() const { return m_allowsPictureInPicturePlayback; }
@@ -164,7 +163,7 @@ public:
 #endif
 
 protected:
-    WEBCORE_EXPORT VideoFullscreenInterfaceAVKit(PlaybackSessionInterfaceAVKit&);
+    WEBCORE_EXPORT VideoFullscreenInterfaceAVKit(Ref<PlaybackSessionInterfaceAVKit>&&, Ref<VideoFullscreenModel>&&);
 
 #if ENABLE(FULLSCREEN_API)
     void doSetup();
@@ -180,10 +179,10 @@ protected:
     WebAVPlayerController *playerController() const;
 
     Ref<PlaybackSessionInterfaceAVKit> m_playbackSessionInterface;
+    Ref<VideoFullscreenModel> m_videoFullscreenModel;
     RetainPtr<WebAVPlayerViewControllerDelegate> m_playerViewControllerDelegate;
     RetainPtr<WebAVPlayerViewController> m_playerViewController;
-    VideoFullscreenModel* m_videoFullscreenModel { nullptr };
-    VideoFullscreenChangeObserver* m_fullscreenChangeObserver { nullptr };
+    WeakPtr<VideoFullscreenChangeObserver> m_fullscreenChangeObserver;
 
     // These are only used when fullscreen is presented in a separate window.
     RetainPtr<UIWindow> m_window;
index 5cc320e..73244ee 100644 (file)
@@ -289,8 +289,7 @@ static VideoFullscreenInterfaceAVKit::ExitFullScreenReason convertToExitFullScre
     } else if ([getAVLayerVideoGravityResizeAspectFill() isEqualToString:self.videoGravity]) {
         sourceVideoFrame = smallestRectWithAspectRatioAroundRect(videoAspectRatio, self.modelVideoLayerFrame);
         self.modelVideoLayerFrame = CGRectMake(0, 0, sourceVideoFrame.width(), sourceVideoFrame.height());
-        if (auto* model = _fullscreenInterface->videoFullscreenModel())
-            model->setVideoLayerFrame(self.modelVideoLayerFrame);
+        _fullscreenInterface->videoFullscreenModel().setVideoLayerFrame(self.modelVideoLayerFrame);
         targetVideoFrame = smallestRectWithAspectRatioAroundRect(videoAspectRatio, self.bounds);
     } else
         ASSERT_NOT_REACHED();
@@ -325,8 +324,7 @@ static VideoFullscreenInterfaceAVKit::ExitFullScreenReason convertToExitFullScre
     
     if (!CGRectEqualToRect(self.modelVideoLayerFrame, [self bounds])) {
         self.modelVideoLayerFrame = [self bounds];
-        if (auto* model = _fullscreenInterface->videoFullscreenModel())
-            model->setVideoLayerFrame(self.modelVideoLayerFrame);
+        _fullscreenInterface->videoFullscreenModel().setVideoLayerFrame(self.modelVideoLayerFrame);
     }
     [(UIView *)[_videoSublayer delegate] setTransform:CGAffineTransformIdentity];
     
@@ -350,8 +348,7 @@ static VideoFullscreenInterfaceAVKit::ExitFullScreenReason convertToExitFullScre
     else
         ASSERT_NOT_REACHED();
     
-    if (auto* model = _fullscreenInterface->videoFullscreenModel())
-        model->setVideoLayerGravity(gravity);
+    _fullscreenInterface->videoFullscreenModel().setVideoLayerGravity(gravity);
 }
 
 - (NSString *)videoGravity
@@ -725,15 +722,16 @@ NS_ASSUME_NONNULL_END
 }
 @end
 
-Ref<VideoFullscreenInterfaceAVKit> VideoFullscreenInterfaceAVKit::create(PlaybackSessionInterfaceAVKit& playbackSessionInterface)
+Ref<VideoFullscreenInterfaceAVKit> VideoFullscreenInterfaceAVKit::create(Ref<PlaybackSessionInterfaceAVKit>&& playbackSessionInterface, Ref<VideoFullscreenModel>&& videoFullscreenModel)
 {
-    Ref<VideoFullscreenInterfaceAVKit> interface = adoptRef(*new VideoFullscreenInterfaceAVKit(playbackSessionInterface));
+    Ref<VideoFullscreenInterfaceAVKit> interface = adoptRef(*new VideoFullscreenInterfaceAVKit(WTFMove(playbackSessionInterface), WTFMove(videoFullscreenModel)));
     [interface->m_playerViewControllerDelegate setFullscreenInterface:interface.ptr()];
     return interface;
 }
 
-VideoFullscreenInterfaceAVKit::VideoFullscreenInterfaceAVKit(PlaybackSessionInterfaceAVKit& playbackSessionInterface)
-    : m_playbackSessionInterface(playbackSessionInterface)
+VideoFullscreenInterfaceAVKit::VideoFullscreenInterfaceAVKit(Ref<PlaybackSessionInterfaceAVKit>&& playbackSessionInterface, Ref<VideoFullscreenModel>&& videoFullscreenModel)
+    : m_playbackSessionInterface(WTFMove(playbackSessionInterface))
+    , m_videoFullscreenModel(WTFMove(videoFullscreenModel))
     , m_playerViewControllerDelegate(adoptNS([[WebAVPlayerViewControllerDelegate alloc] init]))
     , m_watchdogTimer(RunLoop::main(), this, &VideoFullscreenInterfaceAVKit::watchdogTimerFired)
 {
@@ -744,8 +742,7 @@ VideoFullscreenInterfaceAVKit::~VideoFullscreenInterfaceAVKit()
     WebAVPlayerController* playerController = this->playerController();
     if (playerController && playerController.externalPlaybackActive)
         externalPlaybackChanged(false, PlaybackSessionModel::TargetTypeNone, "");
-    if (m_videoFullscreenModel)
-        m_videoFullscreenModel->removeClient(*this);
+    videoFullscreenModel().removeClient(*this);
 }
 
 WebAVPlayerController *VideoFullscreenInterfaceAVKit::playerController() const
@@ -753,21 +750,7 @@ WebAVPlayerController *VideoFullscreenInterfaceAVKit::playerController() const
     return m_playbackSessionInterface->playerController();
 }
 
-void VideoFullscreenInterfaceAVKit::setVideoFullscreenModel(VideoFullscreenModel* model)
-{
-    if (m_videoFullscreenModel)
-        m_videoFullscreenModel->removeClient(*this);
-
-    m_videoFullscreenModel = model;
-
-    if (m_videoFullscreenModel)
-        m_videoFullscreenModel->addClient(*this);
-
-    hasVideoChanged(m_videoFullscreenModel ? m_videoFullscreenModel->hasVideo() : false);
-    videoDimensionsChanged(m_videoFullscreenModel ? m_videoFullscreenModel->videoDimensions() : FloatSize());
-}
-
-void VideoFullscreenInterfaceAVKit::setVideoFullscreenChangeObserver(VideoFullscreenChangeObserver* observer)
+void VideoFullscreenInterfaceAVKit::setVideoFullscreenChangeObserver(WeakPtr<VideoFullscreenChangeObserver> observer)
 {
     m_fullscreenChangeObserver = observer;
 }
@@ -807,7 +790,7 @@ bool VideoFullscreenInterfaceAVKit::pictureInPictureWasStartedWhenEnteringBackgr
 void VideoFullscreenInterfaceAVKit::applicationDidBecomeActive()
 {
     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::applicationDidBecomeActive(%p)", this);
-    if (m_shouldReturnToFullscreenAfterEnteringForeground && m_videoFullscreenModel && m_videoFullscreenModel->isVisible()) {
+    if (m_shouldReturnToFullscreenAfterEnteringForeground && videoFullscreenModel().isVisible()) {
         [m_playerViewController stopPictureInPicture];
         return;
     }
@@ -884,7 +867,7 @@ void VideoFullscreenInterfaceAVKit::setupFullscreen(UIView& videoView, const Int
     [playerController() setPictureInPicturePossible:m_allowsPictureInPicturePlayback];
 
 #if PLATFORM(WATCHOS)
-    m_viewController = videoFullscreenModel()->createVideoFullscreenViewController(m_playerViewController.get().avPlayerViewController);
+    m_viewController = videoFullscreenModel().createVideoFullscreenViewController(m_playerViewController.get().avPlayerViewController);
 #endif
 
     if (m_viewController) {
@@ -949,7 +932,7 @@ static UIViewController *fallbackViewController(UIView *view)
 
 UIViewController *VideoFullscreenInterfaceAVKit::presentingViewController()
 {
-    auto *controller = videoFullscreenModel()->presentingViewController();
+    auto *controller = videoFullscreenModel().presentingViewController();
     if (!controller)
         controller = fallbackViewController(m_parentView.get());
 
@@ -1077,14 +1060,6 @@ void VideoFullscreenInterfaceAVKit::cleanupFullscreen()
     m_enterRequested = false;
 }
 
-void VideoFullscreenInterfaceAVKit::invalidate()
-{
-    m_videoFullscreenModel = nil;
-    m_fullscreenChangeObserver = nil;
-    
-    cleanupFullscreen();
-}
-
 void VideoFullscreenInterfaceAVKit::requestHideAndExitFullscreen()
 {
     if (!m_enterRequested)
@@ -1098,9 +1073,9 @@ void VideoFullscreenInterfaceAVKit::requestHideAndExitFullscreen()
     [m_window setHidden:YES];
     [[m_playerViewController view] setHidden:YES];
 
-    if (playbackSessionModel() && m_videoFullscreenModel && !m_exitRequested) {
-        playbackSessionModel()->pause();
-        m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
+    if (!m_exitRequested) {
+        playbackSessionModel().pause();
+        videoFullscreenModel().requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
     }
 }
 
@@ -1120,7 +1095,7 @@ void VideoFullscreenInterfaceAVKit::preparedToExitFullscreen()
         return;
 
     m_waitingForPreparedToExit = false;
-    m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone, true);
+    videoFullscreenModel().requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone, true);
 }
 
 bool VideoFullscreenInterfaceAVKit::mayAutomaticallyShowVideoPictureInPicture() const
@@ -1139,8 +1114,7 @@ void VideoFullscreenInterfaceAVKit::willStartPictureInPicture()
 {
     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::willStartPictureInPicture(%p)", this);
     setMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
-    if (m_videoFullscreenModel)
-        m_videoFullscreenModel->willEnterPictureInPicture();
+    videoFullscreenModel().willEnterPictureInPicture();
 }
 
 void VideoFullscreenInterfaceAVKit::didStartPictureInPicture()
@@ -1166,8 +1140,7 @@ void VideoFullscreenInterfaceAVKit::didStartPictureInPicture()
 
     if (m_fullscreenChangeObserver)
         m_fullscreenChangeObserver->didEnterFullscreen();
-    if (m_videoFullscreenModel)
-        m_videoFullscreenModel->didEnterPictureInPicture();
+    videoFullscreenModel().didEnterPictureInPicture();
 }
 
 void VideoFullscreenInterfaceAVKit::failedToStartPictureInPicture()
@@ -1182,11 +1155,8 @@ void VideoFullscreenInterfaceAVKit::failedToStartPictureInPicture()
 
     if (m_fullscreenChangeObserver)
         m_fullscreenChangeObserver->didEnterFullscreen();
-    if (m_videoFullscreenModel)
-        m_videoFullscreenModel->failedToEnterPictureInPicture();
-
-    if (m_videoFullscreenModel)
-        m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
+    videoFullscreenModel().failedToEnterPictureInPicture();
+    videoFullscreenModel().requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
 }
 
 void VideoFullscreenInterfaceAVKit::willStopPictureInPicture()
@@ -1202,10 +1172,8 @@ void VideoFullscreenInterfaceAVKit::willStopPictureInPicture()
     [m_window setHidden:NO];
     [[m_playerViewController view] setHidden:NO];
 
-    if (m_videoFullscreenModel)
-        m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
-    if (m_videoFullscreenModel)
-        m_videoFullscreenModel->willExitPictureInPicture();
+    videoFullscreenModel().requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
+    videoFullscreenModel().willExitPictureInPicture();
 }
 
 void VideoFullscreenInterfaceAVKit::didStopPictureInPicture()
@@ -1228,8 +1196,7 @@ void VideoFullscreenInterfaceAVKit::didStopPictureInPicture()
 
     if (m_fullscreenChangeObserver)
         m_fullscreenChangeObserver->didExitFullscreen();
-    if (m_videoFullscreenModel)
-        m_videoFullscreenModel->didExitPictureInPicture();
+    videoFullscreenModel().didExitPictureInPicture();
 }
 
 void VideoFullscreenInterfaceAVKit::prepareForPictureInPictureStopWithCompletionHandler(void (^completionHandler)(BOOL restored))
@@ -1266,9 +1233,6 @@ void VideoFullscreenInterfaceAVKit::prepareForPictureInPictureStopWithCompletion
 
 bool VideoFullscreenInterfaceAVKit::shouldExitFullscreenWithReason(VideoFullscreenInterfaceAVKit::ExitFullScreenReason reason)
 {
-    if (!m_videoFullscreenModel)
-        return true;
-
     if (reason == ExitFullScreenReason::PictureInPictureStarted) {
         if (pictureInPictureWasStartedWhenEnteringBackground())
             return false;
@@ -1278,8 +1242,8 @@ bool VideoFullscreenInterfaceAVKit::shouldExitFullscreenWithReason(VideoFullscre
         return true;
     }
 
-    if (playbackSessionModel() && (reason == ExitFullScreenReason::DoneButtonTapped || reason == ExitFullScreenReason::RemoteControlStopEventReceived))
-        playbackSessionModel()->pause();
+    if (reason == ExitFullScreenReason::DoneButtonTapped || reason == ExitFullScreenReason::RemoteControlStopEventReceived)
+        playbackSessionModel().pause();
 
     if (!m_watchdogTimer.isActive() && !ignoreWatchdogForDebugging)
         m_watchdogTimer.startOneShot(defaultWatchdogTimerInterval);
@@ -1293,7 +1257,7 @@ bool VideoFullscreenInterfaceAVKit::shouldExitFullscreenWithReason(VideoFullscre
 #endif
 
     BOOL finished = reason == ExitFullScreenReason::DoneButtonTapped || reason == ExitFullScreenReason::PinchGestureHandled;
-    m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone, finished);
+    videoFullscreenModel().requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone, finished);
 
     return false;
 }
@@ -1385,14 +1349,6 @@ void VideoFullscreenInterfaceAVKit::cleanupFullscreen()
         m_fullscreenChangeObserver->didCleanupFullscreen();
 }
 
-void VideoFullscreenInterfaceAVKit::invalidate()
-{
-    m_videoFullscreenModel = nil;
-    m_fullscreenChangeObserver = nil;
-    
-    cleanupFullscreen();
-}
-
 void VideoFullscreenInterfaceAVKit::requestHideAndExitFullscreen()
 {
     if (m_currentMode.hasPictureInPicture())
@@ -1403,10 +1359,8 @@ void VideoFullscreenInterfaceAVKit::requestHideAndExitFullscreen()
     [m_window setHidden:YES];
     [[m_playerViewController view] setHidden:YES];
 
-    if (playbackSessionModel() && m_videoFullscreenModel) {
-        playbackSessionModel()->pause();
-        m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
-    }
+    playbackSessionModel().pause();
+    videoFullscreenModel().requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
 }
 
 void VideoFullscreenInterfaceAVKit::preparedToReturnToInline(bool visible, const IntRect& inlineRect)
@@ -1445,8 +1399,7 @@ void VideoFullscreenInterfaceAVKit::willStartPictureInPicture()
 
     if (!m_hasVideoContentLayer)
         m_fullscreenChangeObserver->requestVideoContentLayer();
-    if (m_videoFullscreenModel)
-        m_videoFullscreenModel->willEnterPictureInPicture();
+    videoFullscreenModel().willEnterPictureInPicture();
 }
 
 void VideoFullscreenInterfaceAVKit::didStartPictureInPicture()
@@ -1466,8 +1419,7 @@ void VideoFullscreenInterfaceAVKit::didStartPictureInPicture()
         [[m_playerViewController view] setHidden:YES];
     }
 
-    if (m_videoFullscreenModel)
-        m_videoFullscreenModel->didEnterPictureInPicture();
+    videoFullscreenModel().didEnterPictureInPicture();
 
     if (m_enterFullscreenNeedsEnterPictureInPicture)
         doEnterFullscreen();
@@ -1485,11 +1437,8 @@ void VideoFullscreenInterfaceAVKit::failedToStartPictureInPicture()
     if (m_fullscreenChangeObserver)
         m_fullscreenChangeObserver->didEnterFullscreen();
 
-    if (m_videoFullscreenModel)
-        m_videoFullscreenModel->failedToEnterPictureInPicture();
-
-    if (m_videoFullscreenModel)
-        m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
+    videoFullscreenModel().failedToEnterPictureInPicture();
+    videoFullscreenModel().requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
 }
 
 void VideoFullscreenInterfaceAVKit::willStopPictureInPicture()
@@ -1504,8 +1453,7 @@ void VideoFullscreenInterfaceAVKit::willStopPictureInPicture()
     [m_window setHidden:NO];
     [[m_playerViewController view] setHidden:NO];
 
-    if (m_videoFullscreenModel)
-        m_videoFullscreenModel->willExitPictureInPicture();
+    videoFullscreenModel().willExitPictureInPicture();
 }
 
 void VideoFullscreenInterfaceAVKit::didStopPictureInPicture()
@@ -1525,13 +1473,11 @@ void VideoFullscreenInterfaceAVKit::didStopPictureInPicture()
     [m_playerLayerView setBackgroundColor:clearUIColor()];
     [[m_playerViewController view] setBackgroundColor:clearUIColor()];
 
-    if (m_videoFullscreenModel)
-        m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
+    videoFullscreenModel().requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
 
     clearMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
 
-    if (m_videoFullscreenModel)
-        m_videoFullscreenModel->didExitPictureInPicture();
+    videoFullscreenModel().didExitPictureInPicture();
 
     if (m_enterFullscreenNeedsExitPictureInPicture)
         doEnterFullscreen();
@@ -1567,17 +1513,14 @@ void VideoFullscreenInterfaceAVKit::prepareForPictureInPictureStopWithCompletion
 
 bool VideoFullscreenInterfaceAVKit::shouldExitFullscreenWithReason(VideoFullscreenInterfaceAVKit::ExitFullScreenReason reason)
 {
-    if (!m_videoFullscreenModel)
-        return true;
-
     if (reason == ExitFullScreenReason::PictureInPictureStarted)
         return false;
 
-    if (playbackSessionModel() && (reason == ExitFullScreenReason::DoneButtonTapped || reason == ExitFullScreenReason::RemoteControlStopEventReceived))
-        playbackSessionModel()->pause();
+    if (reason == ExitFullScreenReason::DoneButtonTapped || reason == ExitFullScreenReason::RemoteControlStopEventReceived)
+        playbackSessionModel().pause();
 
     BOOL finished = reason == ExitFullScreenReason::DoneButtonTapped || reason == ExitFullScreenReason::PinchGestureHandled;
-    m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone, finished);
+    videoFullscreenModel().requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone, finished);
 
     if (!m_watchdogTimer.isActive() && !ignoreWatchdogForDebugging)
         m_watchdogTimer.startOneShot(defaultWatchdogTimerInterval);
@@ -1672,8 +1615,7 @@ void VideoFullscreenInterfaceAVKit::doSetup()
     [playerLayer setModelVideoLayerFrame:modelVideoLayerFrame];
     [playerLayer setVideoDimensions:[playerController() contentDimensions]];
     playerLayer.fullscreenInterface = this;
-    if (m_videoFullscreenModel)
-        m_videoFullscreenModel->setVideoLayerFrame(modelVideoLayerFrame);
+    videoFullscreenModel().setVideoLayerFrame(modelVideoLayerFrame);
 
     if (!m_playerViewController)
         m_playerViewController = adoptNS([[WebAVPlayerViewController alloc] initWithFullscreenInterface:this]);
@@ -1685,7 +1627,7 @@ void VideoFullscreenInterfaceAVKit::doSetup()
     [playerController() setPictureInPicturePossible:m_allowsPictureInPicturePlayback];
 
 #if PLATFORM(WATCHOS)
-    m_viewController = videoFullscreenModel()->createVideoFullscreenViewController(m_playerViewController.get().avPlayerViewController);
+    m_viewController = videoFullscreenModel().createVideoFullscreenViewController(m_playerViewController.get().avPlayerViewController);
 #endif
 
     if (m_viewController) {
@@ -1892,8 +1834,7 @@ void VideoFullscreenInterfaceAVKit::setMode(HTMLMediaElementEnums::VideoFullscre
         return;
 
     m_currentMode.setMode(mode);
-    if (m_videoFullscreenModel)
-        m_videoFullscreenModel->fullscreenModeChanged(m_currentMode.mode());
+    videoFullscreenModel().fullscreenModeChanged(m_currentMode.mode());
 }
 
 void VideoFullscreenInterfaceAVKit::clearMode(HTMLMediaElementEnums::VideoFullscreenMode mode)
@@ -1902,8 +1843,7 @@ void VideoFullscreenInterfaceAVKit::clearMode(HTMLMediaElementEnums::VideoFullsc
         return;
 
     m_currentMode.clearMode(mode);
-    if (m_videoFullscreenModel)
-        m_videoFullscreenModel->fullscreenModeChanged(m_currentMode.mode());
+    videoFullscreenModel().fullscreenModeChanged(m_currentMode.mode());
 }
 
 bool VideoFullscreenInterfaceAVKit::isPlayingVideoInEnhancedFullscreen() const
index a45346c..1e78ab0 100644 (file)
@@ -26,6 +26,7 @@
 #if PLATFORM(IOS) && HAVE(AVKIT)
 
 #import <pal/spi/cocoa/AVKitSPI.h>
+#import <wtf/WeakPtr.h>
 
 namespace WebCore {
 class PlaybackSessionModel;
@@ -39,13 +40,14 @@ class PlaybackSessionInterfaceAVKit;
 @interface WebAVPlayerController : NSObject {
     WebAVMediaSelectionOption *_currentAudioMediaSelectionOption;
     WebAVMediaSelectionOption *_currentLegibleMediaSelectionOption;
+    RefPtr<WebCore::PlaybackSessionInterfaceAVKit> _playbackSessionInterface;
     BOOL _pictureInPictureInterrupted;
     BOOL _muted;
 }
 
 @property (retain) AVPlayerController* playerControllerProxy;
-@property (assign) WebCore::PlaybackSessionModel* delegate;
-@property (assign) WebCore::PlaybackSessionInterfaceAVKit* playbackSessionInterface;
+@property (readonly) WebCore::PlaybackSessionModel* delegate;
+@property WebCore::PlaybackSessionInterfaceAVKit* playbackSessionInterface;
 
 @property (readonly) BOOL canScanForward;
 @property BOOL canScanBackward;
index 3721800..6f24ab2 100644 (file)
@@ -97,6 +97,23 @@ static double WebAVPlayerControllerLiveStreamSeekableTimeRangeMinimumDuration =
     [super dealloc];
 }
 
+@dynamic delegate;
+- (WebCore::PlaybackSessionModel*)delegate
+{
+    return _playbackSessionInterface ? &_playbackSessionInterface->playbackSessionModel() : nullptr;
+}
+
+@dynamic playbackSessionInterface;
+- (WebCore::PlaybackSessionInterfaceAVKit*)playbackSessionInterface
+{
+    return _playbackSessionInterface.get();
+}
+
+- (void)setPlaybackSessionInterface:(WebCore::PlaybackSessionInterfaceAVKit*)playbackSessionInterface
+{
+    _playbackSessionInterface = playbackSessionInterface;
+}
+
 - (AVPlayer *)player
 {
     return nil;
index d43b87c..b705ab3 100644 (file)
@@ -99,11 +99,11 @@ class VideoFullscreenControllerContext;
 @end
 
 class VideoFullscreenControllerContext final
-    : private VideoFullscreenModel
-    , private VideoFullscreenModelClient
-    , private VideoFullscreenChangeObserver
+    : public VideoFullscreenModel
+    , public VideoFullscreenModelClient
+    , public VideoFullscreenChangeObserver
     , private PlaybackSessionModel
-    , private PlaybackSessionModelClient
+    , public PlaybackSessionModelClient
     , public ThreadSafeRefCounted<VideoFullscreenControllerContext> {
 
 public:
@@ -118,6 +118,9 @@ public:
     void requestHideAndExitFullscreen();
     void invalidate();
 
+    using ThreadSafeRefCounted::ref;
+    using ThreadSafeRefCounted::deref;
+
 private:
     VideoFullscreenControllerContext() { }
 
@@ -137,7 +140,9 @@ private:
     void videoDimensionsChanged(const FloatSize&) override;
 
     // PlaybackSessionModel
-    void addClient(PlaybackSessionModelClient&) override;
+    void refPlaybackSessionModel() final { ref(); }
+    void derefPlaybackSessionModel() final { deref(); }
+    void addClient(WeakPtr<PlaybackSessionModelClient>&&) override;
     void removeClient(PlaybackSessionModelClient&) override;
     void play() override;
     void pause() override;
@@ -191,7 +196,9 @@ private:
     void volumeChanged(double) override;
 
     // VideoFullscreenModel
-    void addClient(VideoFullscreenModelClient&) override;
+    void refVideoFullscreenModel() final { ref(); }
+    void derefVideoFullscreenModel() final { deref(); }
+    void addClient(WeakPtr<VideoFullscreenModelClient>&&) override;
     void removeClient(VideoFullscreenModelClient&) override;
     void requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenMode, bool finishedWithMedia = false) override;
     void setVideoLayerFrame(FloatRect) override;
@@ -210,14 +217,17 @@ private:
     void willExitPictureInPicture() final;
     void didExitPictureInPicture() final;
 
-    HashSet<PlaybackSessionModelClient*> m_playbackClients;
-    HashSet<VideoFullscreenModelClient*> m_fullscreenClients;
+    Vector<WeakPtr<PlaybackSessionModelClient>> m_playbackClients;
+    Vector<WeakPtr<VideoFullscreenModelClient>> m_fullscreenClients;
     RefPtr<VideoFullscreenInterfaceAVKit> m_interface;
     RefPtr<VideoFullscreenModelVideoElement> m_fullscreenModel;
     RefPtr<PlaybackSessionModelMediaElement> m_playbackModel;
     RefPtr<HTMLVideoElement> m_videoElement;
     RetainPtr<UIView> m_videoFullscreenView;
     RetainPtr<WebVideoFullscreenController> m_controller;
+    WeakPtrFactory<PlaybackSessionModelClient> m_playbackClientFactory;
+    WeakPtrFactory<VideoFullscreenModelClient> m_fullscreenModelClientFactory;
+    WeakPtrFactory<VideoFullscreenChangeObserver> m_fullscreenChangeObserverFactory;
 };
 
 #pragma mark VideoFullscreenChangeObserver
@@ -321,8 +331,6 @@ void VideoFullscreenControllerContext::didExitFullscreen()
 void VideoFullscreenControllerContext::didCleanupFullscreen()
 {
     ASSERT(isUIThread());
-    m_interface->setVideoFullscreenModel(nullptr);
-    m_interface->setVideoFullscreenChangeObserver(nullptr);
     m_interface = nullptr;
     m_videoFullscreenView = nil;
 
@@ -331,6 +339,7 @@ void VideoFullscreenControllerContext::didCleanupFullscreen()
         m_fullscreenModel->setVideoElement(nullptr);
         m_playbackModel->setMediaElement(nullptr);
         m_playbackModel->removeClient(*this);
+        m_playbackModel = nullptr;
         m_fullscreenModel->removeClient(*this);
         m_fullscreenModel = nullptr;
         m_videoElement = nullptr;
@@ -545,16 +554,16 @@ void VideoFullscreenControllerContext::volumeChanged(double volume)
 }
 #pragma mark VideoFullscreenModel
 
-void VideoFullscreenControllerContext::addClient(VideoFullscreenModelClient& client)
+void VideoFullscreenControllerContext::addClient(WeakPtr<VideoFullscreenModelClient>&& client)
 {
-    ASSERT(!m_fullscreenClients.contains(&client));
-    m_fullscreenClients.add(&client);
+    ASSERT(!m_fullscreenClients.contains(client));
+    m_fullscreenClients.append(WTFMove(client));
 }
 
 void VideoFullscreenControllerContext::removeClient(VideoFullscreenModelClient& client)
 {
     ASSERT(m_fullscreenClients.contains(&client));
-    m_fullscreenClients.remove(&client);
+    m_fullscreenClients.removeAll(&client);
 }
 
 void VideoFullscreenControllerContext::requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenMode mode, bool finishedWithMedia)
@@ -644,35 +653,35 @@ bool VideoFullscreenControllerContext::isPictureInPictureSupported() const
 void VideoFullscreenControllerContext::willEnterPictureInPicture()
 {
     ASSERT(isUIThread());
-    for (auto* client : m_fullscreenClients)
+    for (auto& client : m_fullscreenClients)
         client->willEnterPictureInPicture();
 }
 
 void VideoFullscreenControllerContext::didEnterPictureInPicture()
 {
     ASSERT(isUIThread());
-    for (auto* client : m_fullscreenClients)
+    for (auto& client : m_fullscreenClients)
         client->didEnterPictureInPicture();
 }
 
 void VideoFullscreenControllerContext::failedToEnterPictureInPicture()
 {
     ASSERT(isUIThread());
-    for (auto* client : m_fullscreenClients)
+    for (auto& client : m_fullscreenClients)
         client->failedToEnterPictureInPicture();
 }
 
 void VideoFullscreenControllerContext::willExitPictureInPicture()
 {
     ASSERT(isUIThread());
-    for (auto* client : m_fullscreenClients)
+    for (auto& client : m_fullscreenClients)
         client->willExitPictureInPicture();
 }
 
 void VideoFullscreenControllerContext::didExitPictureInPicture()
 {
     ASSERT(isUIThread());
-    for (auto* client : m_fullscreenClients)
+    for (auto& client : m_fullscreenClients)
         client->didExitPictureInPicture();
 }
 
@@ -684,16 +693,16 @@ FloatSize VideoFullscreenControllerContext::videoDimensions() const
 
 #pragma mark - PlaybackSessionModel
 
-void VideoFullscreenControllerContext::addClient(PlaybackSessionModelClient& client)
+void VideoFullscreenControllerContext::addClient(WeakPtr<PlaybackSessionModelClient>&& client)
 {
-    ASSERT(!m_playbackClients.contains(&client));
-    m_playbackClients.add(&client);
+    ASSERT(!m_playbackClients.contains(client));
+    m_playbackClients.append(WTFMove(client));
 }
 
 void VideoFullscreenControllerContext::removeClient(PlaybackSessionModelClient& client)
 {
     ASSERT(m_playbackClients.contains(&client));
-    m_playbackClients.remove(&client);
+    m_playbackClients.removeAll(&client);
 }
 
 void VideoFullscreenControllerContext::play()
@@ -954,11 +963,11 @@ void VideoFullscreenControllerContext::setUpFullscreen(HTMLVideoElement& videoEl
     RetainPtr<UIView> viewRef = view;
     m_videoElement = &videoElement;
     m_playbackModel = PlaybackSessionModelMediaElement::create();
-    m_playbackModel->addClient(*this);
+    m_playbackModel->addClient(m_playbackClientFactory.createWeakPtr(*this));
     m_playbackModel->setMediaElement(m_videoElement.get());
 
     m_fullscreenModel = VideoFullscreenModelVideoElement::create();
-    m_fullscreenModel->addClient(*this);
+    m_fullscreenModel->addClient(m_fullscreenModelClientFactory.createWeakPtr(*this));
     m_fullscreenModel->setVideoElement(m_videoElement.get());
 
     bool allowsPictureInPicture = m_videoElement->webkitSupportsPresentationMode(HTMLVideoElement::VideoPresentationMode::PictureInPicture);
@@ -971,10 +980,8 @@ void VideoFullscreenControllerContext::setUpFullscreen(HTMLVideoElement& videoEl
         ASSERT(isUIThread());
 
         Ref<PlaybackSessionInterfaceAVKit> sessionInterface = PlaybackSessionInterfaceAVKit::create(*this);
-        m_interface = VideoFullscreenInterfaceAVKit::create(sessionInterface.get());
-        m_interface->setVideoFullscreenChangeObserver(this);
-        m_interface->setVideoFullscreenModel(this);
-        m_interface->setVideoFullscreenChangeObserver(this);
+        m_interface = VideoFullscreenInterfaceAVKit::create(sessionInterface.get(), *this);
+        m_interface->setVideoFullscreenChangeObserver(m_fullscreenChangeObserverFactory.createWeakPtr(*this));
 
         m_videoFullscreenView = adoptNS([allocUIViewInstance() init]);
 
index e7db397..439a19e 100644 (file)
@@ -45,9 +45,9 @@ class WEBCORE_EXPORT PlaybackSessionInterfaceMac final
     , public PlaybackSessionModelClient
     , public RefCounted<PlaybackSessionInterfaceMac> {
 public:
-    static Ref<PlaybackSessionInterfaceMac> create(PlaybackSessionModel&);
-    virtual ~PlaybackSessionInterfaceMac();
-    PlaybackSessionModel* playbackSessionModel() const;
+    static Ref<PlaybackSessionInterfaceMac> create(Ref<PlaybackSessionModel>&&);
+    virtual ~PlaybackSessionInterfaceMac() = default;
+    PlaybackSessionModel& playbackSessionModel() const;
 
     // PlaybackSessionInterface
     void resetMediaState() final;
@@ -64,7 +64,6 @@ public:
     void externalPlaybackChanged(bool /* enabled */, PlaybackSessionModel::ExternalPlaybackTargetType, const String& /* localizedDeviceName */) final;
     void isPictureInPictureSupportedChanged(bool) final;
 
-    void invalidate();
     void ensureControlsManager();
 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
     void setPlayBackControlsManager(WebPlaybackControlsManager *);
@@ -76,8 +75,9 @@ public:
     void endScrubbing();
 
 private:
-    PlaybackSessionInterfaceMac(PlaybackSessionModel&);
-    PlaybackSessionModel* m_playbackSessionModel { nullptr };
+    PlaybackSessionInterfaceMac(Ref<PlaybackSessionModel>&&);
+    Ref<PlaybackSessionModel> m_playbackSessionModel;
+    WeakPtrFactory<PlaybackSessionModelClient> m_weakPtrFactory;
 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
     WebPlaybackControlsManager *m_playbackControlsManager  { nullptr };
 
index b86266d..b8aa93a 100644 (file)
@@ -44,24 +44,18 @@ SOFT_LINK_CLASS_OPTIONAL(AVKit, AVValueTiming)
 
 namespace WebCore {
 
-Ref<PlaybackSessionInterfaceMac> PlaybackSessionInterfaceMac::create(PlaybackSessionModel& model)
+Ref<PlaybackSessionInterfaceMac> PlaybackSessionInterfaceMac::create(Ref<PlaybackSessionModel>&& model)
 {
-    auto interface = adoptRef(*new PlaybackSessionInterfaceMac(model));
-    model.addClient(interface);
-    return interface;
+    return adoptRef(*new PlaybackSessionInterfaceMac(WTFMove(model)));
 }
 
-PlaybackSessionInterfaceMac::PlaybackSessionInterfaceMac(PlaybackSessionModel& model)
-    : m_playbackSessionModel(&model)
+PlaybackSessionInterfaceMac::PlaybackSessionInterfaceMac(Ref<PlaybackSessionModel>&& model)
+    : m_playbackSessionModel(WTFMove(model))
 {
+    playbackSessionModel().addClient(m_weakPtrFactory.createWeakPtr(*this));
 }
 
-PlaybackSessionInterfaceMac::~PlaybackSessionInterfaceMac()
-{
-    invalidate();
-}
-
-PlaybackSessionModel* PlaybackSessionInterfaceMac::playbackSessionModel() const
+PlaybackSessionModel& PlaybackSessionInterfaceMac::playbackSessionModel() const
 {
     return m_playbackSessionModel;
 }
@@ -102,7 +96,7 @@ void PlaybackSessionInterfaceMac::rateChanged(bool isPlaying, float playbackRate
     WebPlaybackControlsManager* controlsManager = playBackControlsManager();
     [controlsManager setRate:isPlaying ? playbackRate : 0.];
     [controlsManager setPlaying:isPlaying];
-    updatePlaybackControlsManagerTiming(m_playbackSessionModel ? m_playbackSessionModel->currentTime() : 0, [[NSProcessInfo processInfo] systemUptime], playbackRate, isPlaying);
+    updatePlaybackControlsManagerTiming(playbackSessionModel().currentTime(), [[NSProcessInfo processInfo] systemUptime], playbackRate, isPlaying);
 #else
     UNUSED_PARAM(isPlaying);
     UNUSED_PARAM(playbackRate);
@@ -112,14 +106,14 @@ void PlaybackSessionInterfaceMac::rateChanged(bool isPlaying, float playbackRate
 void PlaybackSessionInterfaceMac::beginScrubbing()
 {
 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
-    updatePlaybackControlsManagerTiming(m_playbackSessionModel ? m_playbackSessionModel->currentTime() : 0, [[NSProcessInfo processInfo] systemUptime], 0, false);
+    updatePlaybackControlsManagerTiming(playbackSessionModel().currentTime(), [[NSProcessInfo processInfo] systemUptime], 0, false);
 #endif
-    playbackSessionModel()->beginScrubbing();
+    playbackSessionModel().beginScrubbing();
 }
 
 void PlaybackSessionInterfaceMac::endScrubbing()
 {
-    playbackSessionModel()->endScrubbing();
+    playbackSessionModel().endScrubbing();
 }
 
 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
@@ -198,15 +192,6 @@ void PlaybackSessionInterfaceMac::externalPlaybackChanged(bool, PlaybackSessionM
 #endif
 }
 
-void PlaybackSessionInterfaceMac::invalidate()
-{
-    if (!m_playbackSessionModel)
-        return;
-
-    m_playbackSessionModel->removeClient(*this);
-    m_playbackSessionModel = nullptr;
-}
-
 void PlaybackSessionInterfaceMac::ensureControlsManager()
 {
 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
@@ -225,32 +210,27 @@ void PlaybackSessionInterfaceMac::setPlayBackControlsManager(WebPlaybackControls
 {
     m_playbackControlsManager = manager;
 
-    if (!manager || !m_playbackSessionModel)
+    if (!manager)
         return;
 
     NSTimeInterval anchorTimeStamp = ![manager rate] ? NAN : [[NSProcessInfo processInfo] systemUptime];
-    manager.timing = [getAVValueTimingClass() valueTimingWithAnchorValue:m_playbackSessionModel->currentTime() anchorTimeStamp:anchorTimeStamp rate:0];
-    double duration = m_playbackSessionModel->duration();
+    manager.timing = [getAVValueTimingClass() valueTimingWithAnchorValue:playbackSessionModel().currentTime() anchorTimeStamp:anchorTimeStamp rate:0];
+    double duration = playbackSessionModel().duration();
     manager.contentDuration = duration;
     manager.hasEnabledAudio = duration > 0;
     manager.hasEnabledVideo = duration > 0;
-    manager.rate = m_playbackSessionModel->isPlaying() ? m_playbackSessionModel->playbackRate() : 0.;
-    manager.seekableTimeRanges = timeRangesToArray(m_playbackSessionModel->seekableRanges()).get();
+    manager.rate = playbackSessionModel().isPlaying() ? playbackSessionModel().playbackRate() : 0.;
+    manager.seekableTimeRanges = timeRangesToArray(playbackSessionModel().seekableRanges()).get();
     manager.canTogglePlayback = YES;
-    manager.playing = m_playbackSessionModel->isPlaying();
-    [manager setAudioMediaSelectionOptions:m_playbackSessionModel->audioMediaSelectionOptions() withSelectedIndex:static_cast<NSUInteger>(m_playbackSessionModel->audioMediaSelectedIndex())];
-    [manager setLegibleMediaSelectionOptions:m_playbackSessionModel->legibleMediaSelectionOptions() withSelectedIndex:static_cast<NSUInteger>(m_playbackSessionModel->legibleMediaSelectedIndex())];
+    manager.playing = playbackSessionModel().isPlaying();
+    [manager setAudioMediaSelectionOptions:playbackSessionModel().audioMediaSelectionOptions() withSelectedIndex:static_cast<NSUInteger>(playbackSessionModel().audioMediaSelectedIndex())];
+    [manager setLegibleMediaSelectionOptions:playbackSessionModel().legibleMediaSelectionOptions() withSelectedIndex:static_cast<NSUInteger>(playbackSessionModel().legibleMediaSelectedIndex())];
 }
 
 void PlaybackSessionInterfaceMac::updatePlaybackControlsManagerCanTogglePictureInPicture()
 {
-    PlaybackSessionModel* model = playbackSessionModel();
-    if (!model) {
-        [playBackControlsManager() setCanTogglePictureInPicture:NO];
-        return;
-    }
-
-    [playBackControlsManager() setCanTogglePictureInPicture:model->isPictureInPictureSupported() && !model->externalPlaybackEnabled()];
+    auto& model = playbackSessionModel();
+    [playBackControlsManager() setCanTogglePictureInPicture:model.isPictureInPictureSupported() && !model.externalPlaybackEnabled()];
 }
 
 void PlaybackSessionInterfaceMac::updatePlaybackControlsManagerTiming(double currentTime, double anchorTime, double playbackRate, bool isPlaying)
@@ -259,16 +239,14 @@ void PlaybackSessionInterfaceMac::updatePlaybackControlsManagerTiming(double cur
     if (!manager)
         return;
 
-    PlaybackSessionModel *model = playbackSessionModel();
-    if (!model)
-        return;
+    auto& model = playbackSessionModel();
 
     double effectiveAnchorTime = playbackRate ? anchorTime : NAN;
     double effectivePlaybackRate = playbackRate;
     if (!isPlaying
-        || model->isScrubbing()
-        || (manager.rate > 0 && model->playbackStartedTime() >= currentTime)
-        || (manager.rate < 0 && model->playbackStartedTime() <= currentTime))
+        || model.isScrubbing()
+        || (manager.rate > 0 && model.playbackStartedTime() >= currentTime)
+        || (manager.rate < 0 && model.playbackStartedTime() <= currentTime))
         effectivePlaybackRate = 0;
 
     manager.timing = [getAVValueTimingClass() valueTimingWithAnchorValue:currentTime anchorTimeStamp:effectiveAnchorTime rate:effectivePlaybackRate];
index af2c649..e00573a 100644 (file)
@@ -33,6 +33,7 @@
 #include "VideoFullscreenModel.h"
 #include <wtf/RefCounted.h>
 #include <wtf/RetainPtr.h>
+#include <wtf/WeakPtr.h>
 #include <wtf/text/WTFString.h>
 
 OBJC_CLASS NSWindow;
@@ -46,21 +47,21 @@ class VideoFullscreenChangeObserver;
 
 class VideoFullscreenInterfaceMac
     : public VideoFullscreenModelClient
-    , private PlaybackSessionModelClient
-    , public RefCounted<VideoFullscreenInterfaceMac> {
+    , public PlaybackSessionModelClient
+    , public RefCounted<VideoFullscreenInterfaceMac>
+    , public CanMakeWeakPtr<VideoFullscreenInterfaceMac> {
 
 public:
-    static Ref<VideoFullscreenInterfaceMac> create(PlaybackSessionInterfaceMac& playbackSessionInterface)
+    static Ref<VideoFullscreenInterfaceMac> create(Ref<PlaybackSessionInterfaceMac>&& playbackSessionInterface, Ref<VideoFullscreenModel> videoFullscreenModel)
     {
-        return adoptRef(*new VideoFullscreenInterfaceMac(playbackSessionInterface));
+        return adoptRef(*new VideoFullscreenInterfaceMac(WTFMove(playbackSessionInterface), WTFMove(videoFullscreenModel)));
     }
     virtual ~VideoFullscreenInterfaceMac();
     PlaybackSessionInterfaceMac& playbackSessionInterface() const { return m_playbackSessionInterface.get(); }
-    VideoFullscreenModel* videoFullscreenModel() const { return m_videoFullscreenModel; }
-    PlaybackSessionModel* playbackSessionModel() const { return m_playbackSessionInterface->playbackSessionModel(); }
-    WEBCORE_EXPORT void setVideoFullscreenModel(VideoFullscreenModel*);
-    VideoFullscreenChangeObserver* videoFullscreenChangeObserver() const { return m_fullscreenChangeObserver; }
-    WEBCORE_EXPORT void setVideoFullscreenChangeObserver(VideoFullscreenChangeObserver*);
+    VideoFullscreenModel& videoFullscreenModel() const { return m_videoFullscreenModel; }
+    PlaybackSessionModel& playbackSessionModel() const { return m_playbackSessionInterface->playbackSessionModel(); }
+    VideoFullscreenChangeObserver* videoFullscreenChangeObserver() const { return m_fullscreenChangeObserver.get(); }
+    WEBCORE_EXPORT void setVideoFullscreenChangeObserver(WeakPtr<VideoFullscreenChangeObserver>);
 
     // PlaybackSessionModelClient
     WEBCORE_EXPORT void rateChanged(bool isPlaying, float playbackRate) override;
@@ -97,10 +98,11 @@ public:
     WEBCORE_EXPORT void requestHideAndExitPiP();
 
 private:
-    WEBCORE_EXPORT VideoFullscreenInterfaceMac(PlaybackSessionInterfaceMac&);
+    WEBCORE_EXPORT VideoFullscreenInterfaceMac(Ref<PlaybackSessionInterfaceMac>&&, Ref<VideoFullscreenModel>&&);
     Ref<PlaybackSessionInterfaceMac> m_playbackSessionInterface;
-    VideoFullscreenModel* m_videoFullscreenModel { nullptr };
-    VideoFullscreenChangeObserver* m_fullscreenChangeObserver { nullptr };
+    Ref<VideoFullscreenModel> m_videoFullscreenModel;
+    WeakPtrFactory<PlaybackSessionModelClient> m_weakPtrFactory;
+    WeakPtr<VideoFullscreenChangeObserver> m_fullscreenChangeObserver;
     HTMLMediaElementEnums::VideoFullscreenMode m_mode { HTMLMediaElementEnums::VideoFullscreenModeNone };
     RetainPtr<WebVideoFullscreenInterfaceMacObjC> m_webVideoFullscreenInterfaceObjC;
 };
index 0ae6afe..499a038 100644 (file)
@@ -39,6 +39,7 @@
 #import <pal/avfoundation/MediaTimeAVFoundation.h>
 #import <pal/spi/cocoa/AVKitSPI.h>
 #import <pal/spi/mac/PIPSPI.h>
+#import <wtf/WeakObjCPtr.h>
 
 #import <pal/cf/CoreMediaSoftLink.h>
 
@@ -64,11 +65,9 @@ using WebCore::VideoFullscreenChangeObserver;
 using WebCore::PlaybackSessionModel;
 
 @interface WebVideoViewContainer : NSView {
-    __unsafe_unretained id <WebVideoViewContainerDelegate> _videoViewContainerDelegate;
+    __weak id <WebVideoViewContainerDelegate> _videoViewContainerDelegate;
 }
-
-@property (nonatomic, assign) id <WebVideoViewContainerDelegate> videoViewContainerDelegate;
-
+@property (nonatomic, weak, assign) id <WebVideoViewContainerDelegate> videoViewContainerDelegate;
 @end
 
 @implementation WebVideoViewContainer
@@ -98,7 +97,7 @@ enum class PIPState {
 };
 
 @interface WebVideoFullscreenInterfaceMacObjC : NSObject <PIPViewControllerDelegate, WebVideoViewContainerDelegate> {
-    WebCore::VideoFullscreenInterfaceMac* _videoFullscreenInterfaceMac;
+    WeakPtr<WebCore::VideoFullscreenInterfaceMac> _videoFullscreenInterfaceMac;
     NSSize _videoDimensions;
     RetainPtr<PIPViewController> _pipViewController;
     RetainPtr<NSViewController> _videoViewContainerController;
@@ -140,7 +139,7 @@ enum class PIPState {
     if (!(self = [super init]))
         return nil;
 
-    _videoFullscreenInterfaceMac = videoFullscreenInterfaceMac;
+    _videoFullscreenInterfaceMac = makeWeakPtr(videoFullscreenInterfaceMac);
     _pipState = PIPState::NotInPIP;
 
     return self;
@@ -192,8 +191,8 @@ enum class PIPState {
     [_pipViewController setUserCanResize:YES];
     [_pipViewController setPlaying:_playing];
     [self setVideoDimensions:NSEqualSizes(_videoDimensions, NSZeroSize) ? frame.size : _videoDimensions];
-    if (_videoFullscreenInterfaceMac && _videoFullscreenInterfaceMac->videoFullscreenModel())
-        _videoFullscreenInterfaceMac->videoFullscreenModel()->setVideoLayerGravity(VideoFullscreenModel::VideoGravityResizeAspectFill);
+    if (_videoFullscreenInterfaceMac)
+        _videoFullscreenInterfaceMac->videoFullscreenModel().setVideoLayerGravity(VideoFullscreenModel::VideoGravityResizeAspectFill);
 
     _videoViewContainer = adoptNS([[WebVideoViewContainer alloc] initWithFrame:frame]);
     [_videoViewContainer setVideoViewContainerDelegate:self];
@@ -246,8 +245,8 @@ enum class PIPState {
 
     ASSERT_UNUSED(videoViewContainer, videoViewContainer == _videoViewContainer);
 
-    if (_videoFullscreenInterfaceMac && _videoFullscreenInterfaceMac->videoFullscreenModel())
-        _videoFullscreenInterfaceMac->videoFullscreenModel()->setVideoLayerFrame([_videoViewContainer bounds]);
+    if (_videoFullscreenInterfaceMac)
+        _videoFullscreenInterfaceMac->videoFullscreenModel().setVideoLayerFrame([_videoViewContainer bounds]);
 }
 
 - (void)superviewDidChangeForVideoViewContainer:(WebVideoViewContainer *)videoViewContainer
@@ -283,12 +282,12 @@ enum class PIPState {
 {
     ASSERT_UNUSED(pip, pip == _pipViewController);
 
-    if (_videoFullscreenInterfaceMac && _videoFullscreenInterfaceMac->videoFullscreenModel() && _videoViewContainer && _returningWindow && !NSEqualRects(_returningRect, NSZeroRect)) {
+    if (_videoFullscreenInterfaceMac && _videoViewContainer && _returningWindow && !NSEqualRects(_returningRect, NSZeroRect)) {
         [NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
             context.allowsImplicitAnimation = NO;
             [_videoViewContainer setFrame:_returningRect];
-            _videoFullscreenInterfaceMac->videoFullscreenModel()->setVideoLayerFrame([_videoViewContainer bounds]);
-            _videoFullscreenInterfaceMac->videoFullscreenModel()->setVideoLayerGravity(VideoFullscreenModel::VideoGravityResizeAspect);
+            _videoFullscreenInterfaceMac->videoFullscreenModel().setVideoLayerFrame([_videoViewContainer bounds]);
+            _videoFullscreenInterfaceMac->videoFullscreenModel().setVideoLayerGravity(VideoFullscreenModel::VideoGravityResizeAspect);
 
             [[_returningWindow contentView] addSubview:_videoViewContainer.get() positioned:NSWindowAbove relativeTo:nil];
         } completionHandler:nil];
@@ -296,10 +295,9 @@ enum class PIPState {
 
     if (_videoFullscreenInterfaceMac) {
         if (!self.isExitingToStandardFullscreen) {
-            if (VideoFullscreenModel* videoFullscreenModel = _videoFullscreenInterfaceMac->videoFullscreenModel()) {
-                videoFullscreenModel->didExitPictureInPicture();
-                videoFullscreenModel->setVideoLayerGravity(VideoFullscreenModel::VideoGravityResizeAspect);
-            }
+            Ref<VideoFullscreenModel> videoFullscreenModel = _videoFullscreenInterfaceMac->videoFullscreenModel();
+            videoFullscreenModel->didExitPictureInPicture();
+            videoFullscreenModel->setVideoLayerGravity(VideoFullscreenModel::VideoGravityResizeAspect);
         }
 
         _videoFullscreenInterfaceMac->clearMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
@@ -313,16 +311,16 @@ enum class PIPState {
 {
     ASSERT_UNUSED(pip, pip == _pipViewController);
 
-    if (_videoFullscreenInterfaceMac && _videoFullscreenInterfaceMac->playbackSessionModel())
-        _videoFullscreenInterfaceMac->playbackSessionModel()->play();
+    if (_videoFullscreenInterfaceMac)
+        _videoFullscreenInterfaceMac->playbackSessionModel().play();
 }
 
 - (void)pipActionPause:(PIPViewController *)pip
 {
     ASSERT_UNUSED(pip, pip == _pipViewController);
 
-    if (_videoFullscreenInterfaceMac && _videoFullscreenInterfaceMac->playbackSessionModel())
-        _videoFullscreenInterfaceMac->playbackSessionModel()->pause();
+    if (_videoFullscreenInterfaceMac)
+        _videoFullscreenInterfaceMac->playbackSessionModel().pause();
 }
 
 - (void)pipActionStop:(PIPViewController *)pip
@@ -332,8 +330,7 @@ enum class PIPState {
     if (!_videoFullscreenInterfaceMac)
         return;
 
-    if (PlaybackSessionModel* playbackSessionModel = _videoFullscreenInterfaceMac->playbackSessionModel())
-        playbackSessionModel->pause();
+    _videoFullscreenInterfaceMac->playbackSessionModel().pause();
 
     _videoFullscreenInterfaceMac->requestHideAndExitPiP();
     _pipState = PIPState::ExitingPIP;
@@ -344,33 +341,24 @@ enum class PIPState {
 namespace WebCore {
 using namespace PAL;
 
-VideoFullscreenInterfaceMac::VideoFullscreenInterfaceMac(PlaybackSessionInterfaceMac& playbackSessionInterface)
-    : m_playbackSessionInterface(playbackSessionInterface)
+VideoFullscreenInterfaceMac::VideoFullscreenInterfaceMac(Ref<PlaybackSessionInterfaceMac>&& playbackSessionInterface, Ref<VideoFullscreenModel>&& videoFullscreenModel)
+    : m_playbackSessionInterface(WTFMove(playbackSessionInterface))
+    , m_videoFullscreenModel(WTFMove(videoFullscreenModel))
 {
-    ASSERT(m_playbackSessionInterface->playbackSessionModel());
-    auto model = m_playbackSessionInterface->playbackSessionModel();
-    model->addClient(*this);
-    [videoFullscreenInterfaceObjC() updateIsPlaying:model->isPlaying() newPlaybackRate:model->playbackRate()];
+    auto& model = playbackSessionModel();
+    model.addClient(makeWeakPtr(this));
+    [videoFullscreenInterfaceObjC() updateIsPlaying:model.isPlaying() newPlaybackRate:model.playbackRate()];
 }
 
 VideoFullscreenInterfaceMac::~VideoFullscreenInterfaceMac()
 {
-    if (m_playbackSessionInterface->playbackSessionModel())
-        m_playbackSessionInterface->playbackSessionModel()->removeClient(*this);
-    if (m_videoFullscreenModel)
-        m_videoFullscreenModel->removeClient(*this);
+    invalidate();
+    auto& model = playbackSessionModel();
+    model.removeClient(*this);
+    m_videoFullscreenModel->removeClient(*this);
 }
 
-void VideoFullscreenInterfaceMac::setVideoFullscreenModel(VideoFullscreenModel* model)
-{
-    if (m_videoFullscreenModel)
-        m_videoFullscreenModel->removeClient(*this);
-    m_videoFullscreenModel = model;
-    if (m_videoFullscreenModel)
-        m_videoFullscreenModel->addClient(*this);
-}
-
-void VideoFullscreenInterfaceMac::setVideoFullscreenChangeObserver(VideoFullscreenChangeObserver* observer)
+void VideoFullscreenInterfaceMac::setVideoFullscreenChangeObserver(WeakPtr<VideoFullscreenChangeObserver> observer)
 {
     m_fullscreenChangeObserver = observer;
 }
@@ -382,8 +370,7 @@ void VideoFullscreenInterfaceMac::setMode(HTMLMediaElementEnums::VideoFullscreen
         return;
 
     m_mode = newMode;
-    if (m_videoFullscreenModel)
-        m_videoFullscreenModel->fullscreenModeChanged(m_mode);
+    m_videoFullscreenModel->fullscreenModeChanged(m_mode);
 }
 
 void VideoFullscreenInterfaceMac::clearMode(HTMLMediaElementEnums::VideoFullscreenMode mode)
@@ -393,8 +380,7 @@ void VideoFullscreenInterfaceMac::clearMode(HTMLMediaElementEnums::VideoFullscre
         return;
 
     m_mode = newMode;
-    if (m_videoFullscreenModel)
-        m_videoFullscreenModel->fullscreenModeChanged(m_mode);
+    m_videoFullscreenModel->fullscreenModeChanged(m_mode);
 }
 
 void VideoFullscreenInterfaceMac::rateChanged(bool isPlaying, float playbackRate)
@@ -499,7 +485,6 @@ void VideoFullscreenInterfaceMac::invalidate()
 {
     LOG(Fullscreen, "VideoFullscreenInterfaceMac::invalidate(%p)", this);
 
-    m_videoFullscreenModel = nil;
     m_fullscreenChangeObserver = nil;
 
     cleanupFullscreen();
@@ -510,9 +495,6 @@ void VideoFullscreenInterfaceMac::invalidate()
 
 void VideoFullscreenInterfaceMac::requestHideAndExitPiP()
 {
-    if (!m_videoFullscreenModel)
-        return;
-
     m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
     m_videoFullscreenModel->willExitPictureInPicture();
 }
index ac08d1f..0dd1251 100644 (file)
@@ -93,7 +93,7 @@ using WebCore::PlaybackSessionInterfaceMac;
 {
     UNUSED_PARAM(toleranceBefore);
     UNUSED_PARAM(toleranceAfter);
-    _playbackSessionInterfaceMac->playbackSessionModel()->seekToTime(time);
+    _playbackSessionInterfaceMac->playbackSessionModel().seekToTime(time);
 }
 
 - (void)cancelThumbnailAndAudioAmplitudeSampleGeneration
@@ -192,7 +192,7 @@ using WebCore::PlaybackSessionInterfaceMac;
     if (audioMediaSelectionOption && _audioTouchBarMediaSelectionOptions)
         index = [_audioTouchBarMediaSelectionOptions indexOfObject:audioMediaSelectionOption];
 
-    _playbackSessionInterfaceMac->playbackSessionModel()->selectAudioMediaOption(index != NSNotFound ? index : UINT64_MAX);
+    _playbackSessionInterfaceMac->playbackSessionModel().selectAudioMediaOption(index != NSNotFound ? index : UINT64_MAX);
 }
 
 - (NSArray<AVTouchBarMediaSelectionOption *> *)legibleTouchBarMediaSelectionOptions
@@ -222,7 +222,7 @@ using WebCore::PlaybackSessionInterfaceMac;
     if (legibleMediaSelectionOption && _legibleTouchBarMediaSelectionOptions)
         index = [_legibleTouchBarMediaSelectionOptions indexOfObject:legibleMediaSelectionOption];
 
-    _playbackSessionInterfaceMac->playbackSessionModel()->selectLegibleMediaOption(index != NSNotFound ? index : UINT64_MAX);
+    _playbackSessionInterfaceMac->playbackSessionModel().selectLegibleMediaOption(index != NSNotFound ? index : UINT64_MAX);
 }
 
 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
@@ -313,34 +313,34 @@ static RetainPtr<NSMutableArray> mediaSelectionOptions(const Vector<MediaSelecti
 
 - (void)togglePlayback
 {
-    if (_playbackSessionInterfaceMac && _playbackSessionInterfaceMac->playbackSessionModel())
-        _playbackSessionInterfaceMac->playbackSessionModel()->togglePlayState();
+    if (_playbackSessionInterfaceMac)
+        _playbackSessionInterfaceMac->playbackSessionModel().togglePlayState();
 }
 
 - (void)setPlaying:(BOOL)playing
 {
-    if (!_playbackSessionInterfaceMac || !_playbackSessionInterfaceMac->playbackSessionModel())
+    if (!_playbackSessionInterfaceMac)
         return;
 
     BOOL isCurrentlyPlaying = self.playing;
     if (!isCurrentlyPlaying && playing)
-        _playbackSessionInterfaceMac->playbackSessionModel()->play();
+        _playbackSessionInterfaceMac->playbackSessionModel().play();
     else if (isCurrentlyPlaying && !playing)
-        _playbackSessionInterfaceMac->playbackSessionModel()->pause();
+        _playbackSessionInterfaceMac->playbackSessionModel().pause();
 }
 
 - (BOOL)isPlaying
 {
-    if (_playbackSessionInterfaceMac && _playbackSessionInterfaceMac->playbackSessionModel())
-        return _playbackSessionInterfaceMac->playbackSessionModel()->isPlaying();
+    if (_playbackSessionInterfaceMac)
+        return _playbackSessionInterfaceMac->playbackSessionModel().isPlaying();
 
     return NO;
 }
 
 - (void)togglePictureInPicture
 {
-    if (_playbackSessionInterfaceMac && _playbackSessionInterfaceMac->playbackSessionModel())
-        _playbackSessionInterfaceMac->playbackSessionModel()->togglePictureInPicture();
+    if (_playbackSessionInterfaceMac)
+        _playbackSessionInterfaceMac->playbackSessionModel().togglePictureInPicture();
 }
 
 IGNORE_CLANG_WARNINGS_END
index 0cc7569..abdc74a 100644 (file)
@@ -1,3 +1,73 @@
+2018-09-28  Jer Noble  <jer.noble@apple.com>
+
+        Refactoring: eliminate raw pointer usage in Fullscreen code
+        https://bugs.webkit.org/show_bug.cgi?id=188747
+        <rdar://problem/43541164>
+
+        Reviewed by Alex Christensen.
+
+        Adopt those Ref and WeakPtr changes made in WebCore.
+
+        * UIProcess/Cocoa/PlaybackSessionManagerProxy.h:
+        * UIProcess/Cocoa/PlaybackSessionManagerProxy.mm:
+        (WebKit::PlaybackSessionModelContext::addClient):
+        (WebKit::PlaybackSessionModelContext::removeClient):
+        (WebKit::PlaybackSessionModelContext::durationChanged):
+        (WebKit::PlaybackSessionModelContext::currentTimeChanged):
+        (WebKit::PlaybackSessionModelContext::bufferedTimeChanged):
+        (WebKit::PlaybackSessionModelContext::rateChanged):
+        (WebKit::PlaybackSessionModelContext::seekableRangesChanged):
+        (WebKit::PlaybackSessionModelContext::canPlayFastReverseChanged):
+        (WebKit::PlaybackSessionModelContext::audioMediaSelectionOptionsChanged):
+        (WebKit::PlaybackSessionModelContext::legibleMediaSelectionOptionsChanged):
+        (WebKit::PlaybackSessionModelContext::audioMediaSelectionIndexChanged):
+        (WebKit::PlaybackSessionModelContext::legibleMediaSelectionIndexChanged):
+        (WebKit::PlaybackSessionModelContext::externalPlaybackChanged):
+        (WebKit::PlaybackSessionModelContext::wirelessVideoPlaybackDisabledChanged):
+        (WebKit::PlaybackSessionModelContext::mutedChanged):
+        (WebKit::PlaybackSessionModelContext::volumeChanged):
+        (WebKit::PlaybackSessionModelContext::pictureInPictureActiveChanged):
+        (WebKit::PlaybackSessionManagerProxy::invalidate):
+        (WebKit::PlaybackSessionManagerProxy::createModelAndInterface):
+        (WebKit::PlaybackSessionManagerProxy::removeClientForContext):
+        * UIProcess/Cocoa/VideoFullscreenManagerProxy.h:
+        * UIProcess/Cocoa/VideoFullscreenManagerProxy.mm:
+        (WebKit::VideoFullscreenModelContext::create):
+        (WebKit::VideoFullscreenModelContext::VideoFullscreenModelContext):
+        (WebKit::VideoFullscreenModelContext::addClient):
+        (WebKit::VideoFullscreenModelContext::removeClient):
+        (WebKit::VideoFullscreenModelContext::willEnterPictureInPicture):
+        (WebKit::VideoFullscreenModelContext::didEnterPictureInPicture):
+        (WebKit::VideoFullscreenModelContext::failedToEnterPictureInPicture):
+        (WebKit::VideoFullscreenModelContext::willExitPictureInPicture):
+        (WebKit::VideoFullscreenModelContext::didExitPictureInPicture):
+        (WebKit::VideoFullscreenManagerProxy::invalidate):
+        (WebKit::VideoFullscreenManagerProxy::createModelAndInterface):
+        (WebKit::VideoFullscreenManagerProxy::removeClientForContext):
+        (WebKit::VideoFullscreenModelContext::~VideoFullscreenModelContext): Deleted.
+        * UIProcess/ios/fullscreen/WKFullScreenViewController.mm:
+        (WKFullScreenViewControllerPlaybackSessionModelClient::setInterface):
+        (WKFullScreenViewControllerVideoFullscreenModelClient::setInterface):
+        (-[WKFullScreenViewController videoControlsManagerDidChange]):
+        (-[WKFullScreenViewController _togglePiPAction:]):
+        * UIProcess/mac/WKFullScreenWindowController.mm:
+        (WebKit::WKFullScreenWindowControllerVideoFullscreenModelClient::setInterface):
+        * WebProcess/cocoa/PlaybackSessionManager.h:
+        * WebProcess/cocoa/PlaybackSessionManager.mm:
+        (WebKit::PlaybackSessionInterfaceContext::PlaybackSessionInterfaceContext):
+        (WebKit::PlaybackSessionManager::~PlaybackSessionManager):
+        (WebKit::PlaybackSessionManager::createModelAndInterface):
+        (WebKit::PlaybackSessionManager::removeContext):
+        (WebKit::PlaybackSessionInterfaceContext::~PlaybackSessionInterfaceContext): Deleted.
+        * WebProcess/cocoa/VideoFullscreenManager.h:
+        (WebKit::VideoFullscreenInterfaceContext::create):
+        (WebKit::VideoFullscreenInterfaceContext::createWeakPtr):
+        * WebProcess/cocoa/VideoFullscreenManager.mm:
+        (WebKit::VideoFullscreenInterfaceContext::VideoFullscreenInterfaceContext):
+        (WebKit::VideoFullscreenManager::~VideoFullscreenManager):
+        (WebKit::VideoFullscreenManager::createModelAndInterface):
+        (WebKit::VideoFullscreenManager::removeContext):
+
 2018-09-28  Fujii Hironori  <Hironori.Fujii@sony.com>
 
         [WinCairo] error C2027: use of undefined type 'WTF::EnumTraits<E>' while compiling AuthenticationChallengeProxy.cpp
index a2773e6..0017a26 100644 (file)
 #include <WebCore/TimeRanges.h>
 #include <wtf/HashCountedSet.h>
 #include <wtf/HashMap.h>
-#include <wtf/HashSet.h>
 #include <wtf/RefCounted.h>
 #include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+#include <wtf/WeakPtrContainer.h>
 
 #if PLATFORM(IOS)
 #include <WebCore/PlaybackSessionInterfaceAVKit.h>
@@ -56,18 +57,20 @@ namespace WebKit {
 class WebPageProxy;
 class PlaybackSessionManagerProxy;
 
-class PlaybackSessionModelContext final: public RefCounted<PlaybackSessionModelContext>, public WebCore::PlaybackSessionModel  {
+class PlaybackSessionModelContext final
+    : public WebCore::PlaybackSessionModel
+    , public RefCounted<PlaybackSessionModelContext> {
 public:
-    static Ref<PlaybackSessionModelContext> create(PlaybackSessionManagerProxy& manager, uint64_t contextId)
+    static Ref<PlaybackSessionModelContext> create(WeakPtr<PlaybackSessionManagerProxy>&& manager, uint64_t contextId)
     {
-        return adoptRef(*new PlaybackSessionModelContext(manager, contextId));
+        return adoptRef(*new PlaybackSessionModelContext(WTFMove(manager), contextId));
     }
     virtual ~PlaybackSessionModelContext() { }
 
     void invalidate() { m_manager = nullptr; }
 
     // PlaybackSessionModel
-    void addClient(WebCore::PlaybackSessionModelClient&) final;
+    void addClient(WeakPtr<WebCore::PlaybackSessionModelClient>&&) final;
     void removeClient(WebCore::PlaybackSessionModelClient&)final;
 
     void durationChanged(double);
@@ -88,16 +91,21 @@ public:
     void pictureInPictureSupportedChanged(bool);
     void pictureInPictureActiveChanged(bool);
 
+    using RefCounted::ref;
+    using RefCounted::deref;
+
 private:
     friend class VideoFullscreenModelContext;
 
-    PlaybackSessionModelContext(PlaybackSessionManagerProxy& manager, uint64_t contextId)
-        : m_manager(&manager)
+    PlaybackSessionModelContext(WeakPtr<PlaybackSessionManagerProxy>&& manager, uint64_t contextId)
+        : m_manager(WTFMove(manager))
         , m_contextId(contextId)
     {
     }
 
     // PlaybackSessionModel
+    void refPlaybackSessionModel() final { ref(); }
+    void derefPlaybackSessionModel() final { deref(); }
     void play() final;
     void pause() final;
     void togglePlayState() final;
@@ -139,10 +147,10 @@ private:
     double volume() const final { return m_volume; }
     bool isPictureInPictureSupported() const final { return m_pictureInPictureSupported; }
     bool isPictureInPictureActive() const final { return m_pictureInPictureActive; }
-
-    PlaybackSessionManagerProxy* m_manager;
+    
+    WeakPtr<PlaybackSessionManagerProxy> m_manager;
     uint64_t m_contextId;
-    HashSet<WebCore::PlaybackSessionModelClient*> m_clients;
+    WeakPtrContainer<WebCore::PlaybackSessionModelClient> m_clients;
     double m_playbackStartedTime { 0 };
     bool m_playbackStartedTimeNeedsUpdate { false };
     double m_duration { 0 };
@@ -169,7 +177,10 @@ private:
     bool m_pictureInPictureActive { false };
 };
 
-class PlaybackSessionManagerProxy : public RefCounted<PlaybackSessionManagerProxy>, private IPC::MessageReceiver {
+class PlaybackSessionManagerProxy
+    : public RefCounted<PlaybackSessionManagerProxy>
+    , private IPC::MessageReceiver
+    , public CanMakeWeakPtr<PlaybackSessionManagerProxy> {
 public:
     static RefPtr<PlaybackSessionManagerProxy> create(WebPageProxy&);
     virtual ~PlaybackSessionManagerProxy();
index dc36171..699bdfd 100644 (file)
@@ -38,16 +38,14 @@ using namespace WebCore;
 
 #pragma mark - PlaybackSessionModelContext
 
-void PlaybackSessionModelContext::addClient(PlaybackSessionModelClient& client)
+void PlaybackSessionModelContext::addClient(WeakPtr<PlaybackSessionModelClient>&& client)
 {
-    ASSERT(!m_clients.contains(&client));
-    m_clients.add(&client);
+    m_clients.add(WTFMove(client));
 }
 
 void PlaybackSessionModelContext::removeClient(PlaybackSessionModelClient& client)
 {
-    ASSERT(m_clients.contains(&client));
-    m_clients.remove(&client);
+    m_clients.remove(client);
 }
 
 void PlaybackSessionModelContext::play()
@@ -166,8 +164,9 @@ void PlaybackSessionModelContext::playbackStartedTimeChanged(double playbackStar
 void PlaybackSessionModelContext::durationChanged(double duration)
 {
     m_duration = duration;
-    for (auto* client : m_clients)
-        client->durationChanged(duration);
+    m_clients.forEachNonNullMember([duration] (auto& client) {
+        client.durationChanged(duration);
+    });
 }
 
 void PlaybackSessionModelContext::currentTimeChanged(double currentTime)
@@ -177,23 +176,26 @@ void PlaybackSessionModelContext::currentTimeChanged(double currentTime)
     if (m_playbackStartedTimeNeedsUpdate)
         playbackStartedTimeChanged(currentTime);
 
-    for (auto* client : m_clients)
-        client->currentTimeChanged(currentTime, anchorTime);
+    m_clients.forEachNonNullMember([currentTime, anchorTime] (auto& client) {
+        client.currentTimeChanged(currentTime, anchorTime);
+    });
 }
 
 void PlaybackSessionModelContext::bufferedTimeChanged(double bufferedTime)
 {
     m_bufferedTime = bufferedTime;
-    for (auto* client : m_clients)
-        client->bufferedTimeChanged(bufferedTime);
+    m_clients.forEachNonNullMember([bufferedTime] (auto& client) {
+        client.bufferedTimeChanged(bufferedTime);
+    });
 }
 
 void PlaybackSessionModelContext::rateChanged(bool isPlaying, float playbackRate)
 {
     m_isPlaying = isPlaying;
     m_playbackRate = playbackRate;
-    for (auto* client : m_clients)
-        client->rateChanged(isPlaying, playbackRate);
+    m_clients.forEachNonNullMember([isPlaying, playbackRate] (auto& client) {
+        client.rateChanged(isPlaying, playbackRate);
+    });
 }
 
 void PlaybackSessionModelContext::seekableRangesChanged(WebCore::TimeRanges& seekableRanges, double lastModifiedTime, double liveUpdateInterval)
@@ -201,23 +203,26 @@ void PlaybackSessionModelContext::seekableRangesChanged(WebCore::TimeRanges& see
     m_seekableRanges = seekableRanges;
     m_seekableTimeRangesLastModifiedTime = lastModifiedTime;
     m_liveUpdateInterval = liveUpdateInterval;
-    for (auto* client : m_clients)
-        client->seekableRangesChanged(seekableRanges, lastModifiedTime, liveUpdateInterval);
+    m_clients.forEachNonNullMember([seekableRanges = makeRef(seekableRanges), lastModifiedTime, liveUpdateInterval] (auto& client) {
+        client.seekableRangesChanged(seekableRanges, lastModifiedTime, liveUpdateInterval);
+    });
 }
 
 void PlaybackSessionModelContext::canPlayFastReverseChanged(bool canPlayFastReverse)
 {
     m_canPlayFastReverse = canPlayFastReverse;
-    for (auto* client : m_clients)
-        client->canPlayFastReverseChanged(canPlayFastReverse);
+    m_clients.forEachNonNullMember([canPlayFastReverse] (auto& client) {
+        client.canPlayFastReverseChanged(canPlayFastReverse);
+    });
 }
 
 void PlaybackSessionModelContext::audioMediaSelectionOptionsChanged(const Vector<MediaSelectionOption>& audioMediaSelectionOptions, uint64_t audioMediaSelectedIndex)
 {
     m_audioMediaSelectionOptions = audioMediaSelectionOptions;
     m_audioMediaSelectedIndex = audioMediaSelectedIndex;
-    for (auto* client : m_clients)
-        client->audioMediaSelectionOptionsChanged(audioMediaSelectionOptions, audioMediaSelectedIndex);
+    m_clients.forEachNonNullMember([audioMediaSelectionOptions, audioMediaSelectedIndex] (auto& client) {
+        client.audioMediaSelectionOptionsChanged(audioMediaSelectionOptions, audioMediaSelectedIndex);
+    });
 }
 
 void PlaybackSessionModelContext::legibleMediaSelectionOptionsChanged(const Vector<MediaSelectionOption>& legibleMediaSelectionOptions, uint64_t legibleMediaSelectedIndex)
@@ -225,24 +230,27 @@ void PlaybackSessionModelContext::legibleMediaSelectionOptionsChanged(const Vect
     m_legibleMediaSelectionOptions = legibleMediaSelectionOptions;
     m_legibleMediaSelectedIndex = legibleMediaSelectedIndex;
 
-    for (auto* client : m_clients)
-        client->legibleMediaSelectionOptionsChanged(legibleMediaSelectionOptions, legibleMediaSelectedIndex);
+    m_clients.forEachNonNullMember([legibleMediaSelectionOptions, legibleMediaSelectedIndex] (auto& client) {
+        client.legibleMediaSelectionOptionsChanged(legibleMediaSelectionOptions, legibleMediaSelectedIndex);
+    });
 }
 
 void PlaybackSessionModelContext::audioMediaSelectionIndexChanged(uint64_t selectedIndex)
 {
     m_audioMediaSelectedIndex = selectedIndex;
 
-    for (auto* client : m_clients)
-        client->audioMediaSelectionIndexChanged(selectedIndex);
+    m_clients.forEachNonNullMember([selectedIndex] (auto& client) {
+        client.audioMediaSelectionIndexChanged(selectedIndex);
+    });
 }
 
 void PlaybackSessionModelContext::legibleMediaSelectionIndexChanged(uint64_t selectedIndex)
 {
     m_legibleMediaSelectedIndex = selectedIndex;
 
-    for (auto* client : m_clients)
-        client->legibleMediaSelectionIndexChanged(selectedIndex);
+    m_clients.forEachNonNullMember([selectedIndex] (auto& client) {
+        client.legibleMediaSelectionIndexChanged(selectedIndex);
+    });
 }
 
 void PlaybackSessionModelContext::externalPlaybackChanged(bool enabled, PlaybackSessionModel::ExternalPlaybackTargetType type, const String& localizedName)
@@ -251,43 +259,49 @@ void PlaybackSessionModelContext::externalPlaybackChanged(bool enabled, Playback
     m_externalPlaybackTargetType = type;
     m_externalPlaybackLocalizedDeviceName = localizedName;
 
-    for (auto* client : m_clients)
-        client->externalPlaybackChanged(enabled, type, localizedName);
+    m_clients.forEachNonNullMember([enabled, type, localizedName] (auto& client) {
+        client.externalPlaybackChanged(enabled, type, localizedName);
+    });
 }
 
 void PlaybackSessionModelContext::wirelessVideoPlaybackDisabledChanged(bool wirelessVideoPlaybackDisabled)
 {
     m_wirelessVideoPlaybackDisabled = wirelessVideoPlaybackDisabled;
-    for (auto* client : m_clients)
-        client->wirelessVideoPlaybackDisabledChanged(wirelessVideoPlaybackDisabled);
+    m_clients.forEachNonNullMember([wirelessVideoPlaybackDisabled] (auto& client) {
+        client.wirelessVideoPlaybackDisabledChanged(wirelessVideoPlaybackDisabled);
+    });
 }
 
 void PlaybackSessionModelContext::mutedChanged(bool muted)
 {
     m_muted = muted;
-    for (auto* client : m_clients)
-        client->mutedChanged(muted);
+    m_clients.forEachNonNullMember([muted] (auto& client) {
+        client.mutedChanged(muted);
+    });
 }
 
 void PlaybackSessionModelContext::volumeChanged(double volume)
 {
     m_volume = volume;
-    for (auto* client : m_clients)
-        client->volumeChanged(volume);
+    m_clients.forEachNonNullMember([volume] (auto& client) {
+        client.volumeChanged(volume);
+    });
 }
 
 void PlaybackSessionModelContext::pictureInPictureSupportedChanged(bool supported)
 {
     m_pictureInPictureSupported = supported;
-    for (auto* client : m_clients)
-        client->isPictureInPictureSupportedChanged(supported);
+    m_clients.forEachNonNullMember([supported] (auto& client) {
+        client.isPictureInPictureSupportedChanged(supported);
+    });
 }
 
 void PlaybackSessionModelContext::pictureInPictureActiveChanged(bool active)
 {
     m_pictureInPictureActive = active;
-    for (auto* client : m_clients)
-        client->pictureInPictureActiveChanged(active);
+    m_clients.forEachNonNullMember([active] (auto& client) {
+        client.pictureInPictureActiveChanged(active);
+    });
 }
 
 #pragma mark - PlaybackSessionManagerProxy
@@ -315,22 +329,14 @@ void PlaybackSessionManagerProxy::invalidate()
     m_page->process().removeMessageReceiver(Messages::PlaybackSessionManagerProxy::messageReceiverName(), m_page->pageID());
     m_page = nullptr;
 
-    auto contextMap = WTFMove(m_contextMap);
+    m_contextMap.clear();
     m_clientCounts.clear();
-
-    for (auto& tuple : contextMap.values()) {
-        RefPtr<PlaybackSessionModelContext> model;
-        RefPtr<PlatformPlaybackSessionInterface> interface;
-        std::tie(model, interface) = tuple;
-
-        interface->invalidate();
-    }
 }
 
 PlaybackSessionManagerProxy::ModelInterfaceTuple PlaybackSessionManagerProxy::createModelAndInterface(uint64_t contextId)
 {
-    Ref<PlaybackSessionModelContext> model = PlaybackSessionModelContext::create(*this, contextId);
-    Ref<PlatformPlaybackSessionInterface> interface = PlatformPlaybackSessionInterface::create(model);
+    Ref<PlaybackSessionModelContext> model = PlaybackSessionModelContext::create(makeWeakPtr(this), contextId);
+    Ref<PlatformPlaybackSessionInterface> interface = PlatformPlaybackSessionInterface::create(model.copyRef());
 
     return std::make_tuple(WTFMove(model), WTFMove(interface));
 }
@@ -360,11 +366,8 @@ void PlaybackSessionManagerProxy::addClientForContext(uint64_t contextId)
 
 void PlaybackSessionManagerProxy::removeClientForContext(uint64_t contextId)
 {
-    if (!m_clientCounts.remove(contextId))
-        return;
-
-    ensureInterface(contextId).invalidate();
-    m_contextMap.remove(contextId);
+    if (m_clientCounts.remove(contextId))
+        m_contextMap.remove(contextId);
 }
 
 #pragma mark Messages from PlaybackSessionManager
@@ -381,7 +384,8 @@ void PlaybackSessionManagerProxy::setUpPlaybackControlsManagerWithID(uint64_t co
     ensureInterface(m_controlsManagerContextId).ensureControlsManager();
     addClientForContext(m_controlsManagerContextId);
 
-    m_page->videoControlsManagerDidChange();
+    if (m_page)
+        m_page->videoControlsManagerDidChange();
 }
 
 void PlaybackSessionManagerProxy::clearPlaybackControlsManager()
@@ -391,7 +395,8 @@ void PlaybackSessionManagerProxy::clearPlaybackControlsManager()
 
     removeClientForContext(m_controlsManagerContextId);
     m_controlsManagerContextId = 0;
-    m_page->videoControlsManagerDidChange();
+    if (m_page)
+        m_page->videoControlsManagerDidChange();
 }
 
 void PlaybackSessionManagerProxy::resetMediaState(uint64_t contextId)
@@ -498,7 +503,7 @@ void PlaybackSessionManagerProxy::pictureInPictureActiveChanged(uint64_t context
 void PlaybackSessionManagerProxy::handleControlledElementIDResponse(uint64_t contextId, String identifier) const
 {
 #if PLATFORM(MAC)
-    if (contextId == m_controlsManagerContextId)
+    if (m_page && contextId == m_controlsManagerContextId)
         m_page->handleControlledElementIDResponse(identifier);
 #else
     UNUSED_PARAM(contextId);
@@ -511,82 +516,98 @@ void PlaybackSessionManagerProxy::handleControlledElementIDResponse(uint64_t con
 
 void PlaybackSessionManagerProxy::play(uint64_t contextId)
 {
-    m_page->send(Messages::PlaybackSessionManager::Play(contextId), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManager::Play(contextId), m_page->pageID());
 }
 
 void PlaybackSessionManagerProxy::pause(uint64_t contextId)
 {
-    m_page->send(Messages::PlaybackSessionManager::Pause(contextId), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManager::Pause(contextId), m_page->pageID());
 }
 
 void PlaybackSessionManagerProxy::togglePlayState(uint64_t contextId)
 {
-    m_page->send(Messages::PlaybackSessionManager::TogglePlayState(contextId), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManager::TogglePlayState(contextId), m_page->pageID());
 }
 
 void PlaybackSessionManagerProxy::beginScrubbing(uint64_t contextId)
 {
-    m_page->send(Messages::PlaybackSessionManager::BeginScrubbing(contextId), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManager::BeginScrubbing(contextId), m_page->pageID());
 }
 
 void PlaybackSessionManagerProxy::endScrubbing(uint64_t contextId)
 {
-    m_page->send(Messages::PlaybackSessionManager::EndScrubbing(contextId), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManager::EndScrubbing(contextId), m_page->pageID());
 }
 
 void PlaybackSessionManagerProxy::seekToTime(uint64_t contextId, double time, double toleranceBefore, double toleranceAfter)
 {
-    m_page->send(Messages::PlaybackSessionManager::SeekToTime(contextId, time, toleranceBefore, toleranceAfter), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManager::SeekToTime(contextId, time, toleranceBefore, toleranceAfter), m_page->pageID());
 }
 
 void PlaybackSessionManagerProxy::fastSeek(uint64_t contextId, double time)
 {
-    m_page->send(Messages::PlaybackSessionManager::FastSeek(contextId, time), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManager::FastSeek(contextId, time), m_page->pageID());
 }
 
 void PlaybackSessionManagerProxy::beginScanningForward(uint64_t contextId)
 {
-    m_page->send(Messages::PlaybackSessionManager::BeginScanningForward(contextId), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManager::BeginScanningForward(contextId), m_page->pageID());
 }
 
 void PlaybackSessionManagerProxy::beginScanningBackward(uint64_t contextId)
 {
-    m_page->send(Messages::PlaybackSessionManager::BeginScanningBackward(contextId), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManager::BeginScanningBackward(contextId), m_page->pageID());
 }
 
 void PlaybackSessionManagerProxy::endScanning(uint64_t contextId)
 {
-    m_page->send(Messages::PlaybackSessionManager::EndScanning(contextId), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManager::EndScanning(contextId), m_page->pageID());
 }
 
 void PlaybackSessionManagerProxy::selectAudioMediaOption(uint64_t contextId, uint64_t index)
 {
-    m_page->send(Messages::PlaybackSessionManager::SelectAudioMediaOption(contextId, index), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManager::SelectAudioMediaOption(contextId, index), m_page->pageID());
 }
 
 void PlaybackSessionManagerProxy::selectLegibleMediaOption(uint64_t contextId, uint64_t index)
 {
-    m_page->send(Messages::PlaybackSessionManager::SelectLegibleMediaOption(contextId, index), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManager::SelectLegibleMediaOption(contextId, index), m_page->pageID());
 }
 
 void PlaybackSessionManagerProxy::togglePictureInPicture(uint64_t contextId)
 {
-    m_page->send(Messages::PlaybackSessionManager::TogglePictureInPicture(contextId), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManager::TogglePictureInPicture(contextId), m_page->pageID());
 }
 
 void PlaybackSessionManagerProxy::toggleMuted(uint64_t contextId)
 {
-    m_page->send(Messages::PlaybackSessionManager::ToggleMuted(contextId), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManager::ToggleMuted(contextId), m_page->pageID());
 }
 
 void PlaybackSessionManagerProxy::setMuted(uint64_t contextId, bool muted)
 {
-    m_page->send(Messages::PlaybackSessionManager::SetMuted(contextId, muted), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManager::SetMuted(contextId, muted), m_page->pageID());
 }
 
 void PlaybackSessionManagerProxy::setVolume(uint64_t contextId, double volume)
 {
-    m_page->send(Messages::PlaybackSessionManager::SetVolume(contextId, volume), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManager::SetVolume(contextId, volume), m_page->pageID());
 }
 
 void PlaybackSessionManagerProxy::setPlayingOnSecondScreen(uint64_t contextId, bool value)
@@ -597,7 +618,7 @@ void PlaybackSessionManagerProxy::setPlayingOnSecondScreen(uint64_t contextId, b
 
 void PlaybackSessionManagerProxy::requestControlledElementID()
 {
-    if (m_controlsManagerContextId)
+    if (m_page && m_controlsManagerContextId)
         m_page->send(Messages::PlaybackSessionManager::HandleControlledElementIDRequest(m_controlsManagerContextId), m_page->pageID());
 }
 
index 48663c2..b6f74f5 100644 (file)
 #include <WebCore/VideoFullscreenChangeObserver.h>
 #include <WebCore/VideoFullscreenModel.h>
 #include <wtf/HashMap.h>
-#include <wtf/HashSet.h>
 #include <wtf/RefCounted.h>
 #include <wtf/RefPtr.h>
+#include <wtf/UniqueRef.h>
+#include <wtf/Vector.h>
+#include <wtf/WeakPtrContainer.h>
 
 #if PLATFORM(IOS)
 #include <WebCore/VideoFullscreenInterfaceAVKit.h>
@@ -59,12 +61,9 @@ class VideoFullscreenManagerProxy;
 class VideoFullscreenModelContext final
     : public RefCounted<VideoFullscreenModelContext>
     , public WebCore::VideoFullscreenModel
-    , public WebCore::VideoFullscreenChangeObserver  {
+    , public WebCore::VideoFullscreenChangeObserver {
 public:
-    static Ref<VideoFullscreenModelContext> create(VideoFullscreenManagerProxy& manager, PlaybackSessionModelContext& playbackSessionModel, uint64_t contextId)
-    {
-        return adoptRef(*new VideoFullscreenModelContext(manager, playbackSessionModel, contextId));
-    }
+    static Ref<VideoFullscreenModelContext> create(WeakPtr<VideoFullscreenManagerProxy>&&, Ref<PlaybackSessionModelContext>&&, uint64_t contextId);
     virtual ~VideoFullscreenModelContext();
 
     void invalidate() { m_manager = nullptr; }
@@ -72,19 +71,26 @@ public:
     PlatformView *layerHostView() const { return m_layerHostView.get(); }
     void setLayerHostView(RetainPtr<PlatformView>&& layerHostView) { m_layerHostView = WTFMove(layerHostView); }
 
+    WeakPtr<VideoFullscreenChangeObserver> createWeakPtr() { return m_weakPtrFactory.createWeakPtr(*this); }
+
+    using RefCounted::ref;
+    using RefCounted::deref;
+
 private:
-    VideoFullscreenModelContext(VideoFullscreenManagerProxy&, PlaybackSessionModelContext&, uint64_t);
+    VideoFullscreenModelContext(WeakPtr<VideoFullscreenManagerProxy>&&, Ref<PlaybackSessionModelContext>&&, uint64_t);
 
     // VideoFullscreenModel
-    void addClient(WebCore::VideoFullscreenModelClient&) override;
-    void removeClient(WebCore::VideoFullscreenModelClient&) override;
-    void requestFullscreenMode(WebCore::HTMLMediaElementEnums::VideoFullscreenMode, bool finishedWithMedia = false) override;
-    void setVideoLayerFrame(WebCore::FloatRect) override;
-    void setVideoLayerGravity(VideoGravity) override;
-    void fullscreenModeChanged(WebCore::HTMLMediaElementEnums::VideoFullscreenMode) override;
-    bool isVisible() const override;
-    bool hasVideo() const override { return m_hasVideo; }
-    WebCore::FloatSize videoDimensions() const override { return m_videoDimensions; }
+    void refVideoFullscreenModel() final { ref(); }
+    void derefVideoFullscreenModel() final { deref(); }
+    void addClient(WeakPtr<WebCore::VideoFullscreenModelClient>&&) final;
+    void removeClient(WebCore::VideoFullscreenModelClient&) final;
+    void requestFullscreenMode(WebCore::HTMLMediaElementEnums::VideoFullscreenMode, bool finishedWithMedia = false) final;
+    void setVideoLayerFrame(WebCore::FloatRect) final;
+    void setVideoLayerGravity(VideoGravity) final;
+    void fullscreenModeChanged(WebCore::HTMLMediaElementEnums::VideoFullscreenMode) final;
+    bool isVisible() const final;
+    bool hasVideo() const final { return m_hasVideo; }
+    WebCore::FloatSize videoDimensions() const final { return m_videoDimensions; }
 #if PLATFORM(IOS)
     UIViewController *presentingViewController() final;
     UIViewController *createVideoFullscreenViewController(AVPlayerViewController*) final;
@@ -106,16 +112,20 @@ private:
     void didCleanupFullscreen() final;
     void fullscreenMayReturnToInline() final;
 
-    VideoFullscreenManagerProxy* m_manager;
+    WeakPtr<VideoFullscreenManagerProxy> m_manager;
     Ref<PlaybackSessionModelContext> m_playbackSessionModel;
     uint64_t m_contextId;
+    WeakPtrFactory<VideoFullscreenChangeObserver> m_weakPtrFactory;
     RetainPtr<PlatformView *> m_layerHostView;
-    HashSet<WebCore::VideoFullscreenModelClient*> m_clients;
+    WeakPtrContainer<WebCore::VideoFullscreenModelClient> m_clients;
     WebCore::FloatSize m_videoDimensions;
     bool m_hasVideo { false };
 };
 
-class VideoFullscreenManagerProxy : public RefCounted<VideoFullscreenManagerProxy>, private IPC::MessageReceiver {
+class VideoFullscreenManagerProxy
+    : public RefCounted<VideoFullscreenManagerProxy>
+    , private IPC::MessageReceiver 
+    , public CanMakeWeakPtr<VideoFullscreenManagerProxy> {
 public:
     static RefPtr<VideoFullscreenManagerProxy> create(WebPageProxy&, PlaybackSessionManagerProxy&);
     virtual ~VideoFullscreenManagerProxy();
index bdfbc80..8e20426 100644 (file)
@@ -158,27 +158,28 @@ void VideoFullscreenManagerProxy::applicationDidBecomeActive()
 
 #pragma mark - VideoFullscreenModelContext
 
-VideoFullscreenModelContext::VideoFullscreenModelContext(VideoFullscreenManagerProxy& manager, PlaybackSessionModelContext& playbackSessionModel, uint64_t contextId)
-    : m_manager(&manager)
-    , m_playbackSessionModel(playbackSessionModel)
-    , m_contextId(contextId)
+Ref<VideoFullscreenModelContext> VideoFullscreenModelContext::create(WeakPtr<VideoFullscreenManagerProxy>&& manager, Ref<PlaybackSessionModelContext>&& playbackSessionModel, uint64_t contextId)
 {
+    return adoptRef(*new VideoFullscreenModelContext(WTFMove(manager), WTFMove(playbackSessionModel), contextId));
 }
 
-VideoFullscreenModelContext::~VideoFullscreenModelContext()
+VideoFullscreenModelContext::VideoFullscreenModelContext(WeakPtr<VideoFullscreenManagerProxy>&& manager, Ref<PlaybackSessionModelContext>&& playbackSessionModel, uint64_t contextId)
+    : m_manager(WTFMove(manager))
+    , m_playbackSessionModel(WTFMove(playbackSessionModel))
+    , m_contextId(contextId)
 {
 }
 
-void VideoFullscreenModelContext::addClient(VideoFullscreenModelClient& client)
+VideoFullscreenModelContext::~VideoFullscreenModelContext() = default;
+
+void VideoFullscreenModelContext::addClient(WeakPtr<VideoFullscreenModelClient>&& client)
 {
-    ASSERT(!m_clients.contains(&client));
-    m_clients.add(&client);
+    m_clients.add(WTFMove(client));
 }
 
 void VideoFullscreenModelContext::removeClient(VideoFullscreenModelClient& client)
 {
-    ASSERT(m_clients.contains(&client));
-    m_clients.remove(&client);
+    m_clients.remove(client);
 }
 
 void VideoFullscreenModelContext::requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenMode mode, bool finishedWithMedia)
@@ -281,32 +282,37 @@ void VideoFullscreenModelContext::fullscreenMayReturnToInline()
 
 void VideoFullscreenModelContext::willEnterPictureInPicture()
 {
-    for (auto& client : m_clients)
-        client->willEnterPictureInPicture();
+    m_clients.forEachNonNullMember([] (auto& client) {
+        client.willEnterPictureInPicture();
+    });
 }
 
 void VideoFullscreenModelContext::didEnterPictureInPicture()
 {
-    for (auto& client : m_clients)
-        client->didEnterPictureInPicture();
+    m_clients.forEachNonNullMember([] (auto& client) {
+        client.didEnterPictureInPicture();
+    });
 }
 
 void VideoFullscreenModelContext::failedToEnterPictureInPicture()
 {
-    for (auto& client : m_clients)
-        client->failedToEnterPictureInPicture();
+    m_clients.forEachNonNullMember([] (auto& client) {
+        client.failedToEnterPictureInPicture();
+    });
 }
 
 void VideoFullscreenModelContext::willExitPictureInPicture()
 {
-    for (auto& client : m_clients)
-        client->willExitPictureInPicture();
+    m_clients.forEachNonNullMember([] (auto& client) {
+        client.willExitPictureInPicture();
+    });
 }
 
 void VideoFullscreenModelContext::didExitPictureInPicture()
 {
-    for (auto& client : m_clients)
-        client->didExitPictureInPicture();
+    m_clients.forEachNonNullMember([] (auto& client) {
+        client.didExitPictureInPicture();
+    });
 }
 
 #pragma mark - VideoFullscreenManagerProxy
@@ -343,7 +349,6 @@ void VideoFullscreenManagerProxy::invalidate()
         RefPtr<PlatformVideoFullscreenInterface> interface;
         std::tie(model, interface) = tuple;
 
-        interface->invalidate();
         [model->layerHostView() removeFromSuperview];
         model->setLayerHostView(nullptr);
     }
@@ -401,13 +406,12 @@ void VideoFullscreenManagerProxy::applicationDidBecomeActive()
 VideoFullscreenManagerProxy::ModelInterfaceTuple VideoFullscreenManagerProxy::createModelAndInterface(uint64_t contextId)
 {
     auto& playbackSessionModel = m_playbackSessionManagerProxy->ensureModel(contextId);
-    Ref<VideoFullscreenModelContext> model = VideoFullscreenModelContext::create(*this, playbackSessionModel, contextId);
     auto& playbackSessionInterface = m_playbackSessionManagerProxy->ensureInterface(contextId);
-    Ref<PlatformVideoFullscreenInterface> interface = PlatformVideoFullscreenInterface::create(playbackSessionInterface);
+    Ref<VideoFullscreenModelContext> model = VideoFullscreenModelContext::create(makeWeakPtr(this), playbackSessionModel, contextId);
+    Ref<PlatformVideoFullscreenInterface> interface = PlatformVideoFullscreenInterface::create(makeRef(playbackSessionInterface), model.copyRef());
     m_playbackSessionManagerProxy->addClientForContext(contextId);
 
-    interface->setVideoFullscreenModel(&model.get());
-    interface->setVideoFullscreenChangeObserver(&model.get());
+    interface->setVideoFullscreenChangeObserver(model->createWeakPtr());
 
     return std::make_tuple(WTFMove(model), WTFMove(interface));
 }
@@ -446,7 +450,6 @@ void VideoFullscreenManagerProxy::removeClientForContext(uint64_t contextId)
     clientCount--;
 
     if (clientCount <= 0) {
-        ensureInterface(contextId).setVideoFullscreenModel(nullptr);
         m_playbackSessionManagerProxy->removeClientForContext(contextId);
         m_clientCounts.remove(contextId);
         m_contextMap.remove(contextId);
index a9ac545..f17475e 100644 (file)
@@ -56,7 +56,9 @@ static const double requiredScore = 0.1;
 - (void)failedToEnterPictureInPicture;
 @end
 
-class WKFullScreenViewControllerPlaybackSessionModelClient : PlaybackSessionModelClient {
+class WKFullScreenViewControllerPlaybackSessionModelClient 
+    : public PlaybackSessionModelClient
+    , public CanMakeWeakPtr<WKFullScreenViewControllerPlaybackSessionModelClient> {
 public:
     void setParent(WKFullScreenViewController *parent) { m_parent = parent; }
 
@@ -79,11 +81,11 @@ public:
         if (m_interface == interface)
             return;
 
-        if (m_interface && m_interface->playbackSessionModel())
-            m_interface->playbackSessionModel()->removeClient(*this);
+        if (m_interface)
+            m_interface->playbackSessionModel().removeClient(*this);
         m_interface = interface;
-        if (m_interface && m_interface->playbackSessionModel())
-            m_interface->playbackSessionModel()->addClient(*this);
+        if (m_interface)
+            m_interface->playbackSessionModel().addClient(makeWeakPtr(*this));
     }
 
 private:
@@ -91,7 +93,9 @@ private:
     RefPtr<PlaybackSessionInterfaceAVKit> m_interface;
 };
 
-class WKFullScreenViewControllerVideoFullscreenModelClient : VideoFullscreenModelClient {
+class WKFullScreenViewControllerVideoFullscreenModelClient
+    : public VideoFullscreenModelClient
+    , public CanMakeWeakPtr<WKFullScreenViewControllerVideoFullscreenModelClient> {
 public:
     void setParent(WKFullScreenViewController *parent) { m_parent = parent; }
 
@@ -100,11 +104,11 @@ public:
         if (m_interface == interface)
             return;
 
-        if (m_interface && m_interface->videoFullscreenModel())
-            m_interface->videoFullscreenModel()->removeClient(*this);
+        if (m_interface)
+            m_interface->videoFullscreenModel().removeClient(*this);
         m_interface = interface;
-        if (m_interface && m_interface->videoFullscreenModel())
-            m_interface->videoFullscreenModel()->addClient(*this);
+        if (m_interface)
+            m_interface->videoFullscreenModel().addClient(makeWeakPtr(*this));
     }
 
     VideoFullscreenInterfaceAVKit* interface() const { return m_interface.get(); }
@@ -268,9 +272,14 @@ private:
     _playbackClient.setInterface(playbackSessionInterface);
     _videoFullscreenClient.setInterface(videoFullscreenInterface);
 
-    PlaybackSessionModel* playbackSessionModel = playbackSessionInterface ? playbackSessionInterface->playbackSessionModel() : nullptr;
-    self.playing = playbackSessionModel ? playbackSessionModel->isPlaying() : NO;
-    [_pipButton setHidden:!playbackSessionModel];
+    if (!playbackSessionInterface) {
+        self.playing = NO;
+        [_pipButton setHidden:YES];
+        return;
+    }
+
+    self.playing = playbackSessionInterface->playbackSessionModel().isPlaying();
+    [_pipButton setHidden:NO];
 }
 
 - (void)setPrefersStatusBarHidden:(BOOL)value
@@ -516,14 +525,8 @@ private:
         return;
 
     PlatformPlaybackSessionInterface* playbackSessionInterface = playbackSessionManager->controlsManagerInterface();
-    if (!playbackSessionInterface)
-        return;
-
-    PlaybackSessionModel* playbackSessionModel = playbackSessionInterface->playbackSessionModel();
-    if (!playbackSessionModel)
-        return;
-
-    playbackSessionModel->togglePictureInPicture();
+    if (playbackSessionInterface)
+        playbackSessionInterface->playbackSessionModel().togglePictureInPicture();
 }
 
 - (void)_touchDetected:(id)sender
index b60a55c..60a7d8a 100644 (file)
@@ -52,7 +52,9 @@ static const NSTimeInterval DefaultWatchdogTimerInterval = 1;
 
 namespace WebKit {
 
-class WKFullScreenWindowControllerVideoFullscreenModelClient : WebCore::VideoFullscreenModelClient {
+class WKFullScreenWindowControllerVideoFullscreenModelClient 
+    : public CanMakeWeakPtr<WKFullScreenWindowControllerVideoFullscreenModelClient>
+    , public WebCore::VideoFullscreenModelClient {
 public:
     void setParent(WKFullScreenWindowController *parent) { m_parent = parent; }
 
@@ -61,11 +63,11 @@ public:
         if (m_interface == interface)
             return;
 
-        if (m_interface && m_interface->videoFullscreenModel())
-            m_interface->videoFullscreenModel()->removeClient(*this);
+        if (m_interface)
+            m_interface->videoFullscreenModel().removeClient(*this);
         m_interface = interface;
-        if (m_interface && m_interface->videoFullscreenModel())
-            m_interface->videoFullscreenModel()->addClient(*this);
+        if (m_interface)
+            m_interface->videoFullscreenModel().addClient(makeWeakPtr(this));
     }
 
     WebCore::VideoFullscreenInterfaceMac* interface() const { return m_interface.get(); }
index f0de62b..91ceffa 100644 (file)
@@ -47,6 +47,8 @@ class MessageReceiver;
 
 namespace WebCore {
 class Node;
+class PlaybackSessionModel;
+class PlaybackSessionModelClient;
 }
 
 namespace WebKit {
@@ -55,17 +57,17 @@ class WebPage;
 class PlaybackSessionManager;
 
 class PlaybackSessionInterfaceContext final
-    : public RefCounted<PlaybackSessionInterfaceContext>
-    , public WebCore::PlaybackSessionInterface
-    , public WebCore::PlaybackSessionModelClient {
+    : public WebCore::PlaybackSessionInterface
+    , public WebCore::PlaybackSessionModelClient
+    , public RefCounted<PlaybackSessionInterfaceContext> {
 public:
-    static Ref<PlaybackSessionInterfaceContext> create(PlaybackSessionManager& manager, uint64_t contextId)
+    static Ref<PlaybackSessionInterfaceContext> create(WeakPtr<PlaybackSessionManager>&& manager, uint64_t contextId)
     {
-        return adoptRef(*new PlaybackSessionInterfaceContext(manager, contextId));
+        return adoptRef(*new PlaybackSessionInterfaceContext(WTFMove(manager), contextId));
     }
     virtual ~PlaybackSessionInterfaceContext();
 
-    void invalidate() { m_manager = nullptr; }
+    WeakPtr<WebCore::PlaybackSessionModelClient> createWeakPtr() { return m_weakPtrFactory.createWeakPtr(*this); }
 
 private:
     friend class VideoFullscreenInterfaceContext;
@@ -91,13 +93,17 @@ private:
     void volumeChanged(double) final;
     void isPictureInPictureSupportedChanged(bool) final;
 
-    PlaybackSessionInterfaceContext(PlaybackSessionManager&, uint64_t contextId);
+    PlaybackSessionInterfaceContext(WeakPtr<PlaybackSessionManager>&&, uint64_t contextId);
 
-    PlaybackSessionManager* m_manager;
+    WeakPtr<PlaybackSessionManager> m_manager;
+    WeakPtrFactory<PlaybackSessionModelClient> m_weakPtrFactory;
     uint64_t m_contextId;
 };
 
-class PlaybackSessionManager : public RefCounted<PlaybackSessionManager>, private IPC::MessageReceiver {
+class PlaybackSessionManager
+    : public RefCounted<PlaybackSessionManager>
+    , private IPC::MessageReceiver
+    , public CanMakeWeakPtr<PlaybackSessionManager> {
 public:
     static Ref<PlaybackSessionManager> create(WebPage&);
     virtual ~PlaybackSessionManager();
@@ -166,6 +172,7 @@ protected:
     void setVolume(uint64_t contextId, double volume);
     void setPlayingOnSecondScreen(uint64_t contextId, bool value);
 
+    WeakPtrFactory<WebCore::PlaybackSessionModel> m_weakPtrFactory;
     WebPage* m_page;
     HashMap<WebCore::HTMLMediaElement*, uint64_t> m_mediaElements;
     HashMap<uint64_t, ModelInterfaceTuple> m_contextMap;
index d0aec25..372ac20 100644 (file)
@@ -54,15 +54,13 @@ static uint64_t nextContextId()
 
 #pragma mark - PlaybackSessionInterfaceContext
 
-PlaybackSessionInterfaceContext::PlaybackSessionInterfaceContext(PlaybackSessionManager& manager, uint64_t contextId)
-    : m_manager(&manager)
+PlaybackSessionInterfaceContext::PlaybackSessionInterfaceContext(WeakPtr<PlaybackSessionManager>&& manager, uint64_t contextId)
+    : m_manager(WTFMove(manager))
     , m_contextId(contextId)
 {
 }
 
-PlaybackSessionInterfaceContext::~PlaybackSessionInterfaceContext()
-{
-}
+PlaybackSessionInterfaceContext::~PlaybackSessionInterfaceContext() = default;
 
 void PlaybackSessionInterfaceContext::resetMediaState()
 {
@@ -185,10 +183,7 @@ PlaybackSessionManager::~PlaybackSessionManager()
         RefPtr<PlaybackSessionModelMediaElement> model;
         RefPtr<PlaybackSessionInterfaceContext> interface;
         std::tie(model, interface) = tuple;
-        model->removeClient(*interface);
         model->setMediaElement(nullptr);
-
-        interface->invalidate();
     }
 
     m_contextMap.clear();
@@ -208,9 +203,9 @@ void PlaybackSessionManager::invalidate()
 
 PlaybackSessionManager::ModelInterfaceTuple PlaybackSessionManager::createModelAndInterface(uint64_t contextId)
 {
-    RefPtr<PlaybackSessionModelMediaElement> model = PlaybackSessionModelMediaElement::create();
-    RefPtr<PlaybackSessionInterfaceContext> interface = PlaybackSessionInterfaceContext::create(*this, contextId);
-    model->addClient(*interface);
+    Ref<PlaybackSessionModelMediaElement> model = PlaybackSessionModelMediaElement::create();
+    Ref<PlaybackSessionInterfaceContext> interface = PlaybackSessionInterfaceContext::create(makeWeakPtr(this), contextId);
+    model->addClient(interface->createWeakPtr());
 
     return std::make_tuple(WTFMove(model), WTFMove(interface));
 }
@@ -241,8 +236,6 @@ void PlaybackSessionManager::removeContext(uint64_t contextId)
 
     RefPtr<HTMLMediaElement> mediaElement = model->mediaElement();
     model->setMediaElement(nullptr);
-    model->removeClient(*interface);
-    interface->invalidate();
     m_mediaElements.remove(mediaElement.get());
     m_contextMap.remove(contextId);
 }
@@ -284,6 +277,8 @@ void PlaybackSessionManager::setUpPlaybackControlsManager(WebCore::HTMLMediaElem
 
     addClientForContext(m_controlsManagerContextId);
 
+    if (!m_page)
+        return;
     m_page->videoControlsManagerDidChange();
     m_page->send(Messages::PlaybackSessionManagerProxy::SetUpPlaybackControlsManagerWithID(m_controlsManagerContextId), m_page->pageID());
 }
@@ -296,6 +291,9 @@ void PlaybackSessionManager::clearPlaybackControlsManager()
     removeClientForContext(m_controlsManagerContextId);
     m_controlsManagerContextId = 0;
 
+    if (!m_page)
+        return;
+
     m_page->videoControlsManagerDidChange();
     m_page->send(Messages::PlaybackSessionManagerProxy::ClearPlaybackControlsManager(), m_page->pageID());
 }
@@ -324,36 +322,45 @@ WebCore::HTMLMediaElement* PlaybackSessionManager::currentPlaybackControlsElemen
 
 void PlaybackSessionManager::resetMediaState(uint64_t contextId)
 {
-    m_page->send(Messages::PlaybackSessionManagerProxy::ResetMediaState(contextId), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManagerProxy::ResetMediaState(contextId), m_page->pageID());
 }
 
 void PlaybackSessionManager::durationChanged(uint64_t contextId, double duration)
 {
-    m_page->send(Messages::PlaybackSessionManagerProxy::DurationChanged(contextId, duration), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManagerProxy::DurationChanged(contextId, duration), m_page->pageID());
 }
 
 void PlaybackSessionManager::currentTimeChanged(uint64_t contextId, double currentTime, double anchorTime)
 {
-    m_page->send(Messages::PlaybackSessionManagerProxy::CurrentTimeChanged(contextId, currentTime, anchorTime), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManagerProxy::CurrentTimeChanged(contextId, currentTime, anchorTime), m_page->pageID());
 }
 
 void PlaybackSessionManager::bufferedTimeChanged(uint64_t contextId, double bufferedTime)
 {
-    m_page->send(Messages::PlaybackSessionManagerProxy::BufferedTimeChanged(contextId, bufferedTime), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManagerProxy::BufferedTimeChanged(contextId, bufferedTime), m_page->pageID());
 }
 
 void PlaybackSessionManager::playbackStartedTimeChanged(uint64_t contextId, double playbackStartedTime)
 {
-    m_page->send(Messages::PlaybackSessionManagerProxy::PlaybackStartedTimeChanged(contextId, playbackStartedTime), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManagerProxy::PlaybackStartedTimeChanged(contextId, playbackStartedTime), m_page->pageID());
 }
 
 void PlaybackSessionManager::rateChanged(uint64_t contextId, bool isPlaying, float playbackRate)
 {
-    m_page->send(Messages::PlaybackSessionManagerProxy::RateChanged(contextId, isPlaying, playbackRate), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManagerProxy::RateChanged(contextId, isPlaying, playbackRate), m_page->pageID());
 }
 
 void PlaybackSessionManager::seekableRangesChanged(uint64_t contextId, const WebCore::TimeRanges& timeRanges, double lastModifiedTime, double liveUpdateInterval)
 {
+    if (!m_page)
+        return;
+
     Vector<std::pair<double, double>> rangesVector;
     for (unsigned i = 0; i < timeRanges.length(); i++) {
         double start = timeRanges.ranges().start(i).toDouble();
@@ -365,47 +372,56 @@ void PlaybackSessionManager::seekableRangesChanged(uint64_t contextId, const Web
 
 void PlaybackSessionManager::canPlayFastReverseChanged(uint64_t contextId, bool value)
 {
-    m_page->send(Messages::PlaybackSessionManagerProxy::CanPlayFastReverseChanged(contextId, value), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManagerProxy::CanPlayFastReverseChanged(contextId, value), m_page->pageID());
 }
 
 void PlaybackSessionManager::audioMediaSelectionOptionsChanged(uint64_t contextId, const Vector<MediaSelectionOption>& options, uint64_t selectedIndex)
 {
-    m_page->send(Messages::PlaybackSessionManagerProxy::AudioMediaSelectionOptionsChanged(contextId, options, selectedIndex), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManagerProxy::AudioMediaSelectionOptionsChanged(contextId, options, selectedIndex), m_page->pageID());
 }
 
 void PlaybackSessionManager::legibleMediaSelectionOptionsChanged(uint64_t contextId, const Vector<MediaSelectionOption>& options, uint64_t selectedIndex)
 {
-    m_page->send(Messages::PlaybackSessionManagerProxy::LegibleMediaSelectionOptionsChanged(contextId, options, selectedIndex), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManagerProxy::LegibleMediaSelectionOptionsChanged(contextId, options, selectedIndex), m_page->pageID());
 }
 
 void PlaybackSessionManager::externalPlaybackChanged(uint64_t contextId, bool enabled, PlaybackSessionModel::ExternalPlaybackTargetType targetType, String localizedDeviceName)
 {
-    m_page->send(Messages::PlaybackSessionManagerProxy::ExternalPlaybackPropertiesChanged(contextId, enabled, static_cast<uint32_t>(targetType), localizedDeviceName), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManagerProxy::ExternalPlaybackPropertiesChanged(contextId, enabled, static_cast<uint32_t>(targetType), localizedDeviceName), m_page->pageID());
 }
 
 void PlaybackSessionManager::audioMediaSelectionIndexChanged(uint64_t contextId, uint64_t selectedIndex)
 {
-    m_page->send(Messages::PlaybackSessionManagerProxy::AudioMediaSelectionIndexChanged(contextId, selectedIndex), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManagerProxy::AudioMediaSelectionIndexChanged(contextId, selectedIndex), m_page->pageID());
 }
 
 void PlaybackSessionManager::legibleMediaSelectionIndexChanged(uint64_t contextId, uint64_t selectedIndex)
 {
-    m_page->send(Messages::PlaybackSessionManagerProxy::LegibleMediaSelectionIndexChanged(contextId, selectedIndex), m_page->pageID());
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManagerProxy::LegibleMediaSelectionIndexChanged(contextId, selectedIndex), m_page->pageID());
 }
 
 void PlaybackSessionManager::wirelessVideoPlaybackDisabledChanged(uint64_t contextId, bool disabled)
 {
-    m_page->send(Messages::PlaybackSessionManagerProxy::WirelessVideoPlaybackDisabledChanged(contextId, disabled));
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManagerProxy::WirelessVideoPlaybackDisabledChanged(contextId, disabled));
 }
 
 void PlaybackSessionManager::mutedChanged(uint64_t contextId, bool muted)
 {
-    m_page->send(Messages::PlaybackSessionManagerProxy::MutedChanged(contextId, muted));
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManagerProxy::MutedChanged(contextId, muted));
 }
 
 void PlaybackSessionManager::volumeChanged(uint64_t contextId, double volume)
 {
-    m_page->send(Messages::PlaybackSessionManagerProxy::VolumeChanged(contextId, volume));
+    if (m_page)
+        m_page->send(Messages::PlaybackSessionManagerProxy::VolumeChanged(contextId, volume));
 }
 
 void PlaybackSessionManager::isPictureInPictureSupportedChanged(uint64_t contextId, bool supported)
@@ -489,8 +505,10 @@ void PlaybackSessionManager::selectLegibleMediaOption(uint64_t contextId, uint64
 
 void PlaybackSessionManager::handleControlledElementIDRequest(uint64_t contextId)
 {
-    auto element = ensureModel(contextId).mediaElement();
-    if (element)
+    if (!m_page)
+        return;
+    
+    if (auto element = ensureModel(contextId).mediaElement())
         m_page->send(Messages::PlaybackSessionManagerProxy::HandleControlledElementIDResponse(contextId, element->getIdAttribute()));
 }
 
index ff8c4ba..d5e3a8f 100644 (file)
@@ -60,9 +60,9 @@ class VideoFullscreenInterfaceContext
     : public RefCounted<VideoFullscreenInterfaceContext>
     , public WebCore::VideoFullscreenModelClient {
 public:
-    static Ref<VideoFullscreenInterfaceContext> create(VideoFullscreenManager& manager, uint64_t contextId)
+    static Ref<VideoFullscreenInterfaceContext> create(WeakPtr<VideoFullscreenManager>&& manager, uint64_t contextId)
     {
-        return adoptRef(*new VideoFullscreenInterfaceContext(manager, contextId));
+        return adoptRef(*new VideoFullscreenInterfaceContext(WTFMove(manager), contextId));
     }
     virtual ~VideoFullscreenInterfaceContext();
 
@@ -86,14 +86,16 @@ public:
     bool isFullscreen() const { return m_isFullscreen; }
     void setIsFullscreen(bool flag) { m_isFullscreen = flag; }
 
+    WeakPtr<WebCore::VideoFullscreenModelClient> createWeakPtr() { return m_weakPtrFactory.createWeakPtr(*this); }
+
 private:
     // VideoFullscreenModelClient
     void hasVideoChanged(bool) override;
     void videoDimensionsChanged(const WebCore::FloatSize&) override;
 
-    VideoFullscreenInterfaceContext(VideoFullscreenManager&, uint64_t contextId);
+    VideoFullscreenInterfaceContext(WeakPtr<VideoFullscreenManager>&&, uint64_t contextId);
 
-    VideoFullscreenManager* m_manager;
+    WeakPtr<VideoFullscreenManager> m_manager;
     uint64_t m_contextId;
     std::unique_ptr<LayerHostingContext> m_layerHostingContext;
     bool m_isAnimating { false };
@@ -101,9 +103,13 @@ private:
     WebCore::HTMLMediaElementEnums::VideoFullscreenMode m_fullscreenMode { WebCore::HTMLMediaElementEnums::VideoFullscreenModeNone };
     bool m_fullscreenStandby { false };
     bool m_isFullscreen { false };
+    WeakPtrFactory<WebCore::VideoFullscreenModelClient> m_weakPtrFactory;
 };
 
-class VideoFullscreenManager : public RefCounted<VideoFullscreenManager>, private IPC::MessageReceiver {
+class VideoFullscreenManager
+    : public RefCounted<VideoFullscreenManager>
+    , public CanMakeWeakPtr<VideoFullscreenManager>
+    , private IPC::MessageReceiver {
 public:
     static Ref<VideoFullscreenManager> create(WebPage&, PlaybackSessionManager&);
     virtual ~VideoFullscreenManager();
index 719cc2b..814e2c8 100644 (file)
@@ -80,8 +80,8 @@ static IntRect inlineVideoFrame(HTMLVideoElement& element)
 
 #pragma mark - VideoFullscreenInterfaceContext
 
-VideoFullscreenInterfaceContext::VideoFullscreenInterfaceContext(VideoFullscreenManager& manager, uint64_t contextId)
-    : m_manager(&manager)
+VideoFullscreenInterfaceContext::VideoFullscreenInterfaceContext(WeakPtr<VideoFullscreenManager>&& manager, uint64_t contextId)
+    : m_manager(WTFMove(manager))
     , m_contextId(contextId)
 {
 }
@@ -129,9 +129,6 @@ VideoFullscreenManager::~VideoFullscreenManager()
         std::tie(model, interface) = tuple;
 
         model->setVideoElement(nullptr);
-        model->removeClient(*interface);
-
-        interface->invalidate();
     }
 
     m_contextMap.clear();
@@ -152,11 +149,11 @@ void VideoFullscreenManager::invalidate()
 VideoFullscreenManager::ModelInterfaceTuple VideoFullscreenManager::createModelAndInterface(uint64_t contextId)
 {
     RefPtr<VideoFullscreenModelVideoElement> model = VideoFullscreenModelVideoElement::create();
-    RefPtr<VideoFullscreenInterfaceContext> interface = VideoFullscreenInterfaceContext::create(*this, contextId);
+    RefPtr<VideoFullscreenInterfaceContext> interface = VideoFullscreenInterfaceContext::create(makeWeakPtr(*this), contextId);
     m_playbackSessionManager->addClientForContext(contextId);
 
     interface->setLayerHostingContext(LayerHostingContext::createForExternalHostingProcess());
-    model->addClient(*interface);
+    model->addClient(interface->createWeakPtr());
 
     return std::make_tuple(WTFMove(model), WTFMove(interface));
 }
@@ -189,8 +186,6 @@ void VideoFullscreenManager::removeContext(uint64_t contextId)
 
     RefPtr<HTMLVideoElement> videoElement = model->videoElement();
     model->setVideoElement(nullptr);
-    model->removeClient(*interface);
-    interface->invalidate();
     m_videoElements.remove(videoElement.get());
     m_contextMap.remove(contextId);
 }
index 1d5bdf6..403887a 100644 (file)
@@ -1,3 +1,16 @@
+2018-09-28  Jer Noble  <jer.noble@apple.com>
+
+        Refactoring: eliminate raw pointer usage in Fullscreen code
+        https://bugs.webkit.org/show_bug.cgi?id=188747
+        <rdar://problem/43541164>
+
+        Reviewed by Alex Christensen.
+
+        PlaybackSessionInterface no longer has an invalidate() method.
+
+        * WebView/WebView.mm:
+        (-[WebView _clearPlaybackControlsManager]):
+
 2018-09-26  Ryosuke Niwa  <rniwa@webkit.org>
 
         Use enum class in createMarkup arguments
index 0e4a675..72d8ad9 100644 (file)
@@ -9420,8 +9420,6 @@ bool LayerFlushController::flushLayers()
         return;
 
     _private->playbackSessionModel->setMediaElement(nullptr);
-    _private->playbackSessionInterface->invalidate();
-
     _private->playbackSessionModel = nullptr;
     _private->playbackSessionInterface = nullptr;
     [self updateTouchBar];