• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2011 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 
29 #if ENABLE(VIDEO)
30 #include "MediaControlRootElement.h"
31 
32 #include "MediaControlElements.h"
33 #include "Page.h"
34 #include "RenderTheme.h"
35 
36 using namespace std;
37 
38 namespace WebCore {
39 
MediaControlRootElement(HTMLMediaElement * mediaElement)40 MediaControlRootElement::MediaControlRootElement(HTMLMediaElement* mediaElement)
41     : MediaControls(mediaElement)
42     , m_mediaElement(mediaElement)
43     , m_rewindButton(0)
44     , m_playButton(0)
45     , m_returnToRealTimeButton(0)
46     , m_statusDisplay(0)
47     , m_currentTimeDisplay(0)
48     , m_timeline(0)
49     , m_timeRemainingDisplay(0)
50     , m_timelineContainer(0)
51     , m_seekBackButton(0)
52     , m_seekForwardButton(0)
53     , m_toggleClosedCaptionsButton(0)
54     , m_panelMuteButton(0)
55     , m_volumeSlider(0)
56     , m_volumeSliderMuteButton(0)
57     , m_volumeSliderContainer(0)
58     , m_fullScreenButton(0)
59     , m_fullScreenMinVolumeButton(0)
60     , m_fullScreenVolumeSlider(0)
61     , m_fullScreenMaxVolumeButton(0)
62     , m_panel(0)
63     , m_opaque(true)
64 {
65 }
66 
create(HTMLMediaElement * mediaElement)67 PassRefPtr<MediaControls> MediaControls::create(HTMLMediaElement* mediaElement)
68 {
69     return MediaControlRootElement::create(mediaElement);
70 }
71 
create(HTMLMediaElement * mediaElement)72 PassRefPtr<MediaControlRootElement> MediaControlRootElement::create(HTMLMediaElement* mediaElement)
73 {
74     if (!mediaElement->document()->page())
75         return 0;
76 
77     RefPtr<MediaControlRootElement> controls = adoptRef(new MediaControlRootElement(mediaElement));
78 
79     RefPtr<MediaControlPanelElement> panel = MediaControlPanelElement::create(mediaElement);
80 
81     ExceptionCode ec;
82 
83     RefPtr<MediaControlRewindButtonElement> rewindButton = MediaControlRewindButtonElement::create(mediaElement);
84     controls->m_rewindButton = rewindButton.get();
85     panel->appendChild(rewindButton.release(), ec, true);
86     if (ec)
87         return 0;
88 
89     RefPtr<MediaControlPlayButtonElement> playButton = MediaControlPlayButtonElement::create(mediaElement);
90     controls->m_playButton = playButton.get();
91     panel->appendChild(playButton.release(), ec, true);
92     if (ec)
93         return 0;
94 
95     RefPtr<MediaControlReturnToRealtimeButtonElement> returnToRealtimeButton = MediaControlReturnToRealtimeButtonElement::create(mediaElement);
96     controls->m_returnToRealTimeButton = returnToRealtimeButton.get();
97     panel->appendChild(returnToRealtimeButton.release(), ec, true);
98     if (ec)
99         return 0;
100 
101     if (mediaElement->document()->page()->theme()->usesMediaControlStatusDisplay()) {
102         RefPtr<MediaControlStatusDisplayElement> statusDisplay = MediaControlStatusDisplayElement::create(mediaElement);
103         controls->m_statusDisplay = statusDisplay.get();
104         panel->appendChild(statusDisplay.release(), ec, true);
105         if (ec)
106             return 0;
107     }
108 
109     RefPtr<MediaControlTimelineContainerElement> timelineContainer = MediaControlTimelineContainerElement::create(mediaElement);
110 
111     RefPtr<MediaControlCurrentTimeDisplayElement> currentTimeDisplay = MediaControlCurrentTimeDisplayElement::create(mediaElement);
112     controls->m_currentTimeDisplay = currentTimeDisplay.get();
113     timelineContainer->appendChild(currentTimeDisplay.release(), ec, true);
114     if (ec)
115         return 0;
116 
117     RefPtr<MediaControlTimelineElement> timeline = MediaControlTimelineElement::create(mediaElement, controls.get());
118     controls->m_timeline = timeline.get();
119     timelineContainer->appendChild(timeline.release(), ec, true);
120     if (ec)
121         return 0;
122 
123     RefPtr<MediaControlTimeRemainingDisplayElement> timeRemainingDisplay = MediaControlTimeRemainingDisplayElement::create(mediaElement);
124     controls->m_timeRemainingDisplay = timeRemainingDisplay.get();
125     timelineContainer->appendChild(timeRemainingDisplay.release(), ec, true);
126     if (ec)
127         return 0;
128 
129     controls->m_timelineContainer = timelineContainer.get();
130     panel->appendChild(timelineContainer.release(), ec, true);
131     if (ec)
132         return 0;
133 
134 #if !PLATFORM(ANDROID)
135     // FIXME: Only create when needed <http://webkit.org/b/57163>
136     RefPtr<MediaControlSeekBackButtonElement> seekBackButton = MediaControlSeekBackButtonElement::create(mediaElement);
137     controls->m_seekBackButton = seekBackButton.get();
138     panel->appendChild(seekBackButton.release(), ec, true);
139     if (ec)
140         return 0;
141 
142     // FIXME: Only create when needed <http://webkit.org/b/57163>
143     RefPtr<MediaControlSeekForwardButtonElement> seekForwardButton = MediaControlSeekForwardButtonElement::create(mediaElement);
144     controls->m_seekForwardButton = seekForwardButton.get();
145     panel->appendChild(seekForwardButton.release(), ec, true);
146     if (ec)
147         return 0;
148 #endif
149 
150     if (mediaElement->document()->page()->theme()->supportsClosedCaptioning()) {
151         RefPtr<MediaControlToggleClosedCaptionsButtonElement> toggleClosedCaptionsButton = MediaControlToggleClosedCaptionsButtonElement::create(mediaElement);
152         controls->m_toggleClosedCaptionsButton = toggleClosedCaptionsButton.get();
153         panel->appendChild(toggleClosedCaptionsButton.release(), ec, true);
154         if (ec)
155             return 0;
156     }
157 
158     // FIXME: Only create when needed <http://webkit.org/b/57163>
159     RefPtr<MediaControlFullscreenButtonElement> fullScreenButton = MediaControlFullscreenButtonElement::create(mediaElement, controls.get());
160     controls->m_fullScreenButton = fullScreenButton.get();
161     panel->appendChild(fullScreenButton.release(), ec, true);
162 
163     RefPtr<MediaControlPanelMuteButtonElement> panelMuteButton = MediaControlPanelMuteButtonElement::create(mediaElement, controls.get());
164     controls->m_panelMuteButton = panelMuteButton.get();
165     panel->appendChild(panelMuteButton.release(), ec, true);
166     if (ec)
167         return 0;
168 
169     if (mediaElement->document()->page()->theme()->usesMediaControlVolumeSlider()) {
170         RefPtr<MediaControlVolumeSliderContainerElement> volumeSliderContainer = MediaControlVolumeSliderContainerElement::create(mediaElement);
171 
172         RefPtr<MediaControlVolumeSliderElement> slider = MediaControlVolumeSliderElement::create(mediaElement);
173         controls->m_volumeSlider = slider.get();
174         volumeSliderContainer->appendChild(slider.release(), ec, true);
175         if (ec)
176             return 0;
177 
178         RefPtr<MediaControlVolumeSliderMuteButtonElement> volumeSliderMuteButton = MediaControlVolumeSliderMuteButtonElement::create(mediaElement);
179         controls->m_volumeSliderMuteButton = volumeSliderMuteButton.get();
180         volumeSliderContainer->appendChild(volumeSliderMuteButton.release(), ec, true);
181         if (ec)
182             return 0;
183 
184         controls->m_volumeSliderContainer = volumeSliderContainer.get();
185         panel->appendChild(volumeSliderContainer.release(), ec, true);
186         if (ec)
187             return 0;
188     }
189 
190     // FIXME: Only create when needed <http://webkit.org/b/57163>
191     RefPtr<MediaControlFullscreenVolumeMinButtonElement> fullScreenMinVolumeButton = MediaControlFullscreenVolumeMinButtonElement::create(mediaElement);
192     controls->m_fullScreenMinVolumeButton = fullScreenMinVolumeButton.get();
193     panel->appendChild(fullScreenMinVolumeButton.release(), ec, true);
194     if (ec)
195         return 0;
196 
197     RefPtr<MediaControlFullscreenVolumeSliderElement> fullScreenVolumeSlider = MediaControlFullscreenVolumeSliderElement::create(mediaElement);
198     controls->m_fullScreenVolumeSlider = fullScreenVolumeSlider.get();
199     panel->appendChild(fullScreenVolumeSlider.release(), ec, true);
200     if (ec)
201         return 0;
202 
203     RefPtr<MediaControlFullscreenVolumeMaxButtonElement> fullScreenMaxVolumeButton = MediaControlFullscreenVolumeMaxButtonElement::create(mediaElement);
204     controls->m_fullScreenMaxVolumeButton = fullScreenMaxVolumeButton.get();
205     panel->appendChild(fullScreenMaxVolumeButton.release(), ec, true);
206     if (ec)
207         return 0;
208 
209     controls->m_panel = panel.get();
210     controls->appendChild(panel.release(), ec, true);
211     if (ec)
212         return 0;
213 
214     return controls.release();
215 }
216 
show()217 void MediaControlRootElement::show()
218 {
219     m_panel->show();
220 }
221 
hide()222 void MediaControlRootElement::hide()
223 {
224     m_panel->hide();
225 }
226 
webkitTransitionString()227 static const String& webkitTransitionString()
228 {
229     DEFINE_STATIC_LOCAL(String, s, ("-webkit-transition"));
230     return s;
231 }
232 
opacityString()233 static const String& opacityString()
234 {
235     DEFINE_STATIC_LOCAL(String, s, ("opacity"));
236     return s;
237 }
238 
makeOpaque()239 void MediaControlRootElement::makeOpaque()
240 {
241     if (m_opaque)
242         return;
243 
244     DEFINE_STATIC_LOCAL(String, transitionValue, ());
245     if (transitionValue.isNull())
246         transitionValue = String::format("opacity %.1gs", document()->page()->theme()->mediaControlsFadeInDuration());
247     DEFINE_STATIC_LOCAL(String, opacityValue, ("1"));
248 
249     ExceptionCode ec;
250     // FIXME: Make more efficient <http://webkit.org/b/58157>
251     m_panel->style()->setProperty(webkitTransitionString(), transitionValue, ec);
252     m_panel->style()->setProperty(opacityString(), opacityValue, ec);
253     m_opaque = true;
254 }
255 
makeTransparent()256 void MediaControlRootElement::makeTransparent()
257 {
258     if (!m_opaque)
259         return;
260 
261     DEFINE_STATIC_LOCAL(String, transitionValue, ());
262     if (transitionValue.isNull())
263         transitionValue = String::format("opacity %.1gs", document()->page()->theme()->mediaControlsFadeOutDuration());
264     DEFINE_STATIC_LOCAL(String, opacityValue, ("0"));
265 
266     ExceptionCode ec;
267     // FIXME: Make more efficient <http://webkit.org/b/58157>
268     m_panel->style()->setProperty(webkitTransitionString(), transitionValue, ec);
269     m_panel->style()->setProperty(opacityString(), opacityValue, ec);
270     m_opaque = false;
271 }
272 
reset()273 void MediaControlRootElement::reset()
274 {
275     Page* page = document()->page();
276     if (!page)
277         return;
278 
279     changedNetworkState();
280 
281     if (m_mediaElement->supportsFullscreen())
282         m_fullScreenButton->show();
283     else
284         m_fullScreenButton->hide();
285 
286     float duration = m_mediaElement->duration();
287     if (isfinite(duration) || page->theme()->hasOwnDisabledStateHandlingFor(MediaSliderPart)) {
288         m_timeline->setDuration(duration);
289         m_timelineContainer->show();
290         m_timeline->setPosition(m_mediaElement->currentTime());
291         updateTimeDisplay();
292     } else
293         m_timelineContainer->hide();
294 
295     if (m_mediaElement->hasAudio() || page->theme()->hasOwnDisabledStateHandlingFor(MediaMuteButtonPart))
296         m_panelMuteButton->show();
297     else
298         m_panelMuteButton->hide();
299 
300     if (m_volumeSlider)
301         m_volumeSlider->setVolume(m_mediaElement->volume());
302 
303     if (m_toggleClosedCaptionsButton) {
304         if (m_mediaElement->hasClosedCaptions())
305             m_toggleClosedCaptionsButton->show();
306         else
307             m_toggleClosedCaptionsButton->hide();
308     }
309 
310     if (m_mediaElement->movieLoadType() != MediaPlayer::LiveStream) {
311         m_returnToRealTimeButton->hide();
312         m_rewindButton->show();
313     } else {
314         m_returnToRealTimeButton->show();
315         m_rewindButton->hide();
316     }
317 
318     makeOpaque();
319 }
320 
playbackStarted()321 void MediaControlRootElement::playbackStarted()
322 {
323     m_playButton->updateDisplayType();
324     m_timeline->setPosition(m_mediaElement->currentTime());
325     updateTimeDisplay();
326 }
327 
playbackProgressed()328 void MediaControlRootElement::playbackProgressed()
329 {
330     m_timeline->setPosition(m_mediaElement->currentTime());
331     updateTimeDisplay();
332 }
333 
playbackStopped()334 void MediaControlRootElement::playbackStopped()
335 {
336     m_playButton->updateDisplayType();
337     m_timeline->setPosition(m_mediaElement->currentTime());
338     updateTimeDisplay();
339     makeOpaque();
340 }
341 
updateTimeDisplay()342 void MediaControlRootElement::updateTimeDisplay()
343 {
344     float now = m_mediaElement->currentTime();
345     float duration = m_mediaElement->duration();
346 
347     Page* page = document()->page();
348     if (!page)
349         return;
350 
351     // Allow the theme to format the time.
352     ExceptionCode ec;
353     m_currentTimeDisplay->setInnerText(page->theme()->formatMediaControlsCurrentTime(now, duration), ec);
354     m_currentTimeDisplay->setCurrentValue(now);
355     m_timeRemainingDisplay->setInnerText(page->theme()->formatMediaControlsRemainingTime(now, duration), ec);
356     m_timeRemainingDisplay->setCurrentValue(now - duration);
357 }
358 
reportedError()359 void MediaControlRootElement::reportedError()
360 {
361     Page* page = document()->page();
362     if (!page)
363         return;
364 
365     if (!page->theme()->hasOwnDisabledStateHandlingFor(MediaSliderPart))
366         m_timelineContainer->hide();
367 
368     if (!page->theme()->hasOwnDisabledStateHandlingFor(MediaMuteButtonPart))
369         m_panelMuteButton->hide();
370 
371      m_fullScreenButton->hide();
372 
373     if (m_volumeSliderContainer)
374         m_volumeSliderContainer->hide();
375     if (m_toggleClosedCaptionsButton && !page->theme()->hasOwnDisabledStateHandlingFor(MediaToggleClosedCaptionsButtonPart))
376         m_toggleClosedCaptionsButton->hide();
377 }
378 
changedNetworkState()379 void MediaControlRootElement::changedNetworkState()
380 {
381     if (m_statusDisplay)
382         m_statusDisplay->update();
383 }
384 
loadedMetadata()385 void MediaControlRootElement::loadedMetadata()
386 {
387     if (m_statusDisplay)
388         m_statusDisplay->hide();
389 
390     reset();
391 }
392 
changedClosedCaptionsVisibility()393 void MediaControlRootElement::changedClosedCaptionsVisibility()
394 {
395     if (m_toggleClosedCaptionsButton)
396         m_toggleClosedCaptionsButton->updateDisplayType();
397 }
398 
changedMute()399 void MediaControlRootElement::changedMute()
400 {
401     m_panelMuteButton->changedMute();
402     if (m_volumeSliderMuteButton)
403         m_volumeSliderMuteButton->changedMute();
404 }
405 
changedVolume()406 void MediaControlRootElement::changedVolume()
407 {
408     if (m_volumeSlider)
409         m_volumeSlider->setVolume(m_mediaElement->volume());
410 }
411 
enteredFullscreen()412 void MediaControlRootElement::enteredFullscreen()
413 {
414     if (m_mediaElement->movieLoadType() == MediaPlayer::LiveStream || m_mediaElement->movieLoadType() == MediaPlayer::StoredStream) {
415 #if !PLATFORM(ANDROID)
416         m_seekBackButton->hide();
417         m_seekForwardButton->hide();
418 #endif
419     } else
420         m_rewindButton->hide();
421 }
422 
exitedFullscreen()423 void MediaControlRootElement::exitedFullscreen()
424 {
425     // "show" actually means removal of display:none style, so we are just clearing styles
426     // when exiting fullscreen.
427     // FIXME: Clarify naming of show/hide <http://webkit.org/b/58157>
428     m_rewindButton->show();
429 #if !PLATFORM(ANDROID)
430     m_seekBackButton->show();
431     m_seekForwardButton->show();
432 #endif
433 }
434 
showVolumeSlider()435 void MediaControlRootElement::showVolumeSlider()
436 {
437     if (!m_mediaElement->hasAudio())
438         return;
439 
440     if (m_volumeSliderContainer)
441         m_volumeSliderContainer->show();
442 }
443 
shadowPseudoId() const444 const AtomicString& MediaControlRootElement::shadowPseudoId() const
445 {
446     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls"));
447     return id;
448 }
449 
450 }
451 
452 #endif
453