Old subtitle track is not deleted on 'src' attribute change event
[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 "EventNames.h"
33 #include "MouseEvent.h"
34 #include "Page.h"
35 #include "RenderElement.h"
36 #include "RenderTheme.h"
37 #include "Settings.h"
38
39 namespace WebCore {
40
41 MediaControls::MediaControls(Document& document)
42     : HTMLDivElement(HTMLNames::divTag, document)
43     , m_mediaController(0)
44     , m_panel(0)
45 #if ENABLE(VIDEO_TRACK)
46     , m_textDisplayContainer(0)
47 #endif
48     , m_playButton(0)
49     , m_currentTimeDisplay(0)
50     , m_timeline(0)
51     , m_panelMuteButton(0)
52     , m_volumeSlider(0)
53     , m_toggleClosedCaptionsButton(0)
54     , m_fullScreenButton(0)
55     , m_hideFullscreenControlsTimer(*this, &MediaControls::hideFullscreenControlsTimerFired)
56     , m_isFullscreen(false)
57     , m_isMouseOverControls(false)
58 {
59     setPseudo(AtomicString("-webkit-media-controls", AtomicString::ConstructFromLiteral));
60 }
61
62 void MediaControls::setMediaController(MediaControllerInterface* controller)
63 {
64     if (m_mediaController == controller)
65         return;
66     m_mediaController = controller;
67
68     if (m_panel)
69         m_panel->setMediaController(controller);
70 #if ENABLE(VIDEO_TRACK)
71     if (m_textDisplayContainer)
72         m_textDisplayContainer->setMediaController(controller);
73 #endif
74     if (m_playButton)
75         m_playButton->setMediaController(controller);
76     if (m_currentTimeDisplay)
77         m_currentTimeDisplay->setMediaController(controller);
78     if (m_timeline)
79         m_timeline->setMediaController(controller);
80     if (m_panelMuteButton)
81         m_panelMuteButton->setMediaController(controller);
82     if (m_volumeSlider)
83         m_volumeSlider->setMediaController(controller);
84     if (m_toggleClosedCaptionsButton)
85         m_toggleClosedCaptionsButton->setMediaController(controller);
86     if (m_fullScreenButton)
87         m_fullScreenButton->setMediaController(controller);
88 }
89
90 void MediaControls::reset()
91 {
92     m_playButton->updateDisplayType();
93
94     updateCurrentTimeDisplay();
95
96     double duration = m_mediaController->duration();
97     if (std::isfinite(duration) || RenderTheme::singleton().hasOwnDisabledStateHandlingFor(MediaSliderPart)) {
98         m_timeline->setDuration(duration);
99         m_timeline->setPosition(m_mediaController->currentTime());
100     }
101
102     if (m_mediaController->hasAudio() || RenderTheme::singleton().hasOwnDisabledStateHandlingFor(MediaMuteButtonPart))
103         m_panelMuteButton->show();
104     else
105         m_panelMuteButton->hide();
106
107     if (m_volumeSlider) {
108         if (!m_mediaController->hasAudio())
109             m_volumeSlider->hide();
110         else {
111             m_volumeSlider->show();
112             setSliderVolume();
113         }
114     }
115
116     refreshClosedCaptionsButtonVisibility();
117
118     if (m_fullScreenButton) {
119         if (m_mediaController->supportsFullscreen(HTMLMediaElementEnums::VideoFullscreenModeStandard) && m_mediaController->hasVideo())
120             m_fullScreenButton->show();
121         else
122             m_fullScreenButton->hide();
123     }
124
125     makeOpaque();
126 }
127
128 void MediaControls::reportedError()
129 {
130     auto& theme = RenderTheme::singleton();
131     if (!theme.hasOwnDisabledStateHandlingFor(MediaMuteButtonPart)) {
132         m_panelMuteButton->hide();
133         m_volumeSlider->hide();
134     }
135
136     if (m_toggleClosedCaptionsButton && !theme.hasOwnDisabledStateHandlingFor(MediaToggleClosedCaptionsButtonPart))
137         m_toggleClosedCaptionsButton->hide();
138
139     if (m_fullScreenButton && !theme.hasOwnDisabledStateHandlingFor(MediaEnterFullscreenButtonPart))
140         m_fullScreenButton->hide();
141 }
142
143 void MediaControls::loadedMetadata()
144 {
145     reset();
146 }
147
148 void MediaControls::show()
149 {
150     makeOpaque();
151     m_panel->setIsDisplayed(true);
152     m_panel->show();
153 }
154
155 void MediaControls::hide()
156 {
157     m_panel->setIsDisplayed(false);
158     m_panel->hide();
159 }
160
161 void MediaControls::makeOpaque()
162 {
163     m_panel->makeOpaque();
164 }
165
166 void MediaControls::makeTransparent()
167 {
168     m_panel->makeTransparent();
169 }
170
171 bool MediaControls::shouldHideControls()
172 {
173     return !m_panel->hovered();
174 }
175
176 void MediaControls::bufferingProgressed()
177 {
178     // We only need to update buffering progress when paused, during normal
179     // playback playbackProgressed() will take care of it.
180     if (m_mediaController->paused())
181         m_timeline->setPosition(m_mediaController->currentTime());
182 }
183
184 void MediaControls::playbackStarted()
185 {
186     m_playButton->updateDisplayType();
187     m_timeline->setPosition(m_mediaController->currentTime());
188     updateCurrentTimeDisplay();
189
190     if (m_isFullscreen)
191         startHideFullscreenControlsTimer();
192 }
193
194 void MediaControls::playbackProgressed()
195 {
196     m_timeline->setPosition(m_mediaController->currentTime());
197     updateCurrentTimeDisplay();
198
199     if (!m_isMouseOverControls && m_mediaController->hasVideo())
200         makeTransparent();
201 }
202
203 void MediaControls::playbackStopped()
204 {
205     m_playButton->updateDisplayType();
206     m_timeline->setPosition(m_mediaController->currentTime());
207     updateCurrentTimeDisplay();
208     makeOpaque();
209
210     stopHideFullscreenControlsTimer();
211 }
212
213 void MediaControls::updateCurrentTimeDisplay()
214 {
215     double now = m_mediaController->currentTime();
216     m_currentTimeDisplay->setInnerText(RenderTheme::singleton().formatMediaControlsTime(now));
217     m_currentTimeDisplay->setCurrentValue(now);
218 }
219
220 void MediaControls::showVolumeSlider()
221 {
222     if (!m_mediaController->hasAudio())
223         return;
224
225     m_volumeSlider->show();
226 }
227
228 void MediaControls::changedMute()
229 {
230     m_panelMuteButton->changedMute();
231 }
232
233 void MediaControls::changedVolume()
234 {
235     if (m_volumeSlider)
236         setSliderVolume();
237     if (m_panelMuteButton && m_panelMuteButton->renderer())
238         m_panelMuteButton->renderer()->repaint();
239 }
240
241 void MediaControls::changedClosedCaptionsVisibility()
242 {
243     if (m_toggleClosedCaptionsButton)
244         m_toggleClosedCaptionsButton->updateDisplayType();
245 }
246
247 void MediaControls::refreshClosedCaptionsButtonVisibility()
248 {
249     if (!m_toggleClosedCaptionsButton)
250         return;
251
252     if (m_mediaController->hasClosedCaptions())
253         m_toggleClosedCaptionsButton->show();
254     else
255         m_toggleClosedCaptionsButton->hide();
256 }
257
258 void MediaControls::closedCaptionTracksChanged()
259 {
260     refreshClosedCaptionsButtonVisibility();
261 }
262
263 void MediaControls::enteredFullscreen()
264 {
265     m_isFullscreen = true;
266     m_fullScreenButton->setIsFullscreen(true);
267
268     if (Page* page = document().page())
269         page->chrome().setCursorHiddenUntilMouseMoves(true);
270
271     startHideFullscreenControlsTimer();
272 #if ENABLE(VIDEO_TRACK)
273     if (m_textDisplayContainer)
274         m_textDisplayContainer->enteredFullscreen();
275 #endif
276 }
277
278 void MediaControls::exitedFullscreen()
279 {
280     m_isFullscreen = false;
281     m_fullScreenButton->setIsFullscreen(false);
282     stopHideFullscreenControlsTimer();
283 #if ENABLE(VIDEO_TRACK)
284     if (m_textDisplayContainer)
285         m_textDisplayContainer->exitedFullscreen();
286 #endif
287 }
288
289 void MediaControls::defaultEventHandler(Event& event)
290 {
291     HTMLDivElement::defaultEventHandler(event);
292
293     if (event.type() == eventNames().mouseoverEvent) {
294         if (!containsRelatedTarget(event)) {
295             m_isMouseOverControls = true;
296             if (!m_mediaController->canPlay()) {
297                 makeOpaque();
298                 if (shouldHideControls())
299                     startHideFullscreenControlsTimer();
300             }
301         }
302         return;
303     }
304
305     if (event.type() == eventNames().mouseoutEvent) {
306         if (!containsRelatedTarget(event)) {
307             m_isMouseOverControls = false;
308             stopHideFullscreenControlsTimer();
309         }
310         return;
311     }
312
313     if (event.type() == eventNames().mousemoveEvent) {
314         if (m_isFullscreen) {
315             // When we get a mouse move in fullscreen mode, show the media controls, and start a timer
316             // that will hide the media controls after a 3 seconds without a mouse move.
317             makeOpaque();
318             if (shouldHideControls())
319                 startHideFullscreenControlsTimer();
320         }
321         return;
322     }
323 }
324
325 void MediaControls::hideFullscreenControlsTimerFired()
326 {
327     if (m_mediaController->paused())
328         return;
329
330     if (!m_isFullscreen)
331         return;
332
333     if (!shouldHideControls())
334         return;
335
336     if (Page* page = document().page())
337         page->chrome().setCursorHiddenUntilMouseMoves(true);
338
339     makeTransparent();
340 }
341
342 void MediaControls::startHideFullscreenControlsTimer()
343 {
344     if (!m_isFullscreen)
345         return;
346
347     Page* page = document().page();
348     if (!page)
349         return;
350
351     m_hideFullscreenControlsTimer.startOneShot(page->settings().timeWithoutMouseMovementBeforeHidingControls());
352 }
353
354 void MediaControls::stopHideFullscreenControlsTimer()
355 {
356     m_hideFullscreenControlsTimer.stop();
357 }
358
359 bool MediaControls::containsRelatedTarget(Event& event)
360 {
361     if (!is<MouseEvent>(event))
362         return false;
363     EventTarget* relatedTarget = downcast<MouseEvent>(event).relatedTarget();
364     if (!relatedTarget)
365         return false;
366     return contains(relatedTarget->toNode());
367 }
368
369 #if ENABLE(VIDEO_TRACK)
370
371 void MediaControls::createTextTrackDisplay()
372 {
373     if (m_textDisplayContainer)
374         return;
375
376     auto textDisplayContainer = MediaControlTextTrackContainerElement::create(document());
377     m_textDisplayContainer = textDisplayContainer.ptr();
378
379     if (m_mediaController)
380         m_textDisplayContainer->setMediaController(m_mediaController);
381
382     // Insert it before the first controller element so it always displays behind the controls.
383     insertBefore(textDisplayContainer, m_panel);
384 }
385
386 void MediaControls::showTextTrackDisplay()
387 {
388     if (!m_textDisplayContainer)
389         createTextTrackDisplay();
390     m_textDisplayContainer->show();
391 }
392
393 void MediaControls::hideTextTrackDisplay()
394 {
395     if (!m_textDisplayContainer)
396         createTextTrackDisplay();
397     m_textDisplayContainer->hide();
398 }
399
400 void MediaControls::updateTextTrackDisplay()
401 {
402     if (!m_textDisplayContainer)
403         createTextTrackDisplay();
404
405     m_textDisplayContainer->updateDisplay();
406 }
407     
408 void MediaControls::textTrackPreferencesChanged()
409 {
410     closedCaptionTracksChanged();
411     if (m_textDisplayContainer)
412         m_textDisplayContainer->updateSizes(true);
413 }
414
415 void MediaControls::clearTextDisplayContainer()
416 {
417     if (m_textDisplayContainer)
418         m_textDisplayContainer->removeChildren();
419 }
420
421 #endif
422
423 void MediaControls::setSliderVolume()
424 {
425     m_volumeSlider->setVolume(m_mediaController->muted() ? 0.0 : m_mediaController->volume());
426 }
427
428 }
429
430 #endif