Refactoring: eliminate raw pointer usage in Fullscreen code
[WebKit-https.git] / Source / WebCore / platform / cocoa / VideoFullscreenModelVideoElement.mm
1 /*
2  * Copyright (C) 2014 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 #import "config.h"
27
28 #if PLATFORM(IOS) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE))
29 #import "VideoFullscreenModelVideoElement.h"
30
31 #import "DOMWindow.h"
32 #import "History.h"
33 #import "Logging.h"
34 #import "MediaControlsHost.h"
35 #import "PlaybackSessionModelMediaElement.h"
36 #import <QuartzCore/CoreAnimation.h>
37 #import <WebCore/Event.h>
38 #import <WebCore/EventListener.h>
39 #import <WebCore/EventNames.h>
40 #import <WebCore/HTMLElement.h>
41 #import <WebCore/HTMLVideoElement.h>
42 #import <WebCore/Page.h>
43 #import <WebCore/TextTrackList.h>
44 #import <WebCore/TimeRanges.h>
45 #import <wtf/NeverDestroyed.h>
46 #import <wtf/SoftLinking.h>
47
48 namespace WebCore {
49
50
51 class VideoFullscreenModelVideoElement::MediaElementEventListener final : public EventListener {
52 public:
53     MediaElementEventListener(WeakPtr<VideoFullscreenModelVideoElement>&& parent)
54         : EventListener(CPPEventListenerType)
55         , m_parent(WTFMove(parent))
56     {
57     }
58 private:
59     void handleEvent(WebCore::ScriptExecutionContext&, WebCore::Event& event) final
60     {
61         if (m_parent)
62             m_parent->updateForEventName(event.type());
63     }
64     bool operator==(const EventListener& rhs) const final { return static_cast<const WebCore::EventListener*>(this) == &rhs; }
65
66     WeakPtr<VideoFullscreenModelVideoElement> m_parent;
67 };
68
69 VideoFullscreenModelVideoElement::VideoFullscreenModelVideoElement()
70     : m_eventListener(adoptRef(*new MediaElementEventListener(makeWeakPtr(*this))))
71 {
72     LOG(Fullscreen, "VideoFullscreenModelVideoElement %p ctor", this);
73 }
74
75 VideoFullscreenModelVideoElement::~VideoFullscreenModelVideoElement()
76 {
77     LOG(Fullscreen, "VideoFullscreenModelVideoElement %p dtor", this);
78 }
79
80 void VideoFullscreenModelVideoElement::setVideoElement(HTMLVideoElement* videoElement)
81 {
82     if (m_videoElement == videoElement)
83         return;
84
85     LOG(Fullscreen, "VideoFullscreenModelVideoElement %p setVideoElement(%p)", this, videoElement);
86
87     if (m_videoElement && m_videoElement->videoFullscreenLayer())
88         m_videoElement->setVideoFullscreenLayer(nullptr);
89
90     if (m_videoElement) {
91         for (auto& eventName : observedEventNames())
92             m_videoElement->removeEventListener(eventName, m_eventListener.copyRef(), false);
93     }
94
95     m_videoElement = videoElement;
96
97     if (m_videoElement) {
98         for (auto& eventName : observedEventNames())
99             m_videoElement->addEventListener(eventName, m_eventListener.copyRef(), false);
100     }
101
102     updateForEventName(eventNameAll());
103 }
104
105 void VideoFullscreenModelVideoElement::updateForEventName(const WTF::AtomicString& eventName)
106 {
107     if (m_clients.isEmpty())
108         return;
109     
110     bool all = eventName == eventNameAll();
111
112     if (all
113         || eventName == eventNames().resizeEvent) {
114         setHasVideo(m_videoElement);
115         setVideoDimensions(m_videoElement ? FloatSize(m_videoElement->videoWidth(), m_videoElement->videoHeight()) : FloatSize());
116     }
117 }
118
119 void VideoFullscreenModelVideoElement::willExitFullscreen()
120 {
121     if (m_videoElement)
122         m_videoElement->willExitFullscreen();
123 }
124
125 void VideoFullscreenModelVideoElement::setVideoFullscreenLayer(PlatformLayer* videoLayer, WTF::Function<void()>&& completionHandler)
126 {
127     if (m_videoFullscreenLayer == videoLayer) {
128         completionHandler();
129         return;
130     }
131     
132     m_videoFullscreenLayer = videoLayer;
133 #if PLATFORM(MAC)
134     [m_videoFullscreenLayer setAnchorPoint:CGPointMake(0, 0)];
135 #else
136     [m_videoFullscreenLayer setAnchorPoint:CGPointMake(0.5, 0.5)];
137 #endif
138     [m_videoFullscreenLayer setBounds:m_videoFrame];
139     
140     if (!m_videoElement) {
141         completionHandler();
142         return;
143     }
144
145     m_videoElement->setVideoFullscreenLayer(m_videoFullscreenLayer.get(), WTFMove(completionHandler));
146 }
147
148 void VideoFullscreenModelVideoElement::waitForPreparedForInlineThen(WTF::Function<void()>&& completionHandler)
149 {
150     if (!m_videoElement) {
151         completionHandler();
152         return;
153     }
154
155     m_videoElement->waitForPreparedForInlineThen(WTFMove(completionHandler));
156 }
157
158 void VideoFullscreenModelVideoElement::requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenMode mode, bool finishedWithMedia)
159 {
160     if (m_videoElement && m_videoElement->fullscreenMode() != mode)
161         m_videoElement->setFullscreenMode(mode);
162
163     if (m_videoElement && finishedWithMedia && mode == MediaPlayerEnums::VideoFullscreenModeNone) {
164         if (m_videoElement->document().isMediaDocument()) {
165             if (DOMWindow* window = m_videoElement->document().domWindow()) {
166                 if (History* history = window->history())
167                     history->back();
168             }
169         }
170     }
171 }
172
173 void VideoFullscreenModelVideoElement::setVideoLayerFrame(FloatRect rect)
174 {
175     m_videoFrame = rect;
176     [m_videoFullscreenLayer setBounds:CGRect(rect)];
177     if (m_videoElement)
178         m_videoElement->setVideoFullscreenFrame(rect);
179 }
180
181 void VideoFullscreenModelVideoElement::setVideoLayerGravity(VideoFullscreenModel::VideoGravity gravity)
182 {
183     MediaPlayer::VideoGravity videoGravity = MediaPlayer::VideoGravityResizeAspect;
184     if (gravity == VideoFullscreenModel::VideoGravityResize)
185         videoGravity = MediaPlayer::VideoGravityResize;
186     else if (gravity == VideoFullscreenModel::VideoGravityResizeAspect)
187         videoGravity = MediaPlayer::VideoGravityResizeAspect;
188     else if (gravity == VideoFullscreenModel::VideoGravityResizeAspectFill)
189         videoGravity = MediaPlayer::VideoGravityResizeAspectFill;
190     else
191         ASSERT_NOT_REACHED();
192     
193     m_videoElement->setVideoFullscreenGravity(videoGravity);
194 }
195
196 const Vector<AtomicString>& VideoFullscreenModelVideoElement::observedEventNames()
197 {
198     static const auto names = makeNeverDestroyed(Vector<AtomicString> { eventNames().resizeEvent });
199     return names;
200 }
201
202 const AtomicString& VideoFullscreenModelVideoElement::eventNameAll()
203 {
204     static NeverDestroyed<AtomicString> sEventNameAll = "allEvents";
205     return sEventNameAll;
206 }
207
208 void VideoFullscreenModelVideoElement::fullscreenModeChanged(HTMLMediaElementEnums::VideoFullscreenMode videoFullscreenMode)
209 {
210     if (m_videoElement)
211         m_videoElement->fullscreenModeChanged(videoFullscreenMode);
212 }
213
214 void VideoFullscreenModelVideoElement::addClient(WeakPtr<VideoFullscreenModelClient>&& client)
215 {
216     m_clients.add(WTFMove(client));
217 }
218
219 void VideoFullscreenModelVideoElement::removeClient(VideoFullscreenModelClient& client)
220 {
221     m_clients.remove(client);
222 }
223
224 bool VideoFullscreenModelVideoElement::isVisible() const
225 {
226     if (!m_videoElement)
227         return false;
228
229     if (Page* page = m_videoElement->document().page())
230         return page->isVisible();
231
232     return false;
233 }
234
235 void VideoFullscreenModelVideoElement::setHasVideo(bool hasVideo)
236 {
237     if (hasVideo == m_hasVideo)
238         return;
239
240     m_hasVideo = hasVideo;
241
242     m_clients.forEachNonNullMember([hasVideo] (auto& client) {
243         client.hasVideoChanged(hasVideo);
244     });
245 }
246
247 void VideoFullscreenModelVideoElement::setVideoDimensions(const FloatSize& videoDimensions)
248 {
249     if (m_videoDimensions == videoDimensions)
250         return;
251
252     m_videoDimensions = videoDimensions;
253
254     m_clients.forEachNonNullMember([videoDimensions] (auto& client) {
255         client.videoDimensionsChanged(videoDimensions);
256     });
257 }
258
259 void VideoFullscreenModelVideoElement::willEnterPictureInPicture()
260 {
261     m_clients.forEachNonNullMember([] (auto& client) {
262         client.willEnterPictureInPicture();
263     });
264 }
265
266 void VideoFullscreenModelVideoElement::didEnterPictureInPicture()
267 {
268     m_clients.forEachNonNullMember([] (auto& client) {
269         client.didEnterPictureInPicture();
270     });
271 }
272
273 void VideoFullscreenModelVideoElement::failedToEnterPictureInPicture()
274 {
275     m_clients.forEachNonNullMember([] (auto& client) {
276         client.failedToEnterPictureInPicture();
277     });
278 }
279
280 void VideoFullscreenModelVideoElement::willExitPictureInPicture()
281 {
282     m_clients.forEachNonNullMember([] (auto& client) {
283         client.willExitPictureInPicture();
284     });
285 }
286
287 void VideoFullscreenModelVideoElement::didExitPictureInPicture()
288 {
289     m_clients.forEachNonNullMember([] (auto& client) {
290         client.didExitPictureInPicture();
291     });
292 }
293
294 } // namespace WebCore
295
296 #endif