Home | History | Annotate | Download | only in rendering
      1 /*
      2  * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 
     28 #if ENABLE(VIDEO)
     29 #include "RenderMedia.h"
     30 
     31 #include "EventNames.h"
     32 #include "FloatConversion.h"
     33 #include "HTMLNames.h"
     34 #include "MediaControlElements.h"
     35 #include "MouseEvent.h"
     36 #include "RenderTheme.h"
     37 #include <wtf/CurrentTime.h>
     38 #include <wtf/MathExtras.h>
     39 
     40 using namespace std;
     41 
     42 namespace WebCore {
     43 
     44 using namespace HTMLNames;
     45 
     46 static const double cTimeUpdateRepeatDelay = 0.2;
     47 static const double cOpacityAnimationRepeatDelay = 0.05;
     48 
     49 RenderMedia::RenderMedia(HTMLMediaElement* video)
     50     : RenderImage(video)
     51     , m_timeUpdateTimer(this, &RenderMedia::timeUpdateTimerFired)
     52     , m_opacityAnimationTimer(this, &RenderMedia::opacityAnimationTimerFired)
     53     , m_mouseOver(false)
     54     , m_opacityAnimationStartTime(0)
     55     , m_opacityAnimationDuration(0)
     56     , m_opacityAnimationFrom(0)
     57     , m_opacityAnimationTo(1.0f)
     58 {
     59 }
     60 
     61 RenderMedia::RenderMedia(HTMLMediaElement* video, const IntSize& intrinsicSize)
     62     : RenderImage(video)
     63     , m_timeUpdateTimer(this, &RenderMedia::timeUpdateTimerFired)
     64     , m_opacityAnimationTimer(this, &RenderMedia::opacityAnimationTimerFired)
     65     , m_mouseOver(false)
     66     , m_opacityAnimationStartTime(0)
     67     , m_opacityAnimationDuration(0)
     68     , m_opacityAnimationFrom(0)
     69     , m_opacityAnimationTo(1.0f)
     70 {
     71     setIntrinsicSize(intrinsicSize);
     72 }
     73 
     74 RenderMedia::~RenderMedia()
     75 {
     76 }
     77 
     78 void RenderMedia::destroy()
     79 {
     80     if (m_controlsShadowRoot && m_controlsShadowRoot->renderer()) {
     81 
     82         // detach the panel before removing the shadow renderer to prevent a crash in m_controlsShadowRoot->detach()
     83         //  when display: style changes
     84         m_panel->detach();
     85 
     86         removeChild(m_controlsShadowRoot->renderer());
     87         m_controlsShadowRoot->detach();
     88         m_controlsShadowRoot = 0;
     89     }
     90     RenderImage::destroy();
     91 }
     92 
     93 HTMLMediaElement* RenderMedia::mediaElement() const
     94 {
     95     return static_cast<HTMLMediaElement*>(node());
     96 }
     97 
     98 MediaPlayer* RenderMedia::player() const
     99 {
    100     return mediaElement()->player();
    101 }
    102 
    103 void RenderMedia::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
    104 {
    105     RenderImage::styleDidChange(diff, oldStyle);
    106 
    107     if (m_controlsShadowRoot) {
    108         if (m_panel)
    109             m_panel->updateStyle();
    110         if (m_muteButton)
    111             m_muteButton->updateStyle();
    112         if (m_playButton)
    113             m_playButton->updateStyle();
    114         if (m_seekBackButton)
    115             m_seekBackButton->updateStyle();
    116         if (m_seekForwardButton)
    117             m_seekForwardButton->updateStyle();
    118         if (m_rewindButton)
    119             m_rewindButton->updateStyle();
    120         if (m_returnToRealtimeButton)
    121             m_returnToRealtimeButton->updateStyle();
    122         if (m_toggleClosedCaptionsButton)
    123             m_toggleClosedCaptionsButton->updateStyle();
    124         if (m_statusDisplay)
    125             m_statusDisplay->updateStyle();
    126         if (m_timelineContainer)
    127             m_timelineContainer->updateStyle();
    128         if (m_timeline)
    129             m_timeline->updateStyle();
    130         if (m_fullscreenButton)
    131             m_fullscreenButton->updateStyle();
    132         if (m_currentTimeDisplay)
    133             m_currentTimeDisplay->updateStyle();
    134         if (m_timeRemainingDisplay)
    135             m_timeRemainingDisplay->updateStyle();
    136         if (m_volumeSliderContainer)
    137             m_volumeSliderContainer->updateStyle();
    138         if (m_volumeSlider)
    139             m_volumeSlider->updateStyle();
    140     }
    141 }
    142 
    143 void RenderMedia::layout()
    144 {
    145     IntSize oldSize = contentBoxRect().size();
    146 
    147     RenderImage::layout();
    148 
    149     RenderBox* controlsRenderer = m_controlsShadowRoot ? m_controlsShadowRoot->renderBox() : 0;
    150     if (!controlsRenderer)
    151         return;
    152     IntSize newSize = contentBoxRect().size();
    153     if (newSize != oldSize || controlsRenderer->needsLayout()) {
    154 
    155         if (m_currentTimeDisplay && m_timeRemainingDisplay) {
    156             bool shouldShowTimeDisplays = shouldShowTimeDisplayControls();
    157             m_currentTimeDisplay->setVisible(shouldShowTimeDisplays);
    158             m_timeRemainingDisplay->setVisible(shouldShowTimeDisplays);
    159         }
    160 
    161         controlsRenderer->setLocation(borderLeft() + paddingLeft(), borderTop() + paddingTop());
    162         controlsRenderer->style()->setHeight(Length(newSize.height(), Fixed));
    163         controlsRenderer->style()->setWidth(Length(newSize.width(), Fixed));
    164         controlsRenderer->setNeedsLayout(true, false);
    165         controlsRenderer->layout();
    166         setChildNeedsLayout(false);
    167     }
    168 }
    169 
    170 void RenderMedia::createControlsShadowRoot()
    171 {
    172     ASSERT(!m_controlsShadowRoot);
    173     m_controlsShadowRoot = new MediaControlShadowRootElement(document(), mediaElement());
    174     addChild(m_controlsShadowRoot->renderer());
    175 }
    176 
    177 void RenderMedia::createPanel()
    178 {
    179     ASSERT(!m_panel);
    180     m_panel = new MediaControlElement(document(), MEDIA_CONTROLS_PANEL, mediaElement());
    181     m_panel->attachToParent(m_controlsShadowRoot.get());
    182 }
    183 
    184 void RenderMedia::createMuteButton()
    185 {
    186     ASSERT(!m_muteButton);
    187     m_muteButton = new MediaControlMuteButtonElement(document(), mediaElement());
    188     m_muteButton->attachToParent(m_panel.get());
    189 }
    190 
    191 void RenderMedia::createPlayButton()
    192 {
    193     ASSERT(!m_playButton);
    194     m_playButton = new MediaControlPlayButtonElement(document(), mediaElement());
    195     m_playButton->attachToParent(m_panel.get());
    196 }
    197 
    198 void RenderMedia::createSeekBackButton()
    199 {
    200     ASSERT(!m_seekBackButton);
    201     m_seekBackButton = new MediaControlSeekButtonElement(document(), mediaElement(), false);
    202     m_seekBackButton->attachToParent(m_panel.get());
    203 }
    204 
    205 void RenderMedia::createSeekForwardButton()
    206 {
    207     ASSERT(!m_seekForwardButton);
    208     m_seekForwardButton = new MediaControlSeekButtonElement(document(), mediaElement(), true);
    209     m_seekForwardButton->attachToParent(m_panel.get());
    210 }
    211 
    212 void RenderMedia::createRewindButton()
    213 {
    214     ASSERT(!m_rewindButton);
    215     m_rewindButton = new MediaControlRewindButtonElement(document(), mediaElement());
    216     m_rewindButton->attachToParent(m_panel.get());
    217 }
    218 
    219 void RenderMedia::createReturnToRealtimeButton()
    220 {
    221     ASSERT(!m_returnToRealtimeButton);
    222     m_returnToRealtimeButton = new MediaControlReturnToRealtimeButtonElement(document(), mediaElement());
    223     m_returnToRealtimeButton->attachToParent(m_panel.get());
    224 }
    225 
    226 void RenderMedia::createToggleClosedCaptionsButton()
    227 {
    228     ASSERT(!m_toggleClosedCaptionsButton);
    229     m_toggleClosedCaptionsButton = new MediaControlToggleClosedCaptionsButtonElement(document(), mediaElement());
    230     m_toggleClosedCaptionsButton->attachToParent(m_panel.get());
    231 }
    232 
    233 void RenderMedia::createStatusDisplay()
    234 {
    235     ASSERT(!m_statusDisplay);
    236     m_statusDisplay = new MediaControlStatusDisplayElement(document(), mediaElement());
    237     m_statusDisplay->attachToParent(m_panel.get());
    238 }
    239 
    240 void RenderMedia::createTimelineContainer()
    241 {
    242     ASSERT(!m_timelineContainer);
    243     m_timelineContainer = new MediaControlTimelineContainerElement(document(), mediaElement());
    244     m_timelineContainer->attachToParent(m_panel.get());
    245 }
    246 
    247 void RenderMedia::createTimeline()
    248 {
    249     ASSERT(!m_timeline);
    250     m_timeline = new MediaControlTimelineElement(document(), mediaElement());
    251     m_timeline->setAttribute(precisionAttr, "float");
    252     m_timeline->attachToParent(m_timelineContainer.get());
    253 }
    254 
    255 void RenderMedia::createVolumeSliderContainer()
    256 {
    257     ASSERT(!m_volumeSliderContainer);
    258     m_volumeSliderContainer = new MediaControlVolumeSliderContainerElement(document(), mediaElement());
    259     m_volumeSliderContainer->attachToParent(m_panel.get());
    260 }
    261 
    262 void RenderMedia::createVolumeSlider()
    263 {
    264     ASSERT(!m_volumeSlider);
    265     m_volumeSlider = new MediaControlVolumeSliderElement(document(), mediaElement());
    266     m_volumeSlider->setAttribute(precisionAttr, "float");
    267     m_volumeSlider->setAttribute(maxAttr, "1");
    268     m_volumeSlider->setAttribute(valueAttr, String::number(mediaElement()->volume()));
    269     m_volumeSlider->attachToParent(m_volumeSliderContainer.get());
    270 }
    271 
    272 void RenderMedia::createCurrentTimeDisplay()
    273 {
    274     ASSERT(!m_currentTimeDisplay);
    275     m_currentTimeDisplay = new MediaControlTimeDisplayElement(document(), MEDIA_CONTROLS_CURRENT_TIME_DISPLAY, mediaElement());
    276     m_currentTimeDisplay->attachToParent(m_timelineContainer.get());
    277 }
    278 
    279 void RenderMedia::createTimeRemainingDisplay()
    280 {
    281     ASSERT(!m_timeRemainingDisplay);
    282     m_timeRemainingDisplay = new MediaControlTimeDisplayElement(document(), MEDIA_CONTROLS_TIME_REMAINING_DISPLAY, mediaElement());
    283     m_timeRemainingDisplay->attachToParent(m_timelineContainer.get());
    284 }
    285 
    286 void RenderMedia::createFullscreenButton()
    287 {
    288     ASSERT(!m_fullscreenButton);
    289     m_fullscreenButton = new MediaControlFullscreenButtonElement(document(), mediaElement());
    290     m_fullscreenButton->attachToParent(m_panel.get());
    291 }
    292 
    293 void RenderMedia::updateFromElement()
    294 {
    295     updateControls();
    296 }
    297 
    298 void RenderMedia::updateControls()
    299 {
    300     HTMLMediaElement* media = mediaElement();
    301     if (!media->controls() || !media->inActiveDocument()) {
    302         if (m_controlsShadowRoot) {
    303             m_controlsShadowRoot->detach();
    304             m_panel = 0;
    305             m_muteButton = 0;
    306             m_playButton = 0;
    307             m_statusDisplay = 0;
    308             m_timelineContainer = 0;
    309             m_timeline = 0;
    310             m_seekBackButton = 0;
    311             m_seekForwardButton = 0;
    312             m_rewindButton = 0;
    313             m_returnToRealtimeButton = 0;
    314             m_currentTimeDisplay = 0;
    315             m_timeRemainingDisplay = 0;
    316             m_fullscreenButton = 0;
    317             m_volumeSliderContainer = 0;
    318             m_volumeSlider = 0;
    319             m_controlsShadowRoot = 0;
    320             m_toggleClosedCaptionsButton = 0;
    321         }
    322         m_opacityAnimationTo = 1.0f;
    323         m_opacityAnimationTimer.stop();
    324         m_timeUpdateTimer.stop();
    325         return;
    326     }
    327 
    328     if (!m_controlsShadowRoot) {
    329         createControlsShadowRoot();
    330         createPanel();
    331         if (m_panel) {
    332             createRewindButton();
    333             createPlayButton();
    334             createReturnToRealtimeButton();
    335             createStatusDisplay();
    336             createTimelineContainer();
    337             if (m_timelineContainer) {
    338                 createCurrentTimeDisplay();
    339                 createTimeline();
    340                 createTimeRemainingDisplay();
    341             }
    342             createSeekBackButton();
    343             createSeekForwardButton();
    344             createToggleClosedCaptionsButton();
    345             createFullscreenButton();
    346             createMuteButton();
    347             createVolumeSliderContainer();
    348             if (m_volumeSliderContainer)
    349                 createVolumeSlider();
    350             m_panel->attach();
    351         }
    352     }
    353 
    354     if (media->canPlay()) {
    355         if (m_timeUpdateTimer.isActive())
    356             m_timeUpdateTimer.stop();
    357     } else if (style()->visibility() == VISIBLE && m_timeline && m_timeline->renderer() && m_timeline->renderer()->style()->display() != NONE) {
    358         m_timeUpdateTimer.startRepeating(cTimeUpdateRepeatDelay);
    359     }
    360 
    361 
    362     if (m_panel) {
    363         // update() might alter the opacity of the element, especially if we are in the middle
    364         // of an animation. This is the only element concerned as we animate only this element.
    365         float opacityBeforeChangingStyle = m_panel->renderer() ? m_panel->renderer()->style()->opacity() : 0;
    366         m_panel->update();
    367         changeOpacity(m_panel.get(), opacityBeforeChangingStyle);
    368     }
    369     if (m_muteButton)
    370         m_muteButton->update();
    371     if (m_playButton)
    372         m_playButton->update();
    373     if (m_timelineContainer)
    374         m_timelineContainer->update();
    375     if (m_volumeSliderContainer)
    376         m_volumeSliderContainer->update();
    377     if (m_timeline)
    378         m_timeline->update();
    379     if (m_currentTimeDisplay)
    380         m_currentTimeDisplay->update();
    381     if (m_timeRemainingDisplay)
    382         m_timeRemainingDisplay->update();
    383     if (m_seekBackButton)
    384         m_seekBackButton->update();
    385     if (m_seekForwardButton)
    386         m_seekForwardButton->update();
    387     if (m_rewindButton)
    388         m_rewindButton->update();
    389     if (m_returnToRealtimeButton)
    390         m_returnToRealtimeButton->update();
    391     if (m_toggleClosedCaptionsButton)
    392         m_toggleClosedCaptionsButton->update();
    393     if (m_statusDisplay)
    394         m_statusDisplay->update();
    395     if (m_fullscreenButton)
    396         m_fullscreenButton->update();
    397     if (m_volumeSlider)
    398         m_volumeSlider->update();
    399 
    400     updateTimeDisplay();
    401     updateControlVisibility();
    402 }
    403 
    404 void RenderMedia::timeUpdateTimerFired(Timer<RenderMedia>*)
    405 {
    406     if (m_timeline)
    407         m_timeline->update(false);
    408     updateTimeDisplay();
    409 }
    410 
    411 void RenderMedia::updateTimeDisplay()
    412 {
    413     if (!m_currentTimeDisplay || !m_currentTimeDisplay->renderer() || m_currentTimeDisplay->renderer()->style()->display() == NONE || style()->visibility() != VISIBLE)
    414         return;
    415 
    416     float now = mediaElement()->currentTime();
    417     float duration = mediaElement()->duration();
    418 
    419     // Allow the theme to format the time
    420     ExceptionCode ec;
    421     m_currentTimeDisplay->setInnerText(theme()->formatMediaControlsCurrentTime(now, duration), ec);
    422     m_currentTimeDisplay->setCurrentValue(now);
    423     m_timeRemainingDisplay->setInnerText(theme()->formatMediaControlsRemainingTime(now, duration), ec);
    424     m_timeRemainingDisplay->setCurrentValue(now - duration);
    425 }
    426 
    427 void RenderMedia::updateControlVisibility()
    428 {
    429     if (!m_panel || !m_panel->renderer())
    430         return;
    431 
    432     // Don't fade for audio controls.
    433     HTMLMediaElement* media = mediaElement();
    434     if (!media->hasVideo())
    435         return;
    436 
    437     // Don't fade if the media element is not visible
    438     if (style()->visibility() != VISIBLE)
    439         return;
    440 
    441     bool shouldHideController = !m_mouseOver && !media->canPlay();
    442 
    443     // Do fading manually, css animations don't work with shadow trees
    444 
    445     float animateFrom = m_panel->renderer()->style()->opacity();
    446     float animateTo = shouldHideController ? 0.0f : 1.0f;
    447 
    448     if (animateFrom == animateTo)
    449         return;
    450 
    451     if (m_opacityAnimationTimer.isActive()) {
    452         if (m_opacityAnimationTo == animateTo)
    453             return;
    454         m_opacityAnimationTimer.stop();
    455     }
    456 
    457     if (animateFrom < animateTo)
    458         m_opacityAnimationDuration = m_panel->renderer()->theme()->mediaControlsFadeInDuration();
    459     else
    460         m_opacityAnimationDuration = m_panel->renderer()->theme()->mediaControlsFadeOutDuration();
    461 
    462     m_opacityAnimationFrom = animateFrom;
    463     m_opacityAnimationTo = animateTo;
    464 
    465     m_opacityAnimationStartTime = currentTime();
    466     m_opacityAnimationTimer.startRepeating(cOpacityAnimationRepeatDelay);
    467 }
    468 
    469 void RenderMedia::changeOpacity(HTMLElement* e, float opacity)
    470 {
    471     if (!e || !e->renderer() || !e->renderer()->style())
    472         return;
    473     RefPtr<RenderStyle> s = RenderStyle::clone(e->renderer()->style());
    474     s->setOpacity(opacity);
    475     // z-index can't be auto if opacity is used
    476     s->setZIndex(0);
    477     e->renderer()->setStyle(s.release());
    478 }
    479 
    480 void RenderMedia::opacityAnimationTimerFired(Timer<RenderMedia>*)
    481 {
    482     double time = currentTime() - m_opacityAnimationStartTime;
    483     if (time >= m_opacityAnimationDuration) {
    484         time = m_opacityAnimationDuration;
    485         m_opacityAnimationTimer.stop();
    486     }
    487     float opacity = narrowPrecisionToFloat(m_opacityAnimationFrom + (m_opacityAnimationTo - m_opacityAnimationFrom) * time / m_opacityAnimationDuration);
    488     changeOpacity(m_panel.get(), opacity);
    489 }
    490 
    491 void RenderMedia::updateVolumeSliderContainer(bool visible)
    492 {
    493     if (!mediaElement()->hasAudio() || !m_volumeSliderContainer || !m_volumeSlider)
    494         return;
    495 
    496     if (visible && !m_volumeSliderContainer->isVisible()) {
    497         if (!m_muteButton || !m_muteButton->renderer() || !m_muteButton->renderBox())
    498             return;
    499 
    500         RefPtr<RenderStyle> s = m_volumeSliderContainer->styleForElement();
    501         int height = s->height().isPercent() ? 0 : s->height().value();
    502         int x = m_muteButton->renderBox()->offsetLeft();
    503         int y = m_muteButton->renderBox()->offsetTop() - height;
    504         FloatPoint absPoint = m_muteButton->renderer()->localToAbsolute(FloatPoint(x, y), true, true);
    505         if (absPoint.y() < 0)
    506             y = m_muteButton->renderBox()->offsetTop() + m_muteButton->renderBox()->height();
    507         m_volumeSliderContainer->setVisible(true);
    508         m_volumeSliderContainer->setPosition(x, y);
    509         m_volumeSliderContainer->update();
    510         m_volumeSlider->update();
    511     } else if (!visible && m_volumeSliderContainer->isVisible()) {
    512         m_volumeSliderContainer->setVisible(false);
    513         m_volumeSliderContainer->updateStyle();
    514     }
    515 }
    516 
    517 void RenderMedia::forwardEvent(Event* event)
    518 {
    519     if (event->isMouseEvent() && m_controlsShadowRoot) {
    520         MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
    521         IntPoint point(mouseEvent->absoluteLocation());
    522         bool showVolumeSlider = false;
    523         if (m_muteButton && m_muteButton->hitTest(point)) {
    524             m_muteButton->defaultEventHandler(event);
    525             if (event->type() != eventNames().mouseoutEvent)
    526                 showVolumeSlider = true;
    527         }
    528 
    529         if (m_volumeSliderContainer && m_volumeSliderContainer->hitTest(point))
    530             showVolumeSlider = true;
    531 
    532         if (m_volumeSlider && m_volumeSlider->hitTest(point)) {
    533             m_volumeSlider->defaultEventHandler(event);
    534             showVolumeSlider = true;
    535         }
    536 
    537         updateVolumeSliderContainer(showVolumeSlider);
    538 
    539         if (m_playButton && m_playButton->hitTest(point))
    540             m_playButton->defaultEventHandler(event);
    541 
    542         if (m_seekBackButton && m_seekBackButton->hitTest(point))
    543             m_seekBackButton->defaultEventHandler(event);
    544 
    545         if (m_seekForwardButton && m_seekForwardButton->hitTest(point))
    546             m_seekForwardButton->defaultEventHandler(event);
    547 
    548         if (m_rewindButton && m_rewindButton->hitTest(point))
    549             m_rewindButton->defaultEventHandler(event);
    550 
    551         if (m_returnToRealtimeButton && m_returnToRealtimeButton->hitTest(point))
    552             m_returnToRealtimeButton->defaultEventHandler(event);
    553 
    554        if (m_toggleClosedCaptionsButton && m_toggleClosedCaptionsButton->hitTest(point))
    555             m_toggleClosedCaptionsButton->defaultEventHandler(event);
    556 
    557         if (m_timeline && m_timeline->hitTest(point))
    558             m_timeline->defaultEventHandler(event);
    559 
    560         if (m_fullscreenButton && m_fullscreenButton->hitTest(point))
    561             m_fullscreenButton->defaultEventHandler(event);
    562 
    563         if (event->type() == eventNames().mouseoverEvent) {
    564             m_mouseOver = true;
    565             updateControlVisibility();
    566         }
    567         if (event->type() == eventNames().mouseoutEvent) {
    568             // When the scrollbar thumb captures mouse events, we should treat the mouse as still being over our renderer if the new target is a descendant
    569             Node* mouseOverNode = mouseEvent->relatedTarget() ? mouseEvent->relatedTarget()->toNode() : 0;
    570             RenderObject* mouseOverRenderer = mouseOverNode ? mouseOverNode->renderer() : 0;
    571             m_mouseOver = mouseOverRenderer && mouseOverRenderer->isDescendantOf(this);
    572             updateControlVisibility();
    573         }
    574     }
    575 }
    576 
    577 int RenderMedia::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
    578 {
    579     int bottom = RenderImage::lowestPosition(includeOverflowInterior, includeSelf);
    580     if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer())
    581         return bottom;
    582 
    583     return max(bottom,  m_controlsShadowRoot->renderBox()->y() + m_controlsShadowRoot->renderBox()->lowestPosition(includeOverflowInterior, includeSelf));
    584 }
    585 
    586 int RenderMedia::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
    587 {
    588     int right = RenderImage::rightmostPosition(includeOverflowInterior, includeSelf);
    589     if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer())
    590         return right;
    591 
    592     return max(right, m_controlsShadowRoot->renderBox()->x() + m_controlsShadowRoot->renderBox()->rightmostPosition(includeOverflowInterior, includeSelf));
    593 }
    594 
    595 int RenderMedia::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
    596 {
    597     int left = RenderImage::leftmostPosition(includeOverflowInterior, includeSelf);
    598     if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer())
    599         return left;
    600 
    601     return min(left, m_controlsShadowRoot->renderBox()->x() +  m_controlsShadowRoot->renderBox()->leftmostPosition(includeOverflowInterior, includeSelf));
    602 }
    603 
    604 
    605 // We want the timeline slider to be at least 100 pixels wide.
    606 static const int minWidthToDisplayTimeDisplays = 16 + 16 + 45 + 100 + 45 + 16 + 1;
    607 
    608 bool RenderMedia::shouldShowTimeDisplayControls() const
    609 {
    610     if (!m_currentTimeDisplay && !m_timeRemainingDisplay)
    611         return false;
    612 
    613     int width = mediaElement()->renderBox()->width();
    614     return width >= minWidthToDisplayTimeDisplays * style()->effectiveZoom();
    615 }
    616 
    617 } // namespace WebCore
    618 
    619 #endif
    620