PiP from Element Fullscreen should match AVKit's behavior
[WebKit-https.git] / Source / WebCore / platform / ios / VideoFullscreenInterfaceAVKit.h
1 /*
2  * Copyright (C) 2014-2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26
27 #pragma once
28
29 #if PLATFORM(IOS)
30
31 #include "EventListener.h"
32 #include "HTMLMediaElementEnums.h"
33 #include "PlatformLayer.h"
34 #include "PlaybackSessionInterfaceAVKit.h"
35 #include "VideoFullscreenModel.h"
36 #include <objc/objc.h>
37 #include <wtf/Forward.h>
38 #include <wtf/Function.h>
39 #include <wtf/RefCounted.h>
40 #include <wtf/RefPtr.h>
41 #include <wtf/RetainPtr.h>
42 #include <wtf/RunLoop.h>
43
44 OBJC_CLASS UIViewController;
45 OBJC_CLASS UIWindow;
46 OBJC_CLASS UIView;
47 OBJC_CLASS CALayer;
48 OBJC_CLASS WebAVPlayerController;
49 OBJC_CLASS WebAVPlayerLayerView;
50 OBJC_CLASS WebAVPlayerLayer;
51 OBJC_CLASS WebAVPlayerViewController;
52 OBJC_CLASS WebAVPlayerViewControllerDelegate;
53 OBJC_CLASS NSError;
54
55 namespace WebCore {
56 class IntRect;
57 class FloatSize;
58 class VideoFullscreenModel;
59 class VideoFullscreenChangeObserver;
60     
61 class VideoFullscreenInterfaceAVKit final
62     : public VideoFullscreenModelClient
63     , public PlaybackSessionModelClient
64     , public ThreadSafeRefCounted<VideoFullscreenInterfaceAVKit> {
65
66 public:
67     WEBCORE_EXPORT static Ref<VideoFullscreenInterfaceAVKit> create(PlaybackSessionInterfaceAVKit&);
68     virtual ~VideoFullscreenInterfaceAVKit();
69     WEBCORE_EXPORT void setVideoFullscreenModel(VideoFullscreenModel*);
70     WEBCORE_EXPORT void setVideoFullscreenChangeObserver(VideoFullscreenChangeObserver*);
71     PlaybackSessionInterfaceAVKit& playbackSessionInterface() const { return m_playbackSessionInterface.get(); }
72     PlaybackSessionModel* playbackSessionModel() const { return m_playbackSessionInterface->playbackSessionModel(); }
73
74     // VideoFullscreenModelClient
75     WEBCORE_EXPORT void hasVideoChanged(bool) final;
76     WEBCORE_EXPORT void videoDimensionsChanged(const FloatSize&) final;
77
78     // PlaybackSessionModelClient
79     WEBCORE_EXPORT void externalPlaybackChanged(bool enabled, PlaybackSessionModel::ExternalPlaybackTargetType, const String& localizedDeviceName) final;
80
81     WEBCORE_EXPORT void setupFullscreen(UIView&, const IntRect& initialRect, UIView *, HTMLMediaElementEnums::VideoFullscreenMode, bool allowsPictureInPicturePlayback, bool standby);
82     WEBCORE_EXPORT void enterFullscreen();
83     WEBCORE_EXPORT void exitFullscreen(const IntRect& finalRect);
84     WEBCORE_EXPORT void cleanupFullscreen();
85     WEBCORE_EXPORT void invalidate();
86     WEBCORE_EXPORT void requestHideAndExitFullscreen();
87     WEBCORE_EXPORT void preparedToReturnToInline(bool visible, const IntRect& inlineRect);
88     WEBCORE_EXPORT void preparedToExitFullscreen();
89 #if ENABLE(FULLSCREEN_API)
90     WEBCORE_EXPORT void setHasVideoContentLayer(bool);
91     WEBCORE_EXPORT void setInlineRect(const IntRect&, bool visible);
92 #endif
93
94     enum class ExitFullScreenReason {
95         DoneButtonTapped,
96         FullScreenButtonTapped,
97         PinchGestureHandled,
98         RemoteControlStopEventReceived,
99         PictureInPictureStarted
100     };
101
102     class Mode {
103         HTMLMediaElementEnums::VideoFullscreenMode m_mode { HTMLMediaElementEnums::VideoFullscreenModeNone };
104
105     public:
106         Mode() = default;
107         Mode(const Mode&) = default;
108         Mode(HTMLMediaElementEnums::VideoFullscreenMode mode) : m_mode(mode) { }
109         void operator=(HTMLMediaElementEnums::VideoFullscreenMode mode) { m_mode = mode; }
110         HTMLMediaElementEnums::VideoFullscreenMode mode() const { return m_mode; }
111
112         void setModeValue(HTMLMediaElementEnums::VideoFullscreenMode mode, bool value) { value ? setMode(mode) : clearMode(mode); }
113         void setMode(HTMLMediaElementEnums::VideoFullscreenMode mode) { m_mode |= mode; }
114         void clearMode(HTMLMediaElementEnums::VideoFullscreenMode mode) { m_mode &= ~mode; }
115         bool hasMode(HTMLMediaElementEnums::VideoFullscreenMode mode) const { return m_mode & mode; }
116
117         bool isPictureInPicture() const { return m_mode == HTMLMediaElementEnums::VideoFullscreenModePictureInPicture; }
118         bool isFullscreen() const { return m_mode == HTMLMediaElementEnums::VideoFullscreenModeStandard; }
119
120         void setPictureInPicture(bool value) { setModeValue(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture, value); }
121         void setFullscreen(bool value) { setModeValue(HTMLMediaElementEnums::VideoFullscreenModeStandard, value); }
122
123         bool hasFullscreen() const { return hasMode(HTMLMediaElementEnums::VideoFullscreenModeStandard); }
124         bool hasPictureInPicture() const { return hasMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture); }
125
126         bool hasVideo() const { return m_mode & (HTMLMediaElementEnums::VideoFullscreenModeStandard | HTMLMediaElementEnums::VideoFullscreenModePictureInPicture); }
127     };
128
129     Mode m_currentMode;
130 #if ENABLE(FULLSCREEN_API)
131     Mode m_targetMode;
132 #endif
133
134     VideoFullscreenModel* videoFullscreenModel() const { return m_videoFullscreenModel; }
135     bool shouldExitFullscreenWithReason(ExitFullScreenReason);
136     HTMLMediaElementEnums::VideoFullscreenMode mode() const { return m_currentMode.mode(); }
137     bool allowsPictureInPicturePlayback() const { return m_allowsPictureInPicturePlayback; }
138     WEBCORE_EXPORT bool mayAutomaticallyShowVideoPictureInPicture() const;
139     void fullscreenMayReturnToInline(WTF::Function<void(bool)>&& callback);
140     bool wirelessVideoPlaybackDisabled() const;
141     WEBCORE_EXPORT void applicationDidBecomeActive();
142
143     void willStartPictureInPicture();
144     void didStartPictureInPicture();
145     void failedToStartPictureInPicture();
146     void willStopPictureInPicture();
147     void didStopPictureInPicture();
148     void prepareForPictureInPictureStopWithCompletionHandler(void (^)(BOOL));
149 #if ENABLE(FULLSCREEN_API)
150     void exitFullscreenHandler(BOOL success, NSError *);
151     void enterFullscreenHandler(BOOL success, NSError *);
152 #endif
153     bool isPlayingVideoInEnhancedFullscreen() const;
154
155     WEBCORE_EXPORT void setMode(HTMLMediaElementEnums::VideoFullscreenMode);
156     void clearMode(HTMLMediaElementEnums::VideoFullscreenMode);
157     bool hasMode(HTMLMediaElementEnums::VideoFullscreenMode mode) const { return m_currentMode.hasMode(mode); }
158
159 #if PLATFORM(IOS)
160     UIViewController *presentingViewController();
161     UIViewController *fullscreenViewController() const { return m_viewController.get(); }
162     WebAVPlayerLayerView* playerLayerView() const { return m_playerLayerView.get(); }
163     WEBCORE_EXPORT bool pictureInPictureWasStartedWhenEnteringBackground() const;
164 #endif
165
166 protected:
167     WEBCORE_EXPORT VideoFullscreenInterfaceAVKit(PlaybackSessionInterfaceAVKit&);
168
169 #if ENABLE(FULLSCREEN_API)
170     void doSetup();
171     void finalizeSetup();
172     void doExitFullscreen();
173     void returnToStandby();
174 #else
175     void enterPictureInPicture();
176     void enterFullscreenStandard();
177 #endif
178     void doEnterFullscreen();
179     void watchdogTimerFired();
180     WebAVPlayerController *playerController() const;
181
182     Ref<PlaybackSessionInterfaceAVKit> m_playbackSessionInterface;
183     RetainPtr<WebAVPlayerViewControllerDelegate> m_playerViewControllerDelegate;
184     RetainPtr<WebAVPlayerViewController> m_playerViewController;
185     VideoFullscreenModel* m_videoFullscreenModel { nullptr };
186     VideoFullscreenChangeObserver* m_fullscreenChangeObserver { nullptr };
187
188     // These are only used when fullscreen is presented in a separate window.
189     RetainPtr<UIWindow> m_window;
190     RetainPtr<UIViewController> m_viewController;
191     RetainPtr<UIView> m_videoView;
192     RetainPtr<UIView> m_parentView;
193     RetainPtr<UIWindow> m_parentWindow;
194     RetainPtr<WebAVPlayerLayerView> m_playerLayerView;
195     WTF::Function<void(bool)> m_prepareToInlineCallback;
196     RunLoop::Timer<VideoFullscreenInterfaceAVKit> m_watchdogTimer;
197     FloatRect m_inlineRect;
198     bool m_allowsPictureInPicturePlayback { false };
199     bool m_wirelessVideoPlaybackDisabled { true };
200     bool m_shouldReturnToFullscreenWhenStoppingPiP { false };
201     bool m_restoringFullscreenForPictureInPictureStop { false };
202
203 #if ENABLE(FULLSCREEN_API)
204     bool m_setupNeedsInlineRect { false };
205     bool m_exitFullscreenNeedInlineRect { false };
206
207     bool m_finalizeSetupNeedsVideoContentLayer { false };
208     bool m_cleanupNeedsReturnVideoContentLayer { false };
209
210     bool m_returnToStandbyNeedsReturnVideoContentLayer { false };
211     bool m_finalizeSetupNeedsReturnVideoContentLayer { false };
212
213     bool m_exitFullscreenNeedsExitFullscreen { false };
214     bool m_exitFullscreenNeedsExitPictureInPicture { false };
215     bool m_exitFullscreenNeedsReturnContentLayer { false };
216
217     bool m_enterFullscreenNeedsEnterFullscreen { false };
218     bool m_enterFullscreenNeedsExitFullscreen { false };
219     bool m_enterFullscreenNeedsEnterPictureInPicture { false };
220     bool m_enterFullscreenNeedsExitPictureInPicture { false };
221
222     bool m_hasVideoContentLayer { false };
223
224     bool m_hasUpdatedInlineRect { false };
225     bool m_inlineIsVisible { false };
226     bool m_standby { false };
227     bool m_targetStandby { false };
228 #else
229     bool m_exitRequested { false };
230     bool m_exitCompleted { false };
231     bool m_enterRequested { false };
232     bool m_shouldReturnToFullscreenAfterEnteringForeground { false };
233     bool m_waitingForPreparedToExit { false };
234 #endif
235 };
236
237 }
238
239 #endif // PLATFORM(IOS)
240