Home | History | Annotate | Download | only in shadow
      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 
     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 
     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 
     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 
    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 
    140 void MediaControls::loadedMetadata()
    141 {
    142     reset();
    143 }
    144 
    145 void MediaControls::show()
    146 {
    147     makeOpaque();
    148     m_panel->setIsDisplayed(true);
    149     m_panel->show();
    150 }
    151 
    152 void MediaControls::hide()
    153 {
    154     m_panel->setIsDisplayed(false);
    155     m_panel->hide();
    156 }
    157 
    158 void MediaControls::makeOpaque()
    159 {
    160     m_panel->makeOpaque();
    161 }
    162 
    163 void MediaControls::makeTransparent()
    164 {
    165     m_panel->makeTransparent();
    166 }
    167 
    168 bool MediaControls::shouldHideControls()
    169 {
    170     return !m_panel->hovered();
    171 }
    172 
    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 
    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 
    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 
    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 
    210 void MediaControls::showVolumeSlider()
    211 {
    212     if (!m_mediaController->hasAudio())
    213         return;
    214 
    215     m_volumeSlider->show();
    216 }
    217 
    218 void MediaControls::changedMute()
    219 {
    220     m_panelMuteButton->changedMute();
    221 }
    222 
    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 
    231 void MediaControls::changedClosedCaptionsVisibility()
    232 {
    233     if (m_toggleClosedCaptionsButton)
    234         m_toggleClosedCaptionsButton->updateDisplayType();
    235 }
    236 
    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 
    248 void MediaControls::closedCaptionTracksChanged()
    249 {
    250     refreshClosedCaptionsButtonVisibility();
    251 }
    252 
    253 void MediaControls::enteredFullscreen()
    254 {
    255     m_isFullscreen = true;
    256     m_fullScreenButton->setIsFullscreen(true);
    257     startHideFullscreenControlsTimer();
    258 }
    259 
    260 void MediaControls::exitedFullscreen()
    261 {
    262     m_isFullscreen = false;
    263     m_fullScreenButton->setIsFullscreen(false);
    264     stopHideFullscreenControlsTimer();
    265 }
    266 
    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 
    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 
    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 
    329 void MediaControls::stopHideFullscreenControlsTimer()
    330 {
    331     m_hideFullscreenControlsTimer.stop();
    332 }
    333 
    334 const AtomicString& MediaControls::pseudo() const
    335 {
    336     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls"));
    337     return id;
    338 }
    339 
    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 
    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 
    365 void MediaControls::showTextTrackDisplay()
    366 {
    367     if (!m_textDisplayContainer)
    368         createTextTrackDisplay();
    369     m_textDisplayContainer->show();
    370 }
    371 
    372 void MediaControls::hideTextTrackDisplay()
    373 {
    374     if (!m_textDisplayContainer)
    375         createTextTrackDisplay();
    376     m_textDisplayContainer->hide();
    377 }
    378 
    379 void MediaControls::updateTextTrackDisplay()
    380 {
    381     if (!m_textDisplayContainer)
    382         createTextTrackDisplay();
    383 
    384     m_textDisplayContainer->updateDisplay();
    385 }
    386 
    387 }
    388