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