c0a4fa5f0eb5af0f87f585dcca5d65706a7f504e
[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 using namespace WebCore;
49
50 VideoFullscreenModelVideoElement::VideoFullscreenModelVideoElement()
51     : EventListener(EventListener::CPPEventListenerType)
52 {
53 }
54
55 VideoFullscreenModelVideoElement::~VideoFullscreenModelVideoElement()
56 {
57 }
58
59 void VideoFullscreenModelVideoElement::setVideoElement(HTMLVideoElement* videoElement)
60 {
61     if (m_videoElement == videoElement)
62         return;
63
64     if (m_videoElement && m_videoElement->videoFullscreenLayer())
65         m_videoElement->setVideoFullscreenLayer(nullptr);
66
67     if (m_videoElement && m_isListening) {
68         for (auto& eventName : observedEventNames())
69             m_videoElement->removeEventListener(eventName, *this, false);
70     }
71     m_isListening = false;
72
73     m_videoElement = videoElement;
74
75     if (m_videoElement) {
76         for (auto& eventName : observedEventNames())
77             m_videoElement->addEventListener(eventName, *this, false);
78         m_isListening = true;
79     }
80
81     updateForEventName(eventNameAll());
82 }
83
84 void VideoFullscreenModelVideoElement::handleEvent(WebCore::ScriptExecutionContext&, WebCore::Event& event)
85 {
86     updateForEventName(event.type());
87 }
88
89 void VideoFullscreenModelVideoElement::updateForEventName(const WTF::AtomicString& eventName)
90 {
91     if (m_clients.isEmpty())
92         return;
93     
94     bool all = eventName == eventNameAll();
95
96     if (all
97         || eventName == eventNames().resizeEvent) {
98         setHasVideo(m_videoElement);
99         setVideoDimensions(m_videoElement ? FloatSize(m_videoElement->videoWidth(), m_videoElement->videoHeight()) : FloatSize());
100     }
101 }
102
103 void VideoFullscreenModelVideoElement::willExitFullscreen()
104 {
105     if (m_videoElement)
106         m_videoElement->willExitFullscreen();
107 }
108
109 void VideoFullscreenModelVideoElement::setVideoFullscreenLayer(PlatformLayer* videoLayer, WTF::Function<void()>&& completionHandler)
110 {
111     if (m_videoFullscreenLayer == videoLayer) {
112         completionHandler();
113         return;
114     }
115     
116     m_videoFullscreenLayer = videoLayer;
117 #if PLATFORM(MAC)
118     [m_videoFullscreenLayer setAnchorPoint:CGPointMake(0, 0)];
119 #else
120     [m_videoFullscreenLayer setAnchorPoint:CGPointMake(0.5, 0.5)];
121 #endif
122     [m_videoFullscreenLayer setBounds:m_videoFrame];
123     
124     if (!m_videoElement) {
125         completionHandler();
126         return;
127     }
128
129     m_videoElement->setVideoFullscreenLayer(m_videoFullscreenLayer.get(), WTFMove(completionHandler));
130 }
131
132 void VideoFullscreenModelVideoElement::waitForPreparedForInlineThen(WTF::Function<void()>&& completionHandler)
133 {
134     if (!m_videoElement) {
135         completionHandler();
136         return;
137     }
138
139     m_videoElement->waitForPreparedForInlineThen(WTFMove(completionHandler));
140 }
141
142 void VideoFullscreenModelVideoElement::requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenMode mode, bool finishedWithMedia)
143 {
144     if (m_videoElement && m_videoElement->fullscreenMode() != mode)
145         m_videoElement->setFullscreenMode(mode);
146
147     if (m_videoElement && finishedWithMedia && mode == MediaPlayerEnums::VideoFullscreenModeNone) {
148         if (m_videoElement->document().isMediaDocument()) {
149             if (DOMWindow* window = m_videoElement->document().domWindow()) {
150                 if (History* history = window->history())
151                     history->back();
152             }
153         }
154     }
155 }
156
157 void VideoFullscreenModelVideoElement::setVideoLayerFrame(FloatRect rect)
158 {
159     m_videoFrame = rect;
160     [m_videoFullscreenLayer setBounds:CGRect(rect)];
161     if (m_videoElement)
162         m_videoElement->setVideoFullscreenFrame(rect);
163 }
164
165 void VideoFullscreenModelVideoElement::setVideoLayerGravity(VideoFullscreenModel::VideoGravity gravity)
166 {
167     MediaPlayer::VideoGravity videoGravity = MediaPlayer::VideoGravityResizeAspect;
168     if (gravity == VideoFullscreenModel::VideoGravityResize)
169         videoGravity = MediaPlayer::VideoGravityResize;
170     else if (gravity == VideoFullscreenModel::VideoGravityResizeAspect)
171         videoGravity = MediaPlayer::VideoGravityResizeAspect;
172     else if (gravity == VideoFullscreenModel::VideoGravityResizeAspectFill)
173         videoGravity = MediaPlayer::VideoGravityResizeAspectFill;
174     else
175         ASSERT_NOT_REACHED();
176     
177     m_videoElement->setVideoFullscreenGravity(videoGravity);
178 }
179
180 const Vector<AtomicString>& VideoFullscreenModelVideoElement::observedEventNames()
181 {
182     static const auto names = makeNeverDestroyed(Vector<AtomicString> { eventNames().resizeEvent });
183     return names;
184 }
185
186 const AtomicString& VideoFullscreenModelVideoElement::eventNameAll()
187 {
188     static NeverDestroyed<AtomicString> sEventNameAll = "allEvents";
189     return sEventNameAll;
190 }
191
192 void VideoFullscreenModelVideoElement::fullscreenModeChanged(HTMLMediaElementEnums::VideoFullscreenMode videoFullscreenMode)
193 {
194     if (m_videoElement)
195         m_videoElement->fullscreenModeChanged(videoFullscreenMode);
196 }
197
198 void VideoFullscreenModelVideoElement::addClient(VideoFullscreenModelClient& client)
199 {
200     ASSERT(!m_clients.contains(&client));
201     m_clients.add(&client);
202 }
203
204 void VideoFullscreenModelVideoElement::removeClient(VideoFullscreenModelClient& client)
205 {
206     ASSERT(m_clients.contains(&client));
207     m_clients.remove(&client);
208 }
209
210 bool VideoFullscreenModelVideoElement::isVisible() const
211 {
212     if (!m_videoElement)
213         return false;
214
215     if (Page* page = m_videoElement->document().page())
216         return page->isVisible();
217
218     return false;
219 }
220
221 void VideoFullscreenModelVideoElement::setHasVideo(bool hasVideo)
222 {
223     if (hasVideo == m_hasVideo)
224         return;
225
226     m_hasVideo = hasVideo;
227
228     for (auto& client : m_clients)
229         client->hasVideoChanged(m_hasVideo);
230 }
231
232 void VideoFullscreenModelVideoElement::setVideoDimensions(const FloatSize& videoDimensions)
233 {
234     if (m_videoDimensions == videoDimensions)
235         return;
236
237     m_videoDimensions = videoDimensions;
238
239     for (auto& client : m_clients)
240         client->videoDimensionsChanged(m_videoDimensions);
241 }
242
243 void VideoFullscreenModelVideoElement::willEnterPictureInPicture()
244 {
245     for (auto& client : m_clients)
246         client->willEnterPictureInPicture();
247 }
248
249 void VideoFullscreenModelVideoElement::didEnterPictureInPicture()
250 {
251     for (auto& client : m_clients)
252         client->didEnterPictureInPicture();
253 }
254
255 void VideoFullscreenModelVideoElement::failedToEnterPictureInPicture()
256 {
257     for (auto& client : m_clients)
258         client->failedToEnterPictureInPicture();
259 }
260
261 void VideoFullscreenModelVideoElement::willExitPictureInPicture()
262 {
263     for (auto& client : m_clients)
264         client->willExitPictureInPicture();
265 }
266
267 void VideoFullscreenModelVideoElement::didExitPictureInPicture()
268 {
269     for (auto& client : m_clients)
270         client->didExitPictureInPicture();
271 }
272
273 #endif