Home | History | Annotate | Download | only in shadow
      1 /*
      2  * Copyright (C) 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  *
      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 "CSSStyleSelector.h"
     36 #include "EventNames.h"
     37 #include "FloatConversion.h"
     38 #include "Frame.h"
     39 #include "HTMLNames.h"
     40 #include "LocalizedStrings.h"
     41 #include "MediaControls.h"
     42 #include "MouseEvent.h"
     43 #include "Page.h"
     44 #include "RenderFlexibleBox.h"
     45 #include "RenderMedia.h"
     46 #include "RenderSlider.h"
     47 #include "RenderTheme.h"
     48 #include "RenderView.h"
     49 #include "Settings.h"
     50 
     51 namespace WebCore {
     52 
     53 using namespace HTMLNames;
     54 
     55 HTMLMediaElement* toParentMediaElement(RenderObject* o)
     56 {
     57     Node* node = o->node();
     58     Node* mediaNode = node ? node->shadowAncestorNode() : 0;
     59     if (!mediaNode || (!mediaNode->hasTagName(HTMLNames::videoTag) && !mediaNode->hasTagName(HTMLNames::audioTag)))
     60         return 0;
     61 
     62     return static_cast<HTMLMediaElement*>(mediaNode);
     63 }
     64 
     65 // FIXME: These constants may need to be tweaked to better match the seeking in the QuickTime plug-in.
     66 static const float cSeekRepeatDelay = 0.1f;
     67 static const float cStepTime = 0.07f;
     68 static const float cSeekTime = 0.2f;
     69 
     70 // ----------------------------
     71 
     72 MediaControlElement::MediaControlElement(HTMLMediaElement* mediaElement)
     73     : HTMLDivElement(divTag, mediaElement->document())
     74     , m_mediaElement(mediaElement)
     75 {
     76 }
     77 
     78 static const String& displayString()
     79 {
     80     DEFINE_STATIC_LOCAL(String, s, ("display"));
     81     return s;
     82 }
     83 
     84 void MediaControlElement::show()
     85 {
     86     ExceptionCode ec;
     87     // FIXME: Make more efficient <http://webkit.org/b/58157>
     88     style()->removeProperty(displayString(), ec);
     89 }
     90 
     91 void MediaControlElement::hide()
     92 {
     93     ExceptionCode ec;
     94     // FIXME: Make more efficient <http://webkit.org/b/58157>
     95     DEFINE_STATIC_LOCAL(String, none, ("none"));
     96     style()->setProperty(displayString(), none, ec);
     97 }
     98 
     99 // ----------------------------
    100 
    101 inline MediaControlPanelElement::MediaControlPanelElement(HTMLMediaElement* mediaElement)
    102     : MediaControlElement(mediaElement)
    103 {
    104 }
    105 
    106 PassRefPtr<MediaControlPanelElement> MediaControlPanelElement::create(HTMLMediaElement* mediaElement)
    107 {
    108     return adoptRef(new MediaControlPanelElement(mediaElement));
    109 }
    110 
    111 MediaControlElementType MediaControlPanelElement::displayType() const
    112 {
    113     return MediaControlsPanel;
    114 }
    115 
    116 const AtomicString& MediaControlPanelElement::shadowPseudoId() const
    117 {
    118     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-panel"));
    119     return id;
    120 }
    121 
    122 // ----------------------------
    123 
    124 inline MediaControlTimelineContainerElement::MediaControlTimelineContainerElement(HTMLMediaElement* mediaElement)
    125     : MediaControlElement(mediaElement)
    126 {
    127 }
    128 
    129 PassRefPtr<MediaControlTimelineContainerElement> MediaControlTimelineContainerElement::create(HTMLMediaElement* mediaElement)
    130 {
    131     RefPtr<MediaControlTimelineContainerElement> element = adoptRef(new MediaControlTimelineContainerElement(mediaElement));
    132     element->hide();
    133     return element.release();
    134 }
    135 
    136 MediaControlElementType MediaControlTimelineContainerElement::displayType() const
    137 {
    138     return MediaTimelineContainer;
    139 }
    140 
    141 const AtomicString& MediaControlTimelineContainerElement::shadowPseudoId() const
    142 {
    143     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-timeline-container"));
    144     return id;
    145 }
    146 
    147 // ----------------------------
    148 
    149 class RenderMediaVolumeSliderContainer : public RenderBlock {
    150 public:
    151     RenderMediaVolumeSliderContainer(Node*);
    152 
    153 private:
    154     virtual void layout();
    155 };
    156 
    157 RenderMediaVolumeSliderContainer::RenderMediaVolumeSliderContainer(Node* node)
    158     : RenderBlock(node)
    159 {
    160 }
    161 
    162 void RenderMediaVolumeSliderContainer::layout()
    163 {
    164     RenderBlock::layout();
    165     if (style()->display() == NONE || !previousSibling() || !previousSibling()->isBox())
    166         return;
    167 
    168     RenderBox* buttonBox = toRenderBox(previousSibling());
    169 
    170     if (view())
    171         view()->disableLayoutState();
    172 
    173     IntPoint offset = theme()->volumeSliderOffsetFromMuteButton(buttonBox, IntSize(width(), height()));
    174     setX(offset.x() + buttonBox->offsetLeft());
    175     setY(offset.y() + buttonBox->offsetTop());
    176 
    177     if (view())
    178         view()->enableLayoutState();
    179 }
    180 
    181 inline MediaControlVolumeSliderContainerElement::MediaControlVolumeSliderContainerElement(HTMLMediaElement* mediaElement)
    182     : MediaControlElement(mediaElement)
    183 {
    184 }
    185 
    186 PassRefPtr<MediaControlVolumeSliderContainerElement> MediaControlVolumeSliderContainerElement::create(HTMLMediaElement* mediaElement)
    187 {
    188     RefPtr<MediaControlVolumeSliderContainerElement> element = adoptRef(new MediaControlVolumeSliderContainerElement(mediaElement));
    189     element->hide();
    190     return element.release();
    191 }
    192 
    193 RenderObject* MediaControlVolumeSliderContainerElement::createRenderer(RenderArena* arena, RenderStyle*)
    194 {
    195     return new (arena) RenderMediaVolumeSliderContainer(this);
    196 }
    197 
    198 void MediaControlVolumeSliderContainerElement::defaultEventHandler(Event* event)
    199 {
    200     if (!event->isMouseEvent() || event->type() != eventNames().mouseoutEvent)
    201         return;
    202 
    203     // Poor man's mouseleave event detection.
    204     MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
    205     if (!mouseEvent->relatedTarget() || !mouseEvent->relatedTarget()->toNode())
    206         return;
    207 
    208     if (this->containsIncludingShadowDOM(mouseEvent->relatedTarget()->toNode()))
    209         return;
    210 
    211     hide();
    212 }
    213 
    214 
    215 MediaControlElementType MediaControlVolumeSliderContainerElement::displayType() const
    216 {
    217     return MediaVolumeSliderContainer;
    218 }
    219 
    220 const AtomicString& MediaControlVolumeSliderContainerElement::shadowPseudoId() const
    221 {
    222     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider-container"));
    223     return id;
    224 }
    225 
    226 // ----------------------------
    227 
    228 inline MediaControlStatusDisplayElement::MediaControlStatusDisplayElement(HTMLMediaElement* mediaElement)
    229     : MediaControlElement(mediaElement)
    230     , m_stateBeingDisplayed(Nothing)
    231 {
    232 }
    233 
    234 PassRefPtr<MediaControlStatusDisplayElement> MediaControlStatusDisplayElement::create(HTMLMediaElement* mediaElement)
    235 {
    236     RefPtr<MediaControlStatusDisplayElement> element = adoptRef(new MediaControlStatusDisplayElement(mediaElement));
    237     element->hide();
    238     return element.release();
    239 }
    240 
    241 void MediaControlStatusDisplayElement::update()
    242 {
    243     // Get the new state that we'll have to display.
    244     StateBeingDisplayed newStateToDisplay = Nothing;
    245 
    246     if (mediaElement()->readyState() != HTMLMediaElement::HAVE_ENOUGH_DATA && !mediaElement()->currentSrc().isEmpty())
    247         newStateToDisplay = Loading;
    248     else if (mediaElement()->movieLoadType() == MediaPlayer::LiveStream)
    249         newStateToDisplay = LiveBroadcast;
    250 
    251     if (newStateToDisplay == m_stateBeingDisplayed)
    252         return;
    253 
    254     ExceptionCode e;
    255 
    256     if (m_stateBeingDisplayed == Nothing)
    257         show();
    258     else if (newStateToDisplay == Nothing)
    259         hide();
    260 
    261     m_stateBeingDisplayed = newStateToDisplay;
    262 
    263     switch (m_stateBeingDisplayed) {
    264     case Nothing:
    265         setInnerText("", e);
    266         break;
    267     case Loading:
    268         setInnerText(mediaElementLoadingStateText(), e);
    269         break;
    270     case LiveBroadcast:
    271         setInnerText(mediaElementLiveBroadcastStateText(), e);
    272         break;
    273     }
    274 }
    275 
    276 MediaControlElementType MediaControlStatusDisplayElement::displayType() const
    277 {
    278     return MediaStatusDisplay;
    279 }
    280 
    281 const AtomicString& MediaControlStatusDisplayElement::shadowPseudoId() const
    282 {
    283     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-status-display"));
    284     return id;
    285 }
    286 
    287 // ----------------------------
    288 
    289 MediaControlInputElement::MediaControlInputElement(HTMLMediaElement* mediaElement, MediaControlElementType displayType)
    290     : HTMLInputElement(inputTag, mediaElement->document(), 0, false)
    291     , m_mediaElement(mediaElement)
    292     , m_displayType(displayType)
    293 {
    294 }
    295 
    296 void MediaControlInputElement::show()
    297 {
    298     ExceptionCode ec;
    299     style()->removeProperty(displayString(), ec);
    300 }
    301 
    302 void MediaControlInputElement::hide()
    303 {
    304     ExceptionCode ec;
    305     DEFINE_STATIC_LOCAL(String, none, ("none"));
    306     style()->setProperty(displayString(), none, ec);
    307 }
    308 
    309 
    310 void MediaControlInputElement::setDisplayType(MediaControlElementType displayType)
    311 {
    312     if (displayType == m_displayType)
    313         return;
    314 
    315     m_displayType = displayType;
    316     if (RenderObject* object = renderer())
    317         object->repaint();
    318 }
    319 
    320 // ----------------------------
    321 
    322 inline MediaControlMuteButtonElement::MediaControlMuteButtonElement(HTMLMediaElement* mediaElement, MediaControlElementType displayType)
    323     : MediaControlInputElement(mediaElement, displayType)
    324 {
    325 }
    326 
    327 void MediaControlMuteButtonElement::defaultEventHandler(Event* event)
    328 {
    329     if (event->type() == eventNames().clickEvent) {
    330         mediaElement()->setMuted(!mediaElement()->muted());
    331         event->setDefaultHandled();
    332     }
    333 
    334     HTMLInputElement::defaultEventHandler(event);
    335 }
    336 
    337 void MediaControlMuteButtonElement::changedMute()
    338 {
    339     updateDisplayType();
    340 }
    341 
    342 void MediaControlMuteButtonElement::updateDisplayType()
    343 {
    344     setDisplayType(mediaElement()->muted() ? MediaUnMuteButton : MediaMuteButton);
    345 }
    346 
    347 // ----------------------------
    348 
    349 inline MediaControlPanelMuteButtonElement::MediaControlPanelMuteButtonElement(HTMLMediaElement* mediaElement, MediaControls* controls)
    350     : MediaControlMuteButtonElement(mediaElement, MediaMuteButton)
    351     , m_controls(controls)
    352 {
    353 }
    354 
    355 PassRefPtr<MediaControlPanelMuteButtonElement> MediaControlPanelMuteButtonElement::create(HTMLMediaElement* mediaElement, MediaControls* controls)
    356 {
    357     ASSERT(controls);
    358 
    359     RefPtr<MediaControlPanelMuteButtonElement> button = adoptRef(new MediaControlPanelMuteButtonElement(mediaElement, controls));
    360     button->setType("button");
    361     return button.release();
    362 }
    363 
    364 void MediaControlPanelMuteButtonElement::defaultEventHandler(Event* event)
    365 {
    366     if (event->type() == eventNames().mouseoverEvent)
    367         m_controls->showVolumeSlider();
    368 
    369     MediaControlMuteButtonElement::defaultEventHandler(event);
    370 }
    371 
    372 const AtomicString& MediaControlPanelMuteButtonElement::shadowPseudoId() const
    373 {
    374     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-mute-button"));
    375     return id;
    376 }
    377 
    378 // ----------------------------
    379 
    380 inline MediaControlVolumeSliderMuteButtonElement::MediaControlVolumeSliderMuteButtonElement(HTMLMediaElement* mediaElement)
    381     : MediaControlMuteButtonElement(mediaElement, MediaMuteButton)
    382 {
    383 }
    384 
    385 PassRefPtr<MediaControlVolumeSliderMuteButtonElement> MediaControlVolumeSliderMuteButtonElement::create(HTMLMediaElement* mediaElement)
    386 {
    387     RefPtr<MediaControlVolumeSliderMuteButtonElement> button = adoptRef(new MediaControlVolumeSliderMuteButtonElement(mediaElement));
    388     button->setType("button");
    389     return button.release();
    390 }
    391 
    392 const AtomicString& MediaControlVolumeSliderMuteButtonElement::shadowPseudoId() const
    393 {
    394     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider-mute-button"));
    395     return id;
    396 }
    397 
    398 // ----------------------------
    399 
    400 inline MediaControlPlayButtonElement::MediaControlPlayButtonElement(HTMLMediaElement* mediaElement)
    401     : MediaControlInputElement(mediaElement, MediaPlayButton)
    402 {
    403 }
    404 
    405 PassRefPtr<MediaControlPlayButtonElement> MediaControlPlayButtonElement::create(HTMLMediaElement* mediaElement)
    406 {
    407     RefPtr<MediaControlPlayButtonElement> button = adoptRef(new MediaControlPlayButtonElement(mediaElement));
    408     button->setType("button");
    409     return button.release();
    410 }
    411 
    412 void MediaControlPlayButtonElement::defaultEventHandler(Event* event)
    413 {
    414     if (event->type() == eventNames().clickEvent) {
    415         mediaElement()->togglePlayState();
    416         updateDisplayType();
    417         event->setDefaultHandled();
    418     }
    419     HTMLInputElement::defaultEventHandler(event);
    420 }
    421 
    422 void MediaControlPlayButtonElement::updateDisplayType()
    423 {
    424     setDisplayType(mediaElement()->canPlay() ? MediaPlayButton : MediaPauseButton);
    425 }
    426 
    427 const AtomicString& MediaControlPlayButtonElement::shadowPseudoId() const
    428 {
    429     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-play-button"));
    430     return id;
    431 }
    432 
    433 // ----------------------------
    434 
    435 inline MediaControlSeekButtonElement::MediaControlSeekButtonElement(HTMLMediaElement* mediaElement, MediaControlElementType displayType)
    436     : MediaControlInputElement(mediaElement, displayType)
    437     , m_seeking(false)
    438     , m_capturing(false)
    439     , m_seekTimer(this, &MediaControlSeekButtonElement::seekTimerFired)
    440 {
    441 }
    442 
    443 void MediaControlSeekButtonElement::defaultEventHandler(Event* event)
    444 {
    445     if (event->type() == eventNames().mousedownEvent) {
    446         if (Frame* frame = document()->frame()) {
    447             m_capturing = true;
    448             frame->eventHandler()->setCapturingMouseEventsNode(this);
    449         }
    450         mediaElement()->pause(event->fromUserGesture());
    451         m_seekTimer.startRepeating(cSeekRepeatDelay);
    452         event->setDefaultHandled();
    453     } else if (event->type() == eventNames().mouseupEvent) {
    454         if (m_capturing)
    455             if (Frame* frame = document()->frame()) {
    456                 m_capturing = false;
    457                 frame->eventHandler()->setCapturingMouseEventsNode(0);
    458             }
    459         ExceptionCode ec;
    460         if (m_seeking || m_seekTimer.isActive()) {
    461             if (!m_seeking) {
    462                 float stepTime = isForwardButton() ? cStepTime : -cStepTime;
    463                 mediaElement()->setCurrentTime(mediaElement()->currentTime() + stepTime, ec);
    464             }
    465             m_seekTimer.stop();
    466             m_seeking = false;
    467             event->setDefaultHandled();
    468         }
    469     }
    470     HTMLInputElement::defaultEventHandler(event);
    471 }
    472 
    473 void MediaControlSeekButtonElement::seekTimerFired(Timer<MediaControlSeekButtonElement>*)
    474 {
    475     ExceptionCode ec;
    476     m_seeking = true;
    477     float seekTime = isForwardButton() ? cSeekTime : -cSeekTime;
    478     mediaElement()->setCurrentTime(mediaElement()->currentTime() + seekTime, ec);
    479 }
    480 
    481 void MediaControlSeekButtonElement::detach()
    482 {
    483     if (m_capturing) {
    484         if (Frame* frame = document()->frame())
    485             frame->eventHandler()->setCapturingMouseEventsNode(0);
    486     }
    487     MediaControlInputElement::detach();
    488 }
    489 
    490 // ----------------------------
    491 
    492 inline MediaControlSeekForwardButtonElement::MediaControlSeekForwardButtonElement(HTMLMediaElement* mediaElement)
    493     : MediaControlSeekButtonElement(mediaElement, MediaSeekForwardButton)
    494 {
    495 }
    496 
    497 PassRefPtr<MediaControlSeekForwardButtonElement> MediaControlSeekForwardButtonElement::create(HTMLMediaElement* mediaElement)
    498 {
    499     RefPtr<MediaControlSeekForwardButtonElement> button = adoptRef(new MediaControlSeekForwardButtonElement(mediaElement));
    500     button->setType("button");
    501     return button.release();
    502 }
    503 
    504 const AtomicString& MediaControlSeekForwardButtonElement::shadowPseudoId() const
    505 {
    506     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-seek-forward-button"));
    507     return id;
    508 }
    509 
    510 // ----------------------------
    511 
    512 inline MediaControlSeekBackButtonElement::MediaControlSeekBackButtonElement(HTMLMediaElement* mediaElement)
    513     : MediaControlSeekButtonElement(mediaElement, MediaSeekBackButton)
    514 {
    515 }
    516 
    517 PassRefPtr<MediaControlSeekBackButtonElement> MediaControlSeekBackButtonElement::create(HTMLMediaElement* mediaElement)
    518 {
    519     RefPtr<MediaControlSeekBackButtonElement> button = adoptRef(new MediaControlSeekBackButtonElement(mediaElement));
    520     button->setType("button");
    521     return button.release();
    522 }
    523 
    524 const AtomicString& MediaControlSeekBackButtonElement::shadowPseudoId() const
    525 {
    526     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-seek-back-button"));
    527     return id;
    528 }
    529 
    530 // ----------------------------
    531 
    532 inline MediaControlRewindButtonElement::MediaControlRewindButtonElement(HTMLMediaElement* element)
    533     : MediaControlInputElement(element, MediaRewindButton)
    534 {
    535 }
    536 
    537 PassRefPtr<MediaControlRewindButtonElement> MediaControlRewindButtonElement::create(HTMLMediaElement* mediaElement)
    538 {
    539     RefPtr<MediaControlRewindButtonElement> button = adoptRef(new MediaControlRewindButtonElement(mediaElement));
    540     button->setType("button");
    541     return button.release();
    542 }
    543 
    544 void MediaControlRewindButtonElement::defaultEventHandler(Event* event)
    545 {
    546     if (event->type() == eventNames().clickEvent) {
    547         mediaElement()->rewind(30);
    548         event->setDefaultHandled();
    549     }
    550     HTMLInputElement::defaultEventHandler(event);
    551 }
    552 
    553 const AtomicString& MediaControlRewindButtonElement::shadowPseudoId() const
    554 {
    555     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-rewind-button"));
    556     return id;
    557 }
    558 
    559 // ----------------------------
    560 
    561 inline MediaControlReturnToRealtimeButtonElement::MediaControlReturnToRealtimeButtonElement(HTMLMediaElement* mediaElement)
    562     : MediaControlInputElement(mediaElement, MediaReturnToRealtimeButton)
    563 {
    564 }
    565 
    566 PassRefPtr<MediaControlReturnToRealtimeButtonElement> MediaControlReturnToRealtimeButtonElement::create(HTMLMediaElement* mediaElement)
    567 {
    568     RefPtr<MediaControlReturnToRealtimeButtonElement> button = adoptRef(new MediaControlReturnToRealtimeButtonElement(mediaElement));
    569     button->setType("button");
    570     button->hide();
    571     return button.release();
    572 }
    573 
    574 void MediaControlReturnToRealtimeButtonElement::defaultEventHandler(Event* event)
    575 {
    576     if (event->type() == eventNames().clickEvent) {
    577         mediaElement()->returnToRealtime();
    578         event->setDefaultHandled();
    579     }
    580     HTMLInputElement::defaultEventHandler(event);
    581 }
    582 
    583 const AtomicString& MediaControlReturnToRealtimeButtonElement::shadowPseudoId() const
    584 {
    585     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-return-to-realtime-button"));
    586     return id;
    587 }
    588 
    589 // ----------------------------
    590 
    591 inline MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement(HTMLMediaElement* mediaElement)
    592     : MediaControlInputElement(mediaElement, MediaShowClosedCaptionsButton)
    593 {
    594 }
    595 
    596 PassRefPtr<MediaControlToggleClosedCaptionsButtonElement> MediaControlToggleClosedCaptionsButtonElement::create(HTMLMediaElement* mediaElement)
    597 {
    598     RefPtr<MediaControlToggleClosedCaptionsButtonElement> button = adoptRef(new MediaControlToggleClosedCaptionsButtonElement(mediaElement));
    599     button->setType("button");
    600     button->hide();
    601     return button.release();
    602 }
    603 
    604 void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event)
    605 {
    606     if (event->type() == eventNames().clickEvent) {
    607         mediaElement()->setClosedCaptionsVisible(!mediaElement()->closedCaptionsVisible());
    608         setChecked(mediaElement()->closedCaptionsVisible());
    609         updateDisplayType();
    610         event->setDefaultHandled();
    611     }
    612 
    613     HTMLInputElement::defaultEventHandler(event);
    614 }
    615 
    616 void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType()
    617 {
    618     setDisplayType(mediaElement()->closedCaptionsVisible() ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton);
    619 }
    620 
    621 const AtomicString& MediaControlToggleClosedCaptionsButtonElement::shadowPseudoId() const
    622 {
    623     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-toggle-closed-captions-button"));
    624     return id;
    625 }
    626 
    627 // ----------------------------
    628 
    629 MediaControlTimelineElement::MediaControlTimelineElement(HTMLMediaElement* mediaElement, MediaControls* controls)
    630     : MediaControlInputElement(mediaElement, MediaSlider)
    631     , m_controls(controls)
    632 {
    633 }
    634 
    635 PassRefPtr<MediaControlTimelineElement> MediaControlTimelineElement::create(HTMLMediaElement* mediaElement, MediaControls* controls)
    636 {
    637     ASSERT(controls);
    638 
    639     RefPtr<MediaControlTimelineElement> timeline = adoptRef(new MediaControlTimelineElement(mediaElement, controls));
    640     timeline->setType("range");
    641     timeline->setAttribute(precisionAttr, "float");
    642     return timeline.release();
    643 }
    644 
    645 void MediaControlTimelineElement::defaultEventHandler(Event* event)
    646 {
    647     // Left button is 0. Rejects mouse events not from left button.
    648     if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button())
    649         return;
    650 
    651     if (!attached())
    652         return;
    653 
    654     if (event->type() == eventNames().mousedownEvent)
    655         mediaElement()->beginScrubbing();
    656 
    657 #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS)
    658     if (event->type() == eventNames().touchstartEvent)
    659         mediaElement()->beginScrubbing();
    660 #endif
    661 
    662     MediaControlInputElement::defaultEventHandler(event);
    663 
    664     if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
    665         return;
    666 
    667 #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS)
    668     if (event->type() == eventNames().touchmoveEvent || event->type() == eventNames().touchcancelEvent)
    669         return;
    670 #endif
    671 
    672     float time = narrowPrecisionToFloat(value().toDouble());
    673     if (time != mediaElement()->currentTime()) {
    674         // FIXME: This is fired 3 times on every click. We should not be doing that <http:/webkit.org/b/58160>.
    675         ExceptionCode ec;
    676         mediaElement()->setCurrentTime(time, ec);
    677     }
    678 
    679     RenderSlider* slider = toRenderSlider(renderer());
    680     if (slider && slider->inDragMode())
    681         m_controls->updateTimeDisplay();
    682 
    683     if (event->type() == eventNames().mouseupEvent)
    684         mediaElement()->endScrubbing();
    685 
    686 #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS)
    687     if (event->type() == eventNames().touchendEvent)
    688         mediaElement()->endScrubbing();
    689 #endif
    690 }
    691 
    692 void MediaControlTimelineElement::setPosition(float currentTime)
    693 {
    694     setValue(String::number(currentTime));
    695 }
    696 
    697 void MediaControlTimelineElement::setDuration(float duration)
    698 {
    699     setAttribute(maxAttr, String::number(isfinite(duration) ? duration : 0));
    700 }
    701 
    702 
    703 const AtomicString& MediaControlTimelineElement::shadowPseudoId() const
    704 {
    705     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-timeline"));
    706     return id;
    707 }
    708 
    709 // ----------------------------
    710 
    711 inline MediaControlVolumeSliderElement::MediaControlVolumeSliderElement(HTMLMediaElement* mediaElement)
    712     : MediaControlInputElement(mediaElement, MediaVolumeSlider)
    713 {
    714 }
    715 
    716 PassRefPtr<MediaControlVolumeSliderElement> MediaControlVolumeSliderElement::create(HTMLMediaElement* mediaElement)
    717 {
    718     RefPtr<MediaControlVolumeSliderElement> slider = adoptRef(new MediaControlVolumeSliderElement(mediaElement));
    719     slider->setType("range");
    720     slider->setAttribute(precisionAttr, "float");
    721     slider->setAttribute(maxAttr, "1");
    722     slider->setAttribute(valueAttr, String::number(mediaElement->volume()));
    723     return slider.release();
    724 }
    725 
    726 void MediaControlVolumeSliderElement::defaultEventHandler(Event* event)
    727 {
    728     // Left button is 0. Rejects mouse events not from left button.
    729     if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button())
    730         return;
    731 
    732     if (!attached())
    733         return;
    734 
    735     MediaControlInputElement::defaultEventHandler(event);
    736 
    737     if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
    738         return;
    739 
    740     float volume = narrowPrecisionToFloat(value().toDouble());
    741     if (volume != mediaElement()->volume()) {
    742         ExceptionCode ec = 0;
    743         mediaElement()->setVolume(volume, ec);
    744         ASSERT(!ec);
    745     }
    746 }
    747 
    748 void MediaControlVolumeSliderElement::setVolume(float volume)
    749 {
    750     if (value().toFloat() != volume)
    751         setValue(String::number(volume));
    752 }
    753 
    754 const AtomicString& MediaControlVolumeSliderElement::shadowPseudoId() const
    755 {
    756     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider"));
    757     return id;
    758 }
    759 
    760 // ----------------------------
    761 
    762 inline MediaControlFullscreenVolumeSliderElement::MediaControlFullscreenVolumeSliderElement(HTMLMediaElement* mediaElement)
    763     : MediaControlVolumeSliderElement(mediaElement)
    764 {
    765 }
    766 
    767 PassRefPtr<MediaControlFullscreenVolumeSliderElement> MediaControlFullscreenVolumeSliderElement::create(HTMLMediaElement* mediaElement)
    768 {
    769     RefPtr<MediaControlFullscreenVolumeSliderElement> slider = adoptRef(new MediaControlFullscreenVolumeSliderElement(mediaElement));
    770     slider->setType("range");
    771     slider->setAttribute(precisionAttr, "float");
    772     slider->setAttribute(maxAttr, "1");
    773     slider->setAttribute(valueAttr, String::number(mediaElement->volume()));
    774     return slider.release();
    775 }
    776 
    777 const AtomicString& MediaControlFullscreenVolumeSliderElement::shadowPseudoId() const
    778 {
    779     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-slider"));
    780     return id;
    781 }
    782 
    783 // ----------------------------
    784 
    785 inline MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(HTMLMediaElement* mediaElement, MediaControls* controls)
    786     : MediaControlInputElement(mediaElement, MediaFullscreenButton)
    787     , m_controls(controls)
    788 {
    789 }
    790 
    791 PassRefPtr<MediaControlFullscreenButtonElement> MediaControlFullscreenButtonElement::create(HTMLMediaElement* mediaElement, MediaControls* controls)
    792 {
    793     ASSERT(controls);
    794 
    795     RefPtr<MediaControlFullscreenButtonElement> button = adoptRef(new MediaControlFullscreenButtonElement(mediaElement, controls));
    796     button->setType("button");
    797     button->hide();
    798     return button.release();
    799 }
    800 
    801 void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event)
    802 {
    803     if (event->type() == eventNames().clickEvent) {
    804 #if ENABLE(FULLSCREEN_API)
    805         // Only use the new full screen API if the fullScreenEnabled setting has
    806         // been explicitly enabled. Otherwise, use the old fullscreen API. This
    807         // allows apps which embed a WebView to retain the existing full screen
    808         // video implementation without requiring them to implement their own full
    809         // screen behavior.
    810         if (document()->settings() && document()->settings()->fullScreenEnabled()) {
    811             if (document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == mediaElement()) {
    812                 document()->webkitCancelFullScreen();
    813                 m_controls->exitedFullscreen();
    814             } else {
    815                 mediaElement()->webkitRequestFullScreen(0);
    816                 m_controls->enteredFullscreen();
    817             }
    818         } else
    819 #endif
    820             mediaElement()->enterFullscreen();
    821         event->setDefaultHandled();
    822     }
    823     HTMLInputElement::defaultEventHandler(event);
    824 }
    825 
    826 const AtomicString& MediaControlFullscreenButtonElement::shadowPseudoId() const
    827 {
    828     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-button"));
    829     return id;
    830 }
    831 
    832 // ----------------------------
    833 
    834 inline MediaControlFullscreenVolumeMinButtonElement::MediaControlFullscreenVolumeMinButtonElement(HTMLMediaElement* mediaElement)
    835     : MediaControlInputElement(mediaElement, MediaUnMuteButton)
    836 {
    837 }
    838 
    839 PassRefPtr<MediaControlFullscreenVolumeMinButtonElement> MediaControlFullscreenVolumeMinButtonElement::create(HTMLMediaElement* mediaElement)
    840 {
    841     RefPtr<MediaControlFullscreenVolumeMinButtonElement> button = adoptRef(new MediaControlFullscreenVolumeMinButtonElement(mediaElement));
    842     button->setType("button");
    843     return button.release();
    844 }
    845 
    846 void MediaControlFullscreenVolumeMinButtonElement::defaultEventHandler(Event* event)
    847 {
    848     if (event->type() == eventNames().clickEvent) {
    849         ExceptionCode code = 0;
    850         mediaElement()->setVolume(0, code);
    851         event->setDefaultHandled();
    852     }
    853     HTMLInputElement::defaultEventHandler(event);
    854 }
    855 
    856 const AtomicString& MediaControlFullscreenVolumeMinButtonElement::shadowPseudoId() const
    857 {
    858     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-min-button"));
    859     return id;
    860 }
    861 
    862 // ----------------------------
    863 
    864 inline MediaControlFullscreenVolumeMaxButtonElement::MediaControlFullscreenVolumeMaxButtonElement(HTMLMediaElement* mediaElement)
    865 : MediaControlInputElement(mediaElement, MediaMuteButton)
    866 {
    867 }
    868 
    869 PassRefPtr<MediaControlFullscreenVolumeMaxButtonElement> MediaControlFullscreenVolumeMaxButtonElement::create(HTMLMediaElement* mediaElement)
    870 {
    871     RefPtr<MediaControlFullscreenVolumeMaxButtonElement> button = adoptRef(new MediaControlFullscreenVolumeMaxButtonElement(mediaElement));
    872     button->setType("button");
    873     return button.release();
    874 }
    875 
    876 void MediaControlFullscreenVolumeMaxButtonElement::defaultEventHandler(Event* event)
    877 {
    878     if (event->type() == eventNames().clickEvent) {
    879         ExceptionCode code = 0;
    880         mediaElement()->setVolume(1, code);
    881         event->setDefaultHandled();
    882     }
    883     HTMLInputElement::defaultEventHandler(event);
    884 }
    885 
    886 const AtomicString& MediaControlFullscreenVolumeMaxButtonElement::shadowPseudoId() const
    887 {
    888     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-max-button"));
    889     return id;
    890 }
    891 
    892 // ----------------------------
    893 
    894 class RenderMediaControlTimeDisplay : public RenderFlexibleBox {
    895 public:
    896     RenderMediaControlTimeDisplay(Node*);
    897 
    898 private:
    899     virtual void layout();
    900 };
    901 
    902 RenderMediaControlTimeDisplay::RenderMediaControlTimeDisplay(Node* node)
    903     : RenderFlexibleBox(node)
    904 {
    905 }
    906 
    907 // We want the timeline slider to be at least 100 pixels wide.
    908 // FIXME: Eliminate hard-coded widths altogether.
    909 static const int minWidthToDisplayTimeDisplays = 45 + 100 + 45;
    910 
    911 void RenderMediaControlTimeDisplay::layout()
    912 {
    913     RenderFlexibleBox::layout();
    914     RenderBox* timelineContainerBox = parentBox();
    915     while (timelineContainerBox && timelineContainerBox->isAnonymous())
    916         timelineContainerBox = timelineContainerBox->parentBox();
    917 
    918     if (timelineContainerBox && timelineContainerBox->width() < minWidthToDisplayTimeDisplays)
    919         setWidth(0);
    920 }
    921 
    922 inline MediaControlTimeDisplayElement::MediaControlTimeDisplayElement(HTMLMediaElement* mediaElement)
    923     : MediaControlElement(mediaElement)
    924     , m_currentValue(0)
    925 {
    926 }
    927 
    928 void MediaControlTimeDisplayElement::setCurrentValue(float time)
    929 {
    930     m_currentValue = time;
    931 }
    932 
    933 RenderObject* MediaControlTimeDisplayElement::createRenderer(RenderArena* arena, RenderStyle*)
    934 {
    935     return new (arena) RenderMediaControlTimeDisplay(this);
    936 }
    937 
    938 // ----------------------------
    939 
    940 PassRefPtr<MediaControlTimeRemainingDisplayElement> MediaControlTimeRemainingDisplayElement::create(HTMLMediaElement* mediaElement)
    941 {
    942     return adoptRef(new MediaControlTimeRemainingDisplayElement(mediaElement));
    943 }
    944 
    945 MediaControlTimeRemainingDisplayElement::MediaControlTimeRemainingDisplayElement(HTMLMediaElement* mediaElement)
    946     : MediaControlTimeDisplayElement(mediaElement)
    947 {
    948 }
    949 
    950 MediaControlElementType MediaControlTimeRemainingDisplayElement::displayType() const
    951 {
    952     return MediaTimeRemainingDisplay;
    953 }
    954 
    955 const AtomicString& MediaControlTimeRemainingDisplayElement::shadowPseudoId() const
    956 {
    957     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-time-remaining-display"));
    958     return id;
    959 }
    960 
    961 // ----------------------------
    962 
    963 PassRefPtr<MediaControlCurrentTimeDisplayElement> MediaControlCurrentTimeDisplayElement::create(HTMLMediaElement* mediaElement)
    964 {
    965     return adoptRef(new MediaControlCurrentTimeDisplayElement(mediaElement));
    966 }
    967 
    968 MediaControlCurrentTimeDisplayElement::MediaControlCurrentTimeDisplayElement(HTMLMediaElement* mediaElement)
    969     : MediaControlTimeDisplayElement(mediaElement)
    970 {
    971 }
    972 
    973 MediaControlElementType MediaControlCurrentTimeDisplayElement::displayType() const
    974 {
    975     return MediaCurrentTimeDisplay;
    976 }
    977 
    978 const AtomicString& MediaControlCurrentTimeDisplayElement::shadowPseudoId() const
    979 {
    980     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-current-time-display"));
    981     return id;
    982 }
    983 
    984 } // namespace WebCore
    985 
    986 #endif // ENABLE(VIDEO)
    987