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