Home | History | Annotate | Download | only in shadow
      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 
     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 
     67 PassRefPtr<MediaControls> MediaControls::create(HTMLMediaElement* mediaElement)
     68 {
     69     return MediaControlRootElement::create(mediaElement);
     70 }
     71 
     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 
    217 void MediaControlRootElement::show()
    218 {
    219     m_panel->show();
    220 }
    221 
    222 void MediaControlRootElement::hide()
    223 {
    224     m_panel->hide();
    225 }
    226 
    227 static const String& webkitTransitionString()
    228 {
    229     DEFINE_STATIC_LOCAL(String, s, ("-webkit-transition"));
    230     return s;
    231 }
    232 
    233 static const String& opacityString()
    234 {
    235     DEFINE_STATIC_LOCAL(String, s, ("opacity"));
    236     return s;
    237 }
    238 
    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 
    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 
    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 
    321 void MediaControlRootElement::playbackStarted()
    322 {
    323     m_playButton->updateDisplayType();
    324     m_timeline->setPosition(m_mediaElement->currentTime());
    325     updateTimeDisplay();
    326 }
    327 
    328 void MediaControlRootElement::playbackProgressed()
    329 {
    330     m_timeline->setPosition(m_mediaElement->currentTime());
    331     updateTimeDisplay();
    332 }
    333 
    334 void MediaControlRootElement::playbackStopped()
    335 {
    336     m_playButton->updateDisplayType();
    337     m_timeline->setPosition(m_mediaElement->currentTime());
    338     updateTimeDisplay();
    339     makeOpaque();
    340 }
    341 
    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 
    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 
    379 void MediaControlRootElement::changedNetworkState()
    380 {
    381     if (m_statusDisplay)
    382         m_statusDisplay->update();
    383 }
    384 
    385 void MediaControlRootElement::loadedMetadata()
    386 {
    387     if (m_statusDisplay)
    388         m_statusDisplay->hide();
    389 
    390     reset();
    391 }
    392 
    393 void MediaControlRootElement::changedClosedCaptionsVisibility()
    394 {
    395     if (m_toggleClosedCaptionsButton)
    396         m_toggleClosedCaptionsButton->updateDisplayType();
    397 }
    398 
    399 void MediaControlRootElement::changedMute()
    400 {
    401     m_panelMuteButton->changedMute();
    402     if (m_volumeSliderMuteButton)
    403         m_volumeSliderMuteButton->changedMute();
    404 }
    405 
    406 void MediaControlRootElement::changedVolume()
    407 {
    408     if (m_volumeSlider)
    409         m_volumeSlider->setVolume(m_mediaElement->volume());
    410 }
    411 
    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 
    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 
    435 void MediaControlRootElement::showVolumeSlider()
    436 {
    437     if (!m_mediaElement->hasAudio())
    438         return;
    439 
    440     if (m_volumeSliderContainer)
    441         m_volumeSliderContainer->show();
    442 }
    443 
    444 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