Add WebSocketProvider stub
[WebKit-https.git] / Source / WebCore / html / shadow / MediaControls.cpp
1 /*
2  * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
3  * Copyright (C) 2011, 2012 Google Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28
29 #if ENABLE(VIDEO)
30 #include "MediaControls.h"
31
32 #include "ExceptionCodePlaceholder.h"
33 #include "Page.h"
34 #include "Settings.h"
35
36 namespace WebCore {
37
38 MediaControls::MediaControls(Document& document)
39     : HTMLDivElement(HTMLNames::divTag, document)
40     , m_mediaController(0)
41     , m_panel(0)
42 #if ENABLE(VIDEO_TRACK)
43     , m_textDisplayContainer(0)
44 #endif
45     , m_playButton(0)
46     , m_currentTimeDisplay(0)
47     , m_timeline(0)
48     , m_panelMuteButton(0)
49     , m_volumeSlider(0)
50     , m_toggleClosedCaptionsButton(0)
51     , m_fullScreenButton(0)
52     , m_hideFullscreenControlsTimer(*this, &MediaControls::hideFullscreenControlsTimerFired)
53     , m_isFullscreen(false)
54     , m_isMouseOverControls(false)
55 {
56     setPseudo(AtomicString("-webkit-media-controls", AtomicString::ConstructFromLiteral));
57 }
58
59 void MediaControls::setMediaController(MediaControllerInterface* controller)
60 {
61     if (m_mediaController == controller)
62         return;
63     m_mediaController = controller;
64
65     if (m_panel)
66         m_panel->setMediaController(controller);
67 #if ENABLE(VIDEO_TRACK)
68     if (m_textDisplayContainer)
69         m_textDisplayContainer->setMediaController(controller);
70 #endif
71     if (m_playButton)
72         m_playButton->setMediaController(controller);
73     if (m_currentTimeDisplay)
74         m_currentTimeDisplay->setMediaController(controller);
75     if (m_timeline)
76         m_timeline->setMediaController(controller);
77     if (m_panelMuteButton)
78         m_panelMuteButton->setMediaController(controller);
79     if (m_volumeSlider)
80         m_volumeSlider->setMediaController(controller);
81     if (m_toggleClosedCaptionsButton)
82         m_toggleClosedCaptionsButton->setMediaController(controller);
83     if (m_fullScreenButton)
84         m_fullScreenButton->setMediaController(controller);
85 }
86
87 void MediaControls::reset()
88 {
89     Page* page = document().page();
90     if (!page)
91         return;
92
93     m_playButton->updateDisplayType();
94
95     updateCurrentTimeDisplay();
96
97     double duration = m_mediaController->duration();
98     if (std::isfinite(duration) || page->theme().hasOwnDisabledStateHandlingFor(MediaSliderPart)) {
99         m_timeline->setDuration(duration);
100         m_timeline->setPosition(m_mediaController->currentTime());
101     }
102
103     if (m_mediaController->hasAudio() || page->theme().hasOwnDisabledStateHandlingFor(MediaMuteButtonPart))
104         m_panelMuteButton->show();
105     else
106         m_panelMuteButton->hide();
107
108     if (m_volumeSlider) {
109         if (!m_mediaController->hasAudio())
110             m_volumeSlider->hide();
111         else {
112             m_volumeSlider->show();
113             setSliderVolume();
114         }
115     }
116
117     refreshClosedCaptionsButtonVisibility();
118
119     if (m_fullScreenButton) {
120         if (m_mediaController->supportsFullscreen(HTMLMediaElementEnums::VideoFullscreenModeStandard) && m_mediaController->hasVideo())
121             m_fullScreenButton->show();
122         else
123             m_fullScreenButton->hide();
124     }
125
126     makeOpaque();
127 }
128
129 void MediaControls::reportedError()
130 {
131     Page* page = document().page();
132     if (!page)
133         return;
134
135     if (!page->theme().hasOwnDisabledStateHandlingFor(MediaMuteButtonPart)) {
136         m_panelMuteButton->hide();
137         m_volumeSlider->hide();
138     }
139
140     if (m_toggleClosedCaptionsButton && !page->theme().hasOwnDisabledStateHandlingFor(MediaToggleClosedCaptionsButtonPart))
141         m_toggleClosedCaptionsButton->hide();
142
143     if (m_fullScreenButton && !page->theme().hasOwnDisabledStateHandlingFor(MediaEnterFullscreenButtonPart))
144         m_fullScreenButton->hide();
145 }
146
147 void MediaControls::loadedMetadata()
148 {
149     reset();
150 }
151
152 void MediaControls::show()
153 {
154     makeOpaque();
155     m_panel->setIsDisplayed(true);
156     m_panel->show();
157 }
158
159 void MediaControls::hide()
160 {
161     m_panel->setIsDisplayed(false);
162     m_panel->hide();
163 }
164
165 void MediaControls::makeOpaque()
166 {
167     m_panel->makeOpaque();
168 }
169
170 void MediaControls::makeTransparent()
171 {
172     m_panel->makeTransparent();
173 }
174
175 bool MediaControls::shouldHideControls()
176 {
177     return !m_panel->hovered();
178 }
179
180 void MediaControls::bufferingProgressed()
181 {
182     // We only need to update buffering progress when paused, during normal
183     // playback playbackProgressed() will take care of it.
184     if (m_mediaController->paused())
185         m_timeline->setPosition(m_mediaController->currentTime());
186 }
187
188 void MediaControls::playbackStarted()
189 {
190     m_playButton->updateDisplayType();
191     m_timeline->setPosition(m_mediaController->currentTime());
192     updateCurrentTimeDisplay();
193
194     if (m_isFullscreen)
195         startHideFullscreenControlsTimer();
196 }
197
198 void MediaControls::playbackProgressed()
199 {
200     m_timeline->setPosition(m_mediaController->currentTime());
201     updateCurrentTimeDisplay();
202
203     if (!m_isMouseOverControls && m_mediaController->hasVideo())
204         makeTransparent();
205 }
206
207 void MediaControls::playbackStopped()
208 {
209     m_playButton->updateDisplayType();
210     m_timeline->setPosition(m_mediaController->currentTime());
211     updateCurrentTimeDisplay();
212     makeOpaque();
213
214     stopHideFullscreenControlsTimer();
215 }
216
217 void MediaControls::updateCurrentTimeDisplay()
218 {
219     double now = m_mediaController->currentTime();
220
221     Page* page = document().page();
222     if (!page)
223         return;
224
225     m_currentTimeDisplay->setInnerText(page->theme().formatMediaControlsTime(now), IGNORE_EXCEPTION);
226     m_currentTimeDisplay->setCurrentValue(now);
227 }
228
229 void MediaControls::showVolumeSlider()
230 {
231     if (!m_mediaController->hasAudio())
232         return;
233
234     m_volumeSlider->show();
235 }
236
237 void MediaControls::changedMute()
238 {
239     m_panelMuteButton->changedMute();
240 }
241
242 void MediaControls::changedVolume()
243 {
244     if (m_volumeSlider)
245         setSliderVolume();
246     if (m_panelMuteButton && m_panelMuteButton->renderer())
247         m_panelMuteButton->renderer()->repaint();
248 }
249
250 void MediaControls::changedClosedCaptionsVisibility()
251 {
252     if (m_toggleClosedCaptionsButton)
253         m_toggleClosedCaptionsButton->updateDisplayType();
254 }
255
256 void MediaControls::refreshClosedCaptionsButtonVisibility()
257 {
258     if (!m_toggleClosedCaptionsButton)
259         return;
260
261     if (m_mediaController->hasClosedCaptions())
262         m_toggleClosedCaptionsButton->show();
263     else
264         m_toggleClosedCaptionsButton->hide();
265 }
266
267 void MediaControls::closedCaptionTracksChanged()
268 {
269     refreshClosedCaptionsButtonVisibility();
270 }
271
272 void MediaControls::enteredFullscreen()
273 {
274     m_isFullscreen = true;
275     m_fullScreenButton->setIsFullscreen(true);
276
277     if (Page* page = document().page())
278         page->chrome().setCursorHiddenUntilMouseMoves(true);
279
280     startHideFullscreenControlsTimer();
281 #if ENABLE(VIDEO_TRACK)
282     if (m_textDisplayContainer)
283         m_textDisplayContainer->enteredFullscreen();
284 #endif
285 }
286
287 void MediaControls::exitedFullscreen()
288 {
289     m_isFullscreen = false;
290     m_fullScreenButton->setIsFullscreen(false);
291     stopHideFullscreenControlsTimer();
292 #if ENABLE(VIDEO_TRACK)
293     if (m_textDisplayContainer)
294         m_textDisplayContainer->exitedFullscreen();
295 #endif
296 }
297
298 void MediaControls::defaultEventHandler(Event* event)
299 {
300     HTMLDivElement::defaultEventHandler(event);
301
302     if (event->type() == eventNames().mouseoverEvent) {
303         if (!containsRelatedTarget(event)) {
304             m_isMouseOverControls = true;
305             if (!m_mediaController->canPlay()) {
306                 makeOpaque();
307                 if (shouldHideControls())
308                     startHideFullscreenControlsTimer();
309             }
310         }
311         return;
312     }
313
314     if (event->type() == eventNames().mouseoutEvent) {
315         if (!containsRelatedTarget(event)) {
316             m_isMouseOverControls = false;
317             stopHideFullscreenControlsTimer();
318         }
319         return;
320     }
321
322     if (event->type() == eventNames().mousemoveEvent) {
323         if (m_isFullscreen) {
324             // When we get a mouse move in fullscreen mode, show the media controls, and start a timer
325             // that will hide the media controls after a 3 seconds without a mouse move.
326             makeOpaque();
327             if (shouldHideControls())
328                 startHideFullscreenControlsTimer();
329         }
330         return;
331     }
332 }
333
334 void MediaControls::hideFullscreenControlsTimerFired()
335 {
336     if (m_mediaController->paused())
337         return;
338
339     if (!m_isFullscreen)
340         return;
341
342     if (!shouldHideControls())
343         return;
344
345     if (Page* page = document().page())
346         page->chrome().setCursorHiddenUntilMouseMoves(true);
347
348     makeTransparent();
349 }
350
351 void MediaControls::startHideFullscreenControlsTimer()
352 {
353     if (!m_isFullscreen)
354         return;
355
356     Page* page = document().page();
357     if (!page)
358         return;
359
360     m_hideFullscreenControlsTimer.startOneShot(page->settings().timeWithoutMouseMovementBeforeHidingControls());
361 }
362
363 void MediaControls::stopHideFullscreenControlsTimer()
364 {
365     m_hideFullscreenControlsTimer.stop();
366 }
367
368 bool MediaControls::containsRelatedTarget(Event* event)
369 {
370     if (!is<MouseEvent>(*event))
371         return false;
372     EventTarget* relatedTarget = downcast<MouseEvent>(*event).relatedTarget();
373     if (!relatedTarget)
374         return false;
375     return contains(relatedTarget->toNode());
376 }
377
378 #if ENABLE(VIDEO_TRACK)
379 void MediaControls::createTextTrackDisplay()
380 {
381     if (m_textDisplayContainer)
382         return;
383
384     auto textDisplayContainer = MediaControlTextTrackContainerElement::create(document());
385     m_textDisplayContainer = textDisplayContainer.ptr();
386
387     if (m_mediaController)
388         m_textDisplayContainer->setMediaController(m_mediaController);
389
390     // Insert it before the first controller element so it always displays behind the controls.
391     insertBefore(textDisplayContainer, m_panel, IGNORE_EXCEPTION);
392 }
393
394 void MediaControls::showTextTrackDisplay()
395 {
396     if (!m_textDisplayContainer)
397         createTextTrackDisplay();
398     m_textDisplayContainer->show();
399 }
400
401 void MediaControls::hideTextTrackDisplay()
402 {
403     if (!m_textDisplayContainer)
404         createTextTrackDisplay();
405     m_textDisplayContainer->hide();
406 }
407
408 void MediaControls::updateTextTrackDisplay()
409 {
410     if (!m_textDisplayContainer)
411         createTextTrackDisplay();
412
413     m_textDisplayContainer->updateDisplay();
414 }
415     
416 void MediaControls::textTrackPreferencesChanged()
417 {
418     closedCaptionTracksChanged();
419     if (m_textDisplayContainer)
420         m_textDisplayContainer->updateSizes(true);
421 }
422 #endif
423
424 void MediaControls::setSliderVolume()
425 {
426     m_volumeSlider->setVolume(m_mediaController->muted() ? 0.0 : m_mediaController->volume());
427 }
428
429 }
430
431 #endif