Home | History | Annotate | Download | only in rendering
      1 /*
      2  * Copyright (C) 2008, 2009 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  *
      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  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     14  *     its contributors may be used to endorse or promote products derived
     15  *     from this software without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include "config.h"
     30 
     31 #if ENABLE(VIDEO)
     32 
     33 #include "MediaControlElements.h"
     34 
     35 #include "EventNames.h"
     36 #include "FloatConversion.h"
     37 #include "Frame.h"
     38 #include "HTMLNames.h"
     39 #include "LocalizedStrings.h"
     40 #include "MouseEvent.h"
     41 #include "Page.h"
     42 #include "RenderMedia.h"
     43 #include "RenderSlider.h"
     44 #include "RenderTheme.h"
     45 
     46 namespace WebCore {
     47 
     48 using namespace HTMLNames;
     49 
     50 HTMLMediaElement* toParentMediaElement(RenderObject* o)
     51 {
     52     Node* node = o->node();
     53     Node* mediaNode = node ? node->shadowAncestorNode() : 0;
     54     if (!mediaNode || (!mediaNode->hasTagName(HTMLNames::videoTag) && !mediaNode->hasTagName(HTMLNames::audioTag)))
     55         return 0;
     56 
     57     return static_cast<HTMLMediaElement*>(mediaNode);
     58 }
     59 
     60 // FIXME: These constants may need to be tweaked to better match the seeking in the QuickTime plug-in.
     61 static const float cSeekRepeatDelay = 0.1f;
     62 static const float cStepTime = 0.07f;
     63 static const float cSeekTime = 0.2f;
     64 
     65 MediaControlShadowRootElement::MediaControlShadowRootElement(Document* document, HTMLMediaElement* mediaElement)
     66     : HTMLDivElement(divTag, document)
     67     , m_mediaElement(mediaElement)
     68 {
     69     RefPtr<RenderStyle> rootStyle = RenderStyle::create();
     70     rootStyle->inheritFrom(mediaElement->renderer()->style());
     71     rootStyle->setDisplay(BLOCK);
     72     rootStyle->setPosition(RelativePosition);
     73     RenderMediaControlShadowRoot* renderer = new (mediaElement->renderer()->renderArena()) RenderMediaControlShadowRoot(this);
     74     renderer->setStyle(rootStyle.release());
     75     setRenderer(renderer);
     76     setAttached();
     77     setInDocument(true);
     78 }
     79 
     80 void MediaControlShadowRootElement::updateStyle()
     81 {
     82     if (renderer()) {
     83         RenderStyle* timelineContainerStyle = m_mediaElement->renderer()->getCachedPseudoStyle(MEDIA_CONTROLS_TIMELINE_CONTAINER);
     84         renderer()->setStyle(timelineContainerStyle);
     85     }
     86 }
     87 
     88 // ----------------------------
     89 
     90 MediaControlElement::MediaControlElement(Document* document, PseudoId pseudo, HTMLMediaElement* mediaElement)
     91     : HTMLDivElement(divTag, document)
     92     , m_mediaElement(mediaElement)
     93     , m_pseudoStyleId(pseudo)
     94 {
     95     setInDocument(true);
     96     switch (pseudo) {
     97     case MEDIA_CONTROLS_CURRENT_TIME_DISPLAY:
     98         m_displayType = MediaCurrentTimeDisplay;
     99         break;
    100     case MEDIA_CONTROLS_TIME_REMAINING_DISPLAY:
    101         m_displayType = MediaTimeRemainingDisplay;
    102         break;
    103     case MEDIA_CONTROLS_TIMELINE_CONTAINER:
    104         m_displayType = MediaTimelineContainer;
    105         break;
    106     case MEDIA_CONTROLS_STATUS_DISPLAY:
    107         m_displayType = MediaStatusDisplay;
    108         break;
    109     case MEDIA_CONTROLS_PANEL:
    110         m_displayType = MediaControlsPanel;
    111         break;
    112     case MEDIA_CONTROLS_VOLUME_SLIDER_CONTAINER:
    113         m_displayType = MediaVolumeSliderContainer;
    114         break;
    115     default:
    116         ASSERT_NOT_REACHED();
    117         break;
    118     }
    119 }
    120 
    121 void MediaControlElement::attachToParent(Element* parent)
    122 {
    123     parent->addChild(this);
    124 }
    125 
    126 void MediaControlElement::update()
    127 {
    128     if (renderer())
    129         renderer()->updateFromElement();
    130     updateStyle();
    131 }
    132 
    133 PassRefPtr<RenderStyle> MediaControlElement::styleForElement()
    134 {
    135     RenderStyle* style = m_mediaElement->renderer()->getCachedPseudoStyle(m_pseudoStyleId);
    136     if (!style)
    137         return 0;
    138 
    139     // text-decoration can't be overrided from CSS. So we do it here.
    140     // See https://bugs.webkit.org/show_bug.cgi?id=27015
    141     style->setTextDecoration(TDNONE);
    142     style->setTextDecorationsInEffect(TDNONE);
    143 
    144     return style;
    145 }
    146 
    147 bool MediaControlElement::rendererIsNeeded(RenderStyle* style)
    148 {
    149     ASSERT(document()->page());
    150 
    151     return HTMLDivElement::rendererIsNeeded(style) && parent() && parent()->renderer()
    152         && (!style->hasAppearance() || document()->page()->theme()->shouldRenderMediaControlPart(style->appearance(), m_mediaElement));
    153 }
    154 
    155 void MediaControlElement::attach()
    156 {
    157     RefPtr<RenderStyle> style = styleForElement();
    158     if (!style)
    159         return;
    160     bool needsRenderer = rendererIsNeeded(style.get());
    161     if (!needsRenderer)
    162         return;
    163     RenderObject* renderer = createRenderer(m_mediaElement->renderer()->renderArena(), style.get());
    164     if (!renderer)
    165         return;
    166     renderer->setStyle(style.get());
    167     setRenderer(renderer);
    168     if (parent() && parent()->renderer()) {
    169         // Find next sibling with a renderer to determine where to insert.
    170         Node* sibling = nextSibling();
    171         while (sibling && !sibling->renderer())
    172             sibling = sibling->nextSibling();
    173         parent()->renderer()->addChild(renderer, sibling ? sibling->renderer() : 0);
    174     }
    175     ContainerNode::attach();
    176 }
    177 
    178 void MediaControlElement::updateStyle()
    179 {
    180     if (!m_mediaElement || !m_mediaElement->renderer())
    181         return;
    182 
    183     RefPtr<RenderStyle> style = styleForElement();
    184     if (!style)
    185         return;
    186 
    187     bool needsRenderer = rendererIsNeeded(style.get()) && parent() && parent()->renderer();
    188     if (renderer() && !needsRenderer)
    189         detach();
    190     else if (!renderer() && needsRenderer)
    191         attach();
    192     else if (renderer()) {
    193         renderer()->setStyle(style.get());
    194 
    195         // Make sure that if there is any innerText renderer, it is updated as well.
    196         if (firstChild() && firstChild()->renderer())
    197             firstChild()->renderer()->setStyle(style.get());
    198     }
    199 }
    200 
    201 // ----------------------------
    202 
    203 MediaControlTimelineContainerElement::MediaControlTimelineContainerElement(Document* document, HTMLMediaElement* element)
    204     : MediaControlElement(document, MEDIA_CONTROLS_TIMELINE_CONTAINER, element)
    205 {
    206 }
    207 
    208 bool MediaControlTimelineContainerElement::rendererIsNeeded(RenderStyle* style)
    209 {
    210     if (!MediaControlElement::rendererIsNeeded(style))
    211         return false;
    212 
    213     // This is for MediaControllerThemeClassic:
    214     // If there is no style for MediaControlStatusDisplayElement style, don't hide
    215     // the timeline.
    216     if (!m_mediaElement->renderer()->getCachedPseudoStyle(MEDIA_CONTROLS_STATUS_DISPLAY))
    217         return true;
    218 
    219     float duration = m_mediaElement->duration();
    220     return !isnan(duration) && !isinf(duration);
    221 }
    222 
    223 // ----------------------------
    224 
    225 MediaControlVolumeSliderContainerElement::MediaControlVolumeSliderContainerElement(Document* doc, HTMLMediaElement* element)
    226     : MediaControlElement(doc, MEDIA_CONTROLS_VOLUME_SLIDER_CONTAINER, element)
    227     , m_isVisible(false)
    228     , m_x(0)
    229     , m_y(0)
    230 {
    231 }
    232 
    233 PassRefPtr<RenderStyle> MediaControlVolumeSliderContainerElement::styleForElement()
    234 {
    235     RefPtr<RenderStyle> style = MediaControlElement::styleForElement();
    236     style->setPosition(AbsolutePosition);
    237     style->setLeft(Length(m_x, Fixed));
    238     style->setTop(Length(m_y, Fixed));
    239     style->setDisplay(m_isVisible ? BLOCK : NONE);
    240     return style;
    241 }
    242 
    243 void MediaControlVolumeSliderContainerElement::setVisible(bool visible)
    244 {
    245     if (visible == m_isVisible)
    246         return;
    247     m_isVisible = visible;
    248 }
    249 
    250 void MediaControlVolumeSliderContainerElement::setPosition(int x, int y)
    251 {
    252     if (x == m_x && y == m_y)
    253         return;
    254     m_x = x;
    255     m_y = y;
    256 }
    257 
    258 bool MediaControlVolumeSliderContainerElement::hitTest(const IntPoint& absPoint)
    259 {
    260     if (renderer() && renderer()->style()->hasAppearance())
    261         return renderer()->theme()->hitTestMediaControlPart(renderer(), absPoint);
    262 
    263     return false;
    264 }
    265 
    266 // ----------------------------
    267 
    268 MediaControlStatusDisplayElement::MediaControlStatusDisplayElement(Document* document, HTMLMediaElement* element)
    269     : MediaControlElement(document, MEDIA_CONTROLS_STATUS_DISPLAY, element)
    270     , m_stateBeingDisplayed(Nothing)
    271 {
    272 }
    273 
    274 void MediaControlStatusDisplayElement::update()
    275 {
    276     MediaControlElement::update();
    277 
    278     // Get the new state that we'll have to display.
    279     StateBeingDisplayed newStateToDisplay = Nothing;
    280 
    281     if (m_mediaElement->readyState() != HTMLMediaElement::HAVE_ENOUGH_DATA && !m_mediaElement->currentSrc().isEmpty())
    282         newStateToDisplay = Loading;
    283     else if (m_mediaElement->movieLoadType() == MediaPlayer::LiveStream)
    284         newStateToDisplay = LiveBroadcast;
    285 
    286     // Propagate only if needed.
    287     if (newStateToDisplay == m_stateBeingDisplayed)
    288         return;
    289     m_stateBeingDisplayed = newStateToDisplay;
    290 
    291     ExceptionCode e;
    292     switch (m_stateBeingDisplayed) {
    293     case Nothing:
    294         setInnerText("", e);
    295         break;
    296     case Loading:
    297         setInnerText(mediaElementLoadingStateText(), e);
    298         break;
    299     case LiveBroadcast:
    300         setInnerText(mediaElementLiveBroadcastStateText(), e);
    301         break;
    302     }
    303 }
    304 
    305 bool MediaControlStatusDisplayElement::rendererIsNeeded(RenderStyle* style)
    306 {
    307     if (!MediaControlElement::rendererIsNeeded(style))
    308         return false;
    309     float duration = m_mediaElement->duration();
    310     return (isnan(duration) || isinf(duration));
    311 }
    312 
    313 // ----------------------------
    314 
    315 MediaControlInputElement::MediaControlInputElement(Document* document, PseudoId pseudo, const String& type, HTMLMediaElement* mediaElement)
    316     : HTMLInputElement(inputTag, document)
    317     , m_mediaElement(mediaElement)
    318     , m_pseudoStyleId(pseudo)
    319 {
    320     setInputType(type);
    321     setInDocument(true);
    322 
    323     switch (pseudo) {
    324     case MEDIA_CONTROLS_MUTE_BUTTON:
    325         m_displayType = MediaMuteButton;
    326         break;
    327     case MEDIA_CONTROLS_PLAY_BUTTON:
    328         m_displayType = MediaPlayButton;
    329         break;
    330     case MEDIA_CONTROLS_SEEK_FORWARD_BUTTON:
    331         m_displayType = MediaSeekForwardButton;
    332         break;
    333     case MEDIA_CONTROLS_SEEK_BACK_BUTTON:
    334         m_displayType = MediaSeekBackButton;
    335         break;
    336     case MEDIA_CONTROLS_FULLSCREEN_BUTTON:
    337         m_displayType = MediaFullscreenButton;
    338         break;
    339     case MEDIA_CONTROLS_TIMELINE:
    340         m_displayType = MediaSlider;
    341         break;
    342     case MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON:
    343         m_displayType = MediaReturnToRealtimeButton;
    344         break;
    345     case MEDIA_CONTROLS_REWIND_BUTTON:
    346         m_displayType = MediaRewindButton;
    347         break;
    348     case MEDIA_CONTROLS_VOLUME_SLIDER:
    349         m_displayType = MediaVolumeSlider;
    350         break;
    351     case MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON:
    352         m_displayType = MediaShowClosedCaptionsButton;
    353         break;
    354     default:
    355         ASSERT_NOT_REACHED();
    356         break;
    357     }
    358 }
    359 
    360 void MediaControlInputElement::attachToParent(Element* parent)
    361 {
    362     parent->addChild(this);
    363 }
    364 
    365 void MediaControlInputElement::update()
    366 {
    367     updateDisplayType();
    368     if (renderer())
    369         renderer()->updateFromElement();
    370     updateStyle();
    371 }
    372 
    373 PassRefPtr<RenderStyle> MediaControlInputElement::styleForElement()
    374 {
    375     return m_mediaElement->renderer()->getCachedPseudoStyle(m_pseudoStyleId);
    376 }
    377 
    378 bool MediaControlInputElement::rendererIsNeeded(RenderStyle* style)
    379 {
    380     ASSERT(document()->page());
    381 
    382     return HTMLInputElement::rendererIsNeeded(style) && parent() && parent()->renderer()
    383         && (!style->hasAppearance() || document()->page()->theme()->shouldRenderMediaControlPart(style->appearance(), m_mediaElement));
    384 }
    385 
    386 void MediaControlInputElement::attach()
    387 {
    388     RefPtr<RenderStyle> style = styleForElement();
    389     if (!style)
    390         return;
    391 
    392     bool needsRenderer = rendererIsNeeded(style.get());
    393     if (!needsRenderer)
    394         return;
    395     RenderObject* renderer = createRenderer(m_mediaElement->renderer()->renderArena(), style.get());
    396     if (!renderer)
    397         return;
    398     renderer->setStyle(style.get());
    399     setRenderer(renderer);
    400     if (parent() && parent()->renderer()) {
    401         // Find next sibling with a renderer to determine where to insert.
    402         Node* sibling = nextSibling();
    403         while (sibling && !sibling->renderer())
    404             sibling = sibling->nextSibling();
    405         parent()->renderer()->addChild(renderer, sibling ? sibling->renderer() : 0);
    406     }
    407     ContainerNode::attach();
    408 }
    409 
    410 void MediaControlInputElement::updateStyle()
    411 {
    412     if (!m_mediaElement || !m_mediaElement->renderer())
    413         return;
    414 
    415     RefPtr<RenderStyle> style = styleForElement();
    416     if (!style)
    417         return;
    418 
    419     bool needsRenderer = rendererIsNeeded(style.get()) && parent() && parent()->renderer();
    420     if (renderer() && !needsRenderer)
    421         detach();
    422     else if (!renderer() && needsRenderer)
    423         attach();
    424     else if (renderer())
    425         renderer()->setStyle(style.get());
    426 }
    427 
    428 bool MediaControlInputElement::hitTest(const IntPoint& absPoint)
    429 {
    430     if (renderer() && renderer()->style()->hasAppearance())
    431         return renderer()->theme()->hitTestMediaControlPart(renderer(), absPoint);
    432 
    433     return false;
    434 }
    435 
    436 void MediaControlInputElement::setDisplayType(MediaControlElementType displayType)
    437 {
    438     if (displayType == m_displayType)
    439         return;
    440 
    441     m_displayType = displayType;
    442     if (RenderObject* object = renderer())
    443         object->repaint();
    444 }
    445 
    446 // ----------------------------
    447 
    448 MediaControlMuteButtonElement::MediaControlMuteButtonElement(Document* document, HTMLMediaElement* element)
    449     : MediaControlInputElement(document, MEDIA_CONTROLS_MUTE_BUTTON, "button", element)
    450 {
    451 }
    452 
    453 void MediaControlMuteButtonElement::defaultEventHandler(Event* event)
    454 {
    455     if (event->type() == eventNames().clickEvent) {
    456         m_mediaElement->setMuted(!m_mediaElement->muted());
    457         event->setDefaultHandled();
    458     }
    459     HTMLInputElement::defaultEventHandler(event);
    460 }
    461 
    462 void MediaControlMuteButtonElement::updateDisplayType()
    463 {
    464     setDisplayType(m_mediaElement->muted() ? MediaUnMuteButton : MediaMuteButton);
    465 }
    466 
    467 // ----------------------------
    468 
    469 MediaControlPlayButtonElement::MediaControlPlayButtonElement(Document* document, HTMLMediaElement* element)
    470     : MediaControlInputElement(document, MEDIA_CONTROLS_PLAY_BUTTON, "button", element)
    471 {
    472 }
    473 
    474 void MediaControlPlayButtonElement::defaultEventHandler(Event* event)
    475 {
    476     if (event->type() == eventNames().clickEvent) {
    477         m_mediaElement->togglePlayState();
    478         event->setDefaultHandled();
    479     }
    480     HTMLInputElement::defaultEventHandler(event);
    481 }
    482 
    483 void MediaControlPlayButtonElement::updateDisplayType()
    484 {
    485     setDisplayType(m_mediaElement->canPlay() ? MediaPlayButton : MediaPauseButton);
    486 }
    487 
    488 // ----------------------------
    489 
    490 MediaControlSeekButtonElement::MediaControlSeekButtonElement(Document* document, HTMLMediaElement* element, bool forward)
    491     : MediaControlInputElement(document, forward ? MEDIA_CONTROLS_SEEK_FORWARD_BUTTON : MEDIA_CONTROLS_SEEK_BACK_BUTTON,
    492                                "button", element)
    493     , m_forward(forward)
    494     , m_seeking(false)
    495     , m_capturing(false)
    496     , m_seekTimer(this, &MediaControlSeekButtonElement::seekTimerFired)
    497 {
    498 }
    499 
    500 void MediaControlSeekButtonElement::defaultEventHandler(Event* event)
    501 {
    502     if (event->type() == eventNames().mousedownEvent) {
    503         if (Frame* frame = document()->frame()) {
    504             m_capturing = true;
    505             frame->eventHandler()->setCapturingMouseEventsNode(this);
    506         }
    507         m_mediaElement->pause(event->fromUserGesture());
    508         m_seekTimer.startRepeating(cSeekRepeatDelay);
    509         event->setDefaultHandled();
    510     } else if (event->type() == eventNames().mouseupEvent) {
    511         if (m_capturing)
    512             if (Frame* frame = document()->frame()) {
    513                 m_capturing = false;
    514                 frame->eventHandler()->setCapturingMouseEventsNode(0);
    515             }
    516         ExceptionCode ec;
    517         if (m_seeking || m_seekTimer.isActive()) {
    518             if (!m_seeking) {
    519                 float stepTime = m_forward ? cStepTime : -cStepTime;
    520                 m_mediaElement->setCurrentTime(m_mediaElement->currentTime() + stepTime, ec);
    521             }
    522             m_seekTimer.stop();
    523             m_seeking = false;
    524             event->setDefaultHandled();
    525         }
    526     }
    527     HTMLInputElement::defaultEventHandler(event);
    528 }
    529 
    530 void MediaControlSeekButtonElement::seekTimerFired(Timer<MediaControlSeekButtonElement>*)
    531 {
    532     ExceptionCode ec;
    533     m_seeking = true;
    534     float seekTime = m_forward ? cSeekTime : -cSeekTime;
    535     m_mediaElement->setCurrentTime(m_mediaElement->currentTime() + seekTime, ec);
    536 }
    537 
    538 void MediaControlSeekButtonElement::detach()
    539 {
    540     if (m_capturing) {
    541         if (Frame* frame = document()->frame())
    542             frame->eventHandler()->setCapturingMouseEventsNode(0);
    543     }
    544     MediaControlInputElement::detach();
    545 }
    546 
    547 
    548 // ----------------------------
    549 
    550 MediaControlRewindButtonElement::MediaControlRewindButtonElement(Document* document, HTMLMediaElement* element)
    551     : MediaControlInputElement(document, MEDIA_CONTROLS_REWIND_BUTTON, "button", element)
    552 {
    553 }
    554 
    555 void MediaControlRewindButtonElement::defaultEventHandler(Event* event)
    556 {
    557     if (event->type() == eventNames().clickEvent) {
    558         m_mediaElement->rewind(30);
    559         event->setDefaultHandled();
    560     }
    561     HTMLInputElement::defaultEventHandler(event);
    562 }
    563 
    564 
    565 // ----------------------------
    566 
    567 MediaControlReturnToRealtimeButtonElement::MediaControlReturnToRealtimeButtonElement(Document* document, HTMLMediaElement* element)
    568     : MediaControlInputElement(document, MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON, "button", element)
    569 {
    570 }
    571 
    572 void MediaControlReturnToRealtimeButtonElement::defaultEventHandler(Event* event)
    573 {
    574     if (event->type() == eventNames().clickEvent) {
    575         m_mediaElement->returnToRealtime();
    576         event->setDefaultHandled();
    577     }
    578     HTMLInputElement::defaultEventHandler(event);
    579 }
    580 
    581 
    582 // ----------------------------
    583 
    584 MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement(Document* doc, HTMLMediaElement* element)
    585     : MediaControlInputElement(doc, MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON, "button", element)
    586 {
    587 }
    588 
    589 void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event)
    590 {
    591     if (event->type() == eventNames().clickEvent) {
    592         m_mediaElement->setClosedCaptionsVisible(!m_mediaElement->closedCaptionsVisible());
    593         setChecked(m_mediaElement->closedCaptionsVisible());
    594         event->setDefaultHandled();
    595     }
    596     HTMLInputElement::defaultEventHandler(event);
    597 }
    598 
    599 void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType()
    600 {
    601     setDisplayType(m_mediaElement->closedCaptionsVisible() ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton);
    602 }
    603 
    604 
    605 // ----------------------------
    606 
    607 MediaControlTimelineElement::MediaControlTimelineElement(Document* document, HTMLMediaElement* element)
    608     : MediaControlInputElement(document, MEDIA_CONTROLS_TIMELINE, "range", element)
    609 {
    610 }
    611 
    612 void MediaControlTimelineElement::defaultEventHandler(Event* event)
    613 {
    614     // Left button is 0. Rejects mouse events not from left button.
    615     if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button())
    616         return;
    617 
    618     if (event->type() == eventNames().mousedownEvent)
    619         m_mediaElement->beginScrubbing();
    620 
    621     MediaControlInputElement::defaultEventHandler(event);
    622 
    623     if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
    624         return;
    625 
    626     float time = narrowPrecisionToFloat(value().toDouble());
    627     if (time != m_mediaElement->currentTime()) {
    628         ExceptionCode ec;
    629         m_mediaElement->setCurrentTime(time, ec);
    630     }
    631 
    632     RenderSlider* slider = toRenderSlider(renderer());
    633     if (slider && slider->inDragMode())
    634         toRenderMedia(m_mediaElement->renderer())->updateTimeDisplay();
    635 
    636     if (event->type() == eventNames().mouseupEvent)
    637         m_mediaElement->endScrubbing();
    638 }
    639 
    640 void MediaControlTimelineElement::update(bool updateDuration)
    641 {
    642     if (updateDuration) {
    643         float dur = m_mediaElement->duration();
    644         setAttribute(maxAttr, String::number(isfinite(dur) ? dur : 0));
    645     }
    646     setValue(String::number(m_mediaElement->currentTime()));
    647     MediaControlInputElement::update();
    648 }
    649 
    650 // ----------------------------
    651 
    652 MediaControlVolumeSliderElement::MediaControlVolumeSliderElement(Document* document, HTMLMediaElement* element)
    653     : MediaControlInputElement(document, MEDIA_CONTROLS_VOLUME_SLIDER, "range", element)
    654 {
    655 }
    656 
    657 void MediaControlVolumeSliderElement::defaultEventHandler(Event* event)
    658 {
    659     // Left button is 0. Rejects mouse events not from left button.
    660     if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button())
    661         return;
    662 
    663     MediaControlInputElement::defaultEventHandler(event);
    664 
    665     if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
    666         return;
    667 
    668     float volume = narrowPrecisionToFloat(value().toDouble());
    669     if (volume != m_mediaElement->volume()) {
    670         ExceptionCode ec = 0;
    671         m_mediaElement->setVolume(volume, ec);
    672         ASSERT(!ec);
    673     }
    674 }
    675 
    676 void MediaControlVolumeSliderElement::update()
    677 {
    678     float volume = m_mediaElement->volume();
    679     if (value().toFloat() != volume)
    680         setValue(String::number(volume));
    681     MediaControlInputElement::update();
    682 }
    683 
    684 // ----------------------------
    685 
    686 MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(Document* document, HTMLMediaElement* element)
    687     : MediaControlInputElement(document, MEDIA_CONTROLS_FULLSCREEN_BUTTON, "button", element)
    688 {
    689 }
    690 
    691 void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event)
    692 {
    693     if (event->type() == eventNames().clickEvent) {
    694         m_mediaElement->enterFullscreen();
    695         event->setDefaultHandled();
    696     }
    697     HTMLInputElement::defaultEventHandler(event);
    698 }
    699 
    700 // ----------------------------
    701 
    702 MediaControlTimeDisplayElement::MediaControlTimeDisplayElement(Document* document, PseudoId pseudo, HTMLMediaElement* element)
    703     : MediaControlElement(document, pseudo, element)
    704     , m_currentValue(0)
    705     , m_isVisible(true)
    706 {
    707 }
    708 
    709 PassRefPtr<RenderStyle> MediaControlTimeDisplayElement::styleForElement()
    710 {
    711     RefPtr<RenderStyle> style = MediaControlElement::styleForElement();
    712     if (!m_isVisible) {
    713         style = RenderStyle::clone(style.get());
    714         style->setWidth(Length(0, Fixed));
    715     }
    716     return style;
    717 }
    718 
    719 void MediaControlTimeDisplayElement::setVisible(bool visible)
    720 {
    721     if (visible == m_isVisible)
    722         return;
    723     m_isVisible = visible;
    724 
    725     // This function is used during the RenderMedia::layout()
    726     // call, where we cannot change the renderer at this time.
    727     if (!renderer() || !renderer()->style())
    728         return;
    729 
    730     RefPtr<RenderStyle> style = styleForElement();
    731     renderer()->setStyle(style.get());
    732 }
    733 
    734 void MediaControlTimeDisplayElement::setCurrentValue(float time)
    735 {
    736     m_currentValue = time;
    737 }
    738 
    739 
    740 } //namespace WebCore
    741 #endif // enable(video)
    742