Home | History | Annotate | Download | only in shadow
      1 /*
      2  * Copyright (C) 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
      3  * Copyright (C) 2012 Google Inc. All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *
      9  * 1.  Redistributions of source code must retain the above copyright
     10  *     notice, this list of conditions and the following disclaimer.
     11  * 2.  Redistributions in binary form must reproduce the above copyright
     12  *     notice, this list of conditions and the following disclaimer in the
     13  *     documentation and/or other materials provided with the distribution.
     14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     15  *     its contributors may be used to endorse or promote products derived
     16  *     from this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 #include "config.h"
     31 #include "core/html/shadow/MediaControlElements.h"
     32 
     33 #include "RuntimeEnabledFeatures.h"
     34 #include "bindings/v8/ExceptionStatePlaceholder.h"
     35 #include "core/dom/DOMTokenList.h"
     36 #include "core/dom/FullscreenElementStack.h"
     37 #include "core/dom/shadow/ShadowRoot.h"
     38 #include "core/events/MouseEvent.h"
     39 #include "core/events/ThreadLocalEventNames.h"
     40 #include "core/html/HTMLVideoElement.h"
     41 #include "core/html/shadow/MediaControls.h"
     42 #include "core/html/track/TextTrack.h"
     43 #include "core/html/track/vtt/VTTRegionList.h"
     44 #include "core/page/EventHandler.h"
     45 #include "core/frame/Frame.h"
     46 #include "core/frame/Settings.h"
     47 #include "core/rendering/RenderMediaControlElements.h"
     48 #include "core/rendering/RenderSlider.h"
     49 #include "core/rendering/RenderTheme.h"
     50 #include "core/rendering/RenderVideo.h"
     51 
     52 namespace WebCore {
     53 
     54 using namespace HTMLNames;
     55 
     56 static const AtomicString& getMediaControlCurrentTimeDisplayElementShadowPseudoId();
     57 static const AtomicString& getMediaControlTimeRemainingDisplayElementShadowPseudoId();
     58 
     59 static const double fadeInDuration = 0.1;
     60 static const double fadeOutDuration = 0.3;
     61 
     62 MediaControlPanelElement::MediaControlPanelElement(Document& document)
     63     : MediaControlDivElement(document, MediaControlsPanel)
     64     , m_canBeDragged(false)
     65     , m_isBeingDragged(false)
     66     , m_isDisplayed(false)
     67     , m_opaque(true)
     68     , m_transitionTimer(this, &MediaControlPanelElement::transitionTimerFired)
     69 {
     70 }
     71 
     72 PassRefPtr<MediaControlPanelElement> MediaControlPanelElement::create(Document& document)
     73 {
     74     return adoptRef(new MediaControlPanelElement(document));
     75 }
     76 
     77 const AtomicString& MediaControlPanelElement::pseudo() const
     78 {
     79     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-panel", AtomicString::ConstructFromLiteral));
     80     return id;
     81 }
     82 
     83 void MediaControlPanelElement::startDrag(const LayoutPoint& eventLocation)
     84 {
     85     if (!m_canBeDragged)
     86         return;
     87 
     88     if (m_isBeingDragged)
     89         return;
     90 
     91     RenderObject* renderer = this->renderer();
     92     if (!renderer || !renderer->isBox())
     93         return;
     94 
     95     Frame* frame = document().frame();
     96     if (!frame)
     97         return;
     98 
     99     m_lastDragEventLocation = eventLocation;
    100 
    101     frame->eventHandler().setCapturingMouseEventsNode(this);
    102 
    103     m_isBeingDragged = true;
    104 }
    105 
    106 void MediaControlPanelElement::continueDrag(const LayoutPoint& eventLocation)
    107 {
    108     if (!m_isBeingDragged)
    109         return;
    110 
    111     LayoutSize distanceDragged = eventLocation - m_lastDragEventLocation;
    112     m_cumulativeDragOffset.move(distanceDragged);
    113     m_lastDragEventLocation = eventLocation;
    114     setPosition(m_cumulativeDragOffset);
    115 }
    116 
    117 void MediaControlPanelElement::endDrag()
    118 {
    119     if (!m_isBeingDragged)
    120         return;
    121 
    122     m_isBeingDragged = false;
    123 
    124     Frame* frame = document().frame();
    125     if (!frame)
    126         return;
    127 
    128     frame->eventHandler().setCapturingMouseEventsNode(0);
    129 }
    130 
    131 void MediaControlPanelElement::startTimer()
    132 {
    133     stopTimer();
    134 
    135     // The timer is required to set the property display:'none' on the panel,
    136     // such that captions are correctly displayed at the bottom of the video
    137     // at the end of the fadeout transition.
    138     // FIXME: Racing a transition with a setTimeout like this is wrong.
    139     m_transitionTimer.startOneShot(fadeOutDuration);
    140 }
    141 
    142 void MediaControlPanelElement::stopTimer()
    143 {
    144     if (m_transitionTimer.isActive())
    145         m_transitionTimer.stop();
    146 }
    147 
    148 void MediaControlPanelElement::transitionTimerFired(Timer<MediaControlPanelElement>*)
    149 {
    150     if (!m_opaque)
    151         hide();
    152 
    153     stopTimer();
    154 }
    155 
    156 void MediaControlPanelElement::setPosition(const LayoutPoint& position)
    157 {
    158     double left = position.x();
    159     double top = position.y();
    160 
    161     // Set the left and top to control the panel's position; this depends on it being absolute positioned.
    162     // Set the margin to zero since the position passed in will already include the effect of the margin.
    163     setInlineStyleProperty(CSSPropertyLeft, left, CSSPrimitiveValue::CSS_PX);
    164     setInlineStyleProperty(CSSPropertyTop, top, CSSPrimitiveValue::CSS_PX);
    165     setInlineStyleProperty(CSSPropertyMarginLeft, 0.0, CSSPrimitiveValue::CSS_PX);
    166     setInlineStyleProperty(CSSPropertyMarginTop, 0.0, CSSPrimitiveValue::CSS_PX);
    167 
    168     classList()->add("dragged", IGNORE_EXCEPTION);
    169 }
    170 
    171 void MediaControlPanelElement::resetPosition()
    172 {
    173     removeInlineStyleProperty(CSSPropertyLeft);
    174     removeInlineStyleProperty(CSSPropertyTop);
    175     removeInlineStyleProperty(CSSPropertyMarginLeft);
    176     removeInlineStyleProperty(CSSPropertyMarginTop);
    177 
    178     classList()->remove("dragged", IGNORE_EXCEPTION);
    179 
    180     m_cumulativeDragOffset.setX(0);
    181     m_cumulativeDragOffset.setY(0);
    182 }
    183 
    184 void MediaControlPanelElement::makeOpaque()
    185 {
    186     if (m_opaque)
    187         return;
    188 
    189     setInlineStyleProperty(CSSPropertyTransitionProperty, CSSPropertyOpacity);
    190     setInlineStyleProperty(CSSPropertyTransitionDuration, fadeInDuration, CSSPrimitiveValue::CSS_S);
    191     setInlineStyleProperty(CSSPropertyOpacity, 1.0, CSSPrimitiveValue::CSS_NUMBER);
    192 
    193     m_opaque = true;
    194 
    195     if (m_isDisplayed)
    196         show();
    197 }
    198 
    199 void MediaControlPanelElement::makeTransparent()
    200 {
    201     if (!m_opaque)
    202         return;
    203 
    204     setInlineStyleProperty(CSSPropertyTransitionProperty, CSSPropertyOpacity);
    205     setInlineStyleProperty(CSSPropertyTransitionDuration, fadeOutDuration, CSSPrimitiveValue::CSS_S);
    206     setInlineStyleProperty(CSSPropertyOpacity, 0.0, CSSPrimitiveValue::CSS_NUMBER);
    207 
    208     m_opaque = false;
    209     startTimer();
    210 }
    211 
    212 void MediaControlPanelElement::defaultEventHandler(Event* event)
    213 {
    214     MediaControlDivElement::defaultEventHandler(event);
    215 
    216     if (event->isMouseEvent()) {
    217         LayoutPoint location = toMouseEvent(event)->absoluteLocation();
    218         if (event->type() == EventTypeNames::mousedown && event->target() == this) {
    219             startDrag(location);
    220             event->setDefaultHandled();
    221         } else if (event->type() == EventTypeNames::mousemove && m_isBeingDragged)
    222             continueDrag(location);
    223         else if (event->type() == EventTypeNames::mouseup && m_isBeingDragged) {
    224             continueDrag(location);
    225             endDrag();
    226             event->setDefaultHandled();
    227         }
    228     }
    229 }
    230 
    231 void MediaControlPanelElement::setCanBeDragged(bool canBeDragged)
    232 {
    233     if (m_canBeDragged == canBeDragged)
    234         return;
    235 
    236     m_canBeDragged = canBeDragged;
    237 
    238     if (!canBeDragged)
    239         endDrag();
    240 }
    241 
    242 void MediaControlPanelElement::setIsDisplayed(bool isDisplayed)
    243 {
    244     m_isDisplayed = isDisplayed;
    245 }
    246 
    247 // ----------------------------
    248 
    249 MediaControlPanelEnclosureElement::MediaControlPanelEnclosureElement(Document& document)
    250     // Mapping onto same MediaControlElementType as panel element, since it has similar properties.
    251     : MediaControlDivElement(document, MediaControlsPanel)
    252 {
    253 }
    254 
    255 PassRefPtr<MediaControlPanelEnclosureElement> MediaControlPanelEnclosureElement::create(Document& document)
    256 {
    257     return adoptRef(new MediaControlPanelEnclosureElement(document));
    258 }
    259 
    260 const AtomicString& MediaControlPanelEnclosureElement::pseudo() const
    261 {
    262     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-enclosure", AtomicString::ConstructFromLiteral));
    263     return id;
    264 }
    265 
    266 // ----------------------------
    267 
    268 MediaControlOverlayEnclosureElement::MediaControlOverlayEnclosureElement(Document& document)
    269     // Mapping onto same MediaControlElementType as panel element, since it has similar properties.
    270     : MediaControlDivElement(document, MediaControlsPanel)
    271 {
    272 }
    273 
    274 PassRefPtr<MediaControlOverlayEnclosureElement> MediaControlOverlayEnclosureElement::create(Document& document)
    275 {
    276     return adoptRef(new MediaControlOverlayEnclosureElement(document));
    277 }
    278 
    279 const AtomicString& MediaControlOverlayEnclosureElement::pseudo() const
    280 {
    281     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-overlay-enclosure", AtomicString::ConstructFromLiteral));
    282     return id;
    283 }
    284 
    285 // ----------------------------
    286 
    287 MediaControlPanelMuteButtonElement::MediaControlPanelMuteButtonElement(Document& document, MediaControls* controls)
    288     : MediaControlMuteButtonElement(document, MediaMuteButton)
    289     , m_controls(controls)
    290 {
    291 }
    292 
    293 PassRefPtr<MediaControlPanelMuteButtonElement> MediaControlPanelMuteButtonElement::create(Document& document, MediaControls* controls)
    294 {
    295     ASSERT(controls);
    296 
    297     RefPtr<MediaControlPanelMuteButtonElement> button = adoptRef(new MediaControlPanelMuteButtonElement(document, controls));
    298     button->ensureUserAgentShadowRoot();
    299     button->setType("button");
    300     return button.release();
    301 }
    302 
    303 void MediaControlPanelMuteButtonElement::defaultEventHandler(Event* event)
    304 {
    305     if (event->type() == EventTypeNames::mouseover)
    306         m_controls->showVolumeSlider();
    307 
    308     MediaControlMuteButtonElement::defaultEventHandler(event);
    309 }
    310 
    311 const AtomicString& MediaControlPanelMuteButtonElement::pseudo() const
    312 {
    313     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-mute-button", AtomicString::ConstructFromLiteral));
    314     return id;
    315 }
    316 
    317 // ----------------------------
    318 
    319 MediaControlVolumeSliderMuteButtonElement::MediaControlVolumeSliderMuteButtonElement(Document& document)
    320     : MediaControlMuteButtonElement(document, MediaMuteButton)
    321 {
    322 }
    323 
    324 PassRefPtr<MediaControlVolumeSliderMuteButtonElement> MediaControlVolumeSliderMuteButtonElement::create(Document& document)
    325 {
    326     RefPtr<MediaControlVolumeSliderMuteButtonElement> button = adoptRef(new MediaControlVolumeSliderMuteButtonElement(document));
    327     button->ensureUserAgentShadowRoot();
    328     button->setType("button");
    329     return button.release();
    330 }
    331 
    332 const AtomicString& MediaControlVolumeSliderMuteButtonElement::pseudo() const
    333 {
    334     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider-mute-button", AtomicString::ConstructFromLiteral));
    335     return id;
    336 }
    337 
    338 // ----------------------------
    339 
    340 MediaControlPlayButtonElement::MediaControlPlayButtonElement(Document& document)
    341     : MediaControlInputElement(document, MediaPlayButton)
    342 {
    343 }
    344 
    345 PassRefPtr<MediaControlPlayButtonElement> MediaControlPlayButtonElement::create(Document& document)
    346 {
    347     RefPtr<MediaControlPlayButtonElement> button = adoptRef(new MediaControlPlayButtonElement(document));
    348     button->ensureUserAgentShadowRoot();
    349     button->setType("button");
    350     return button.release();
    351 }
    352 
    353 void MediaControlPlayButtonElement::defaultEventHandler(Event* event)
    354 {
    355     if (event->type() == EventTypeNames::click) {
    356         if (mediaController()->canPlay())
    357             mediaController()->play();
    358         else
    359             mediaController()->pause();
    360         updateDisplayType();
    361         event->setDefaultHandled();
    362     }
    363     HTMLInputElement::defaultEventHandler(event);
    364 }
    365 
    366 void MediaControlPlayButtonElement::updateDisplayType()
    367 {
    368     setDisplayType(mediaController()->canPlay() ? MediaPlayButton : MediaPauseButton);
    369 }
    370 
    371 const AtomicString& MediaControlPlayButtonElement::pseudo() const
    372 {
    373     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-play-button", AtomicString::ConstructFromLiteral));
    374     return id;
    375 }
    376 
    377 // ----------------------------
    378 
    379 MediaControlOverlayPlayButtonElement::MediaControlOverlayPlayButtonElement(Document& document)
    380     : MediaControlInputElement(document, MediaOverlayPlayButton)
    381 {
    382 }
    383 
    384 PassRefPtr<MediaControlOverlayPlayButtonElement> MediaControlOverlayPlayButtonElement::create(Document& document)
    385 {
    386     RefPtr<MediaControlOverlayPlayButtonElement> button = adoptRef(new MediaControlOverlayPlayButtonElement(document));
    387     button->ensureUserAgentShadowRoot();
    388     button->setType("button");
    389     return button.release();
    390 }
    391 
    392 void MediaControlOverlayPlayButtonElement::defaultEventHandler(Event* event)
    393 {
    394     if (event->type() == EventTypeNames::click && mediaController()->canPlay()) {
    395         mediaController()->play();
    396         updateDisplayType();
    397         event->setDefaultHandled();
    398     }
    399     HTMLInputElement::defaultEventHandler(event);
    400 }
    401 
    402 void MediaControlOverlayPlayButtonElement::updateDisplayType()
    403 {
    404     if (mediaController()->canPlay()) {
    405         show();
    406     } else
    407         hide();
    408 }
    409 
    410 const AtomicString& MediaControlOverlayPlayButtonElement::pseudo() const
    411 {
    412     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-overlay-play-button", AtomicString::ConstructFromLiteral));
    413     return id;
    414 }
    415 
    416 
    417 // ----------------------------
    418 
    419 MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement(Document& document, MediaControls*)
    420     : MediaControlInputElement(document, MediaShowClosedCaptionsButton)
    421 {
    422 }
    423 
    424 PassRefPtr<MediaControlToggleClosedCaptionsButtonElement> MediaControlToggleClosedCaptionsButtonElement::create(Document& document, MediaControls* controls)
    425 {
    426     ASSERT(controls);
    427 
    428     RefPtr<MediaControlToggleClosedCaptionsButtonElement> button = adoptRef(new MediaControlToggleClosedCaptionsButtonElement(document, controls));
    429     button->ensureUserAgentShadowRoot();
    430     button->setType("button");
    431     button->hide();
    432     return button.release();
    433 }
    434 
    435 void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType()
    436 {
    437     bool captionsVisible = mediaController()->closedCaptionsVisible();
    438     setDisplayType(captionsVisible ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton);
    439     setChecked(captionsVisible);
    440 }
    441 
    442 void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event)
    443 {
    444     if (event->type() == EventTypeNames::click) {
    445         mediaController()->setClosedCaptionsVisible(!mediaController()->closedCaptionsVisible());
    446         setChecked(mediaController()->closedCaptionsVisible());
    447         updateDisplayType();
    448         event->setDefaultHandled();
    449     }
    450 
    451     HTMLInputElement::defaultEventHandler(event);
    452 }
    453 
    454 const AtomicString& MediaControlToggleClosedCaptionsButtonElement::pseudo() const
    455 {
    456     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-toggle-closed-captions-button", AtomicString::ConstructFromLiteral));
    457     return id;
    458 }
    459 
    460 // ----------------------------
    461 
    462 MediaControlTimelineElement::MediaControlTimelineElement(Document& document, MediaControls* controls)
    463     : MediaControlInputElement(document, MediaSlider)
    464     , m_controls(controls)
    465 {
    466 }
    467 
    468 PassRefPtr<MediaControlTimelineElement> MediaControlTimelineElement::create(Document& document, MediaControls* controls)
    469 {
    470     ASSERT(controls);
    471 
    472     RefPtr<MediaControlTimelineElement> timeline = adoptRef(new MediaControlTimelineElement(document, controls));
    473     timeline->ensureUserAgentShadowRoot();
    474     timeline->setType("range");
    475     timeline->setAttribute(stepAttr, "any");
    476     return timeline.release();
    477 }
    478 
    479 void MediaControlTimelineElement::defaultEventHandler(Event* event)
    480 {
    481     // Left button is 0. Rejects mouse events not from left button.
    482     if (event->isMouseEvent() && toMouseEvent(event)->button())
    483         return;
    484 
    485     if (!inDocument() || !document().isActive())
    486         return;
    487 
    488     if (event->type() == EventTypeNames::mousedown)
    489         mediaController()->beginScrubbing();
    490 
    491     if (event->type() == EventTypeNames::mouseup)
    492         mediaController()->endScrubbing();
    493 
    494     MediaControlInputElement::defaultEventHandler(event);
    495 
    496     if (event->type() == EventTypeNames::mouseover || event->type() == EventTypeNames::mouseout || event->type() == EventTypeNames::mousemove)
    497         return;
    498 
    499     double time = value().toDouble();
    500     if (event->type() == EventTypeNames::input && time != mediaController()->currentTime())
    501         mediaController()->setCurrentTime(time, IGNORE_EXCEPTION);
    502 
    503     RenderSlider* slider = toRenderSlider(renderer());
    504     if (slider && slider->inDragMode())
    505         m_controls->updateCurrentTimeDisplay();
    506 }
    507 
    508 bool MediaControlTimelineElement::willRespondToMouseClickEvents()
    509 {
    510     return inDocument() && document().isActive();
    511 }
    512 
    513 void MediaControlTimelineElement::setPosition(double currentTime)
    514 {
    515     setValue(String::number(currentTime));
    516 }
    517 
    518 void MediaControlTimelineElement::setDuration(double duration)
    519 {
    520     setFloatingPointAttribute(maxAttr, std::isfinite(duration) ? duration : 0);
    521 }
    522 
    523 
    524 const AtomicString& MediaControlTimelineElement::pseudo() const
    525 {
    526     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-timeline", AtomicString::ConstructFromLiteral));
    527     return id;
    528 }
    529 
    530 // ----------------------------
    531 
    532 MediaControlPanelVolumeSliderElement::MediaControlPanelVolumeSliderElement(Document& document)
    533     : MediaControlVolumeSliderElement(document)
    534 {
    535 }
    536 
    537 PassRefPtr<MediaControlPanelVolumeSliderElement> MediaControlPanelVolumeSliderElement::create(Document& document)
    538 {
    539     RefPtr<MediaControlPanelVolumeSliderElement> slider = adoptRef(new MediaControlPanelVolumeSliderElement(document));
    540     slider->ensureUserAgentShadowRoot();
    541     slider->setType("range");
    542     slider->setAttribute(stepAttr, "any");
    543     slider->setAttribute(maxAttr, "1");
    544     return slider.release();
    545 }
    546 
    547 const AtomicString& MediaControlPanelVolumeSliderElement::pseudo() const
    548 {
    549     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider", AtomicString::ConstructFromLiteral));
    550     return id;
    551 }
    552 
    553 // ----------------------------
    554 
    555 MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(Document& document)
    556     : MediaControlInputElement(document, MediaEnterFullscreenButton)
    557 {
    558 }
    559 
    560 PassRefPtr<MediaControlFullscreenButtonElement> MediaControlFullscreenButtonElement::create(Document& document)
    561 {
    562     RefPtr<MediaControlFullscreenButtonElement> button = adoptRef(new MediaControlFullscreenButtonElement(document));
    563     button->ensureUserAgentShadowRoot();
    564     button->setType("button");
    565     button->hide();
    566     return button.release();
    567 }
    568 
    569 void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event)
    570 {
    571     if (event->type() == EventTypeNames::click) {
    572         // Only use the new full screen API if the fullScreenEnabled setting has
    573         // been explicitly enabled. Otherwise, use the old fullscreen API. This
    574         // allows apps which embed a WebView to retain the existing full screen
    575         // video implementation without requiring them to implement their own full
    576         // screen behavior.
    577         if (document().settings() && document().settings()->fullScreenEnabled()) {
    578             if (FullscreenElementStack::isActiveFullScreenElement(toParentMediaElement(this)))
    579                 FullscreenElementStack::from(&document())->webkitCancelFullScreen();
    580             else
    581                 FullscreenElementStack::from(&document())->requestFullScreenForElement(toParentMediaElement(this), 0, FullscreenElementStack::ExemptIFrameAllowFullScreenRequirement);
    582         } else
    583             mediaController()->enterFullscreen();
    584         event->setDefaultHandled();
    585     }
    586     HTMLInputElement::defaultEventHandler(event);
    587 }
    588 
    589 const AtomicString& MediaControlFullscreenButtonElement::pseudo() const
    590 {
    591     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-button", AtomicString::ConstructFromLiteral));
    592     return id;
    593 }
    594 
    595 void MediaControlFullscreenButtonElement::setIsFullscreen(bool isFullscreen)
    596 {
    597     setDisplayType(isFullscreen ? MediaExitFullscreenButton : MediaEnterFullscreenButton);
    598 }
    599 
    600 // ----------------------------
    601 
    602 MediaControlTimeRemainingDisplayElement::MediaControlTimeRemainingDisplayElement(Document& document)
    603     : MediaControlTimeDisplayElement(document, MediaTimeRemainingDisplay)
    604 {
    605 }
    606 
    607 PassRefPtr<MediaControlTimeRemainingDisplayElement> MediaControlTimeRemainingDisplayElement::create(Document& document)
    608 {
    609     return adoptRef(new MediaControlTimeRemainingDisplayElement(document));
    610 }
    611 
    612 static const AtomicString& getMediaControlTimeRemainingDisplayElementShadowPseudoId()
    613 {
    614     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-time-remaining-display", AtomicString::ConstructFromLiteral));
    615     return id;
    616 }
    617 
    618 const AtomicString& MediaControlTimeRemainingDisplayElement::pseudo() const
    619 {
    620     return getMediaControlTimeRemainingDisplayElementShadowPseudoId();
    621 }
    622 
    623 // ----------------------------
    624 
    625 MediaControlCurrentTimeDisplayElement::MediaControlCurrentTimeDisplayElement(Document& document)
    626     : MediaControlTimeDisplayElement(document, MediaCurrentTimeDisplay)
    627 {
    628 }
    629 
    630 PassRefPtr<MediaControlCurrentTimeDisplayElement> MediaControlCurrentTimeDisplayElement::create(Document& document)
    631 {
    632     return adoptRef(new MediaControlCurrentTimeDisplayElement(document));
    633 }
    634 
    635 static const AtomicString& getMediaControlCurrentTimeDisplayElementShadowPseudoId()
    636 {
    637     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-current-time-display", AtomicString::ConstructFromLiteral));
    638     return id;
    639 }
    640 
    641 const AtomicString& MediaControlCurrentTimeDisplayElement::pseudo() const
    642 {
    643     return getMediaControlCurrentTimeDisplayElementShadowPseudoId();
    644 }
    645 
    646 // ----------------------------
    647 
    648 MediaControlTextTrackContainerElement::MediaControlTextTrackContainerElement(Document& document)
    649     : MediaControlDivElement(document, MediaTextTrackDisplayContainer)
    650     , m_fontSize(0)
    651 {
    652 }
    653 
    654 PassRefPtr<MediaControlTextTrackContainerElement> MediaControlTextTrackContainerElement::create(Document& document)
    655 {
    656     RefPtr<MediaControlTextTrackContainerElement> element = adoptRef(new MediaControlTextTrackContainerElement(document));
    657     element->hide();
    658     return element.release();
    659 }
    660 
    661 RenderObject* MediaControlTextTrackContainerElement::createRenderer(RenderStyle*)
    662 {
    663     return new RenderTextTrackContainerElement(this);
    664 }
    665 
    666 const AtomicString& MediaControlTextTrackContainerElement::textTrackContainerElementShadowPseudoId()
    667 {
    668     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-text-track-container", AtomicString::ConstructFromLiteral));
    669     return id;
    670 }
    671 
    672 const AtomicString& MediaControlTextTrackContainerElement::pseudo() const
    673 {
    674     return textTrackContainerElementShadowPseudoId();
    675 }
    676 
    677 void MediaControlTextTrackContainerElement::updateDisplay()
    678 {
    679     if (!mediaController()->closedCaptionsVisible()) {
    680         removeChildren();
    681         return;
    682     }
    683 
    684     HTMLMediaElement* mediaElement = toParentMediaElement(this);
    685     // 1. If the media element is an audio element, or is another playback
    686     // mechanism with no rendering area, abort these steps. There is nothing to
    687     // render.
    688     if (!mediaElement || !mediaElement->isVideo())
    689         return;
    690 
    691     // 2. Let video be the media element or other playback mechanism.
    692     HTMLVideoElement* video = toHTMLVideoElement(mediaElement);
    693 
    694     // 3. Let output be an empty list of absolutely positioned CSS block boxes.
    695     Vector<RefPtr<HTMLDivElement> > output;
    696 
    697     // 4. If the user agent is exposing a user interface for video, add to
    698     // output one or more completely transparent positioned CSS block boxes that
    699     // cover the same region as the user interface.
    700 
    701     // 5. If the last time these rules were run, the user agent was not exposing
    702     // a user interface for video, but now it is, let reset be true. Otherwise,
    703     // let reset be false.
    704 
    705     // There is nothing to be done explicitly for 4th and 5th steps, as
    706     // everything is handled through CSS. The caption box is on top of the
    707     // controls box, in a container set with the -webkit-box display property.
    708 
    709     // 6. Let tracks be the subset of video's list of text tracks that have as
    710     // their rules for updating the text track rendering these rules for
    711     // updating the display of WebVTT text tracks, and whose text track mode is
    712     // showing or showing by default.
    713     // 7. Let cues be an empty list of text track cues.
    714     // 8. For each track track in tracks, append to cues all the cues from
    715     // track's list of cues that have their text track cue active flag set.
    716     CueList activeCues = video->currentlyActiveCues();
    717 
    718     // 9. If reset is false, then, for each text track cue cue in cues: if cue's
    719     // text track cue display state has a set of CSS boxes, then add those boxes
    720     // to output, and remove cue from cues.
    721 
    722     // There is nothing explicitly to be done here, as all the caching occurs
    723     // within the TextTrackCue instance itself. If parameters of the cue change,
    724     // the display tree is cleared.
    725 
    726     // 10. For each text track cue cue in cues that has not yet had
    727     // corresponding CSS boxes added to output, in text track cue order, run the
    728     // following substeps:
    729     for (size_t i = 0; i < activeCues.size(); ++i) {
    730         TextTrackCue* cue = activeCues[i].data();
    731 
    732         ASSERT(cue->isActive());
    733         if (!cue->track() || !cue->track()->isRendered() || !cue->isActive())
    734             continue;
    735 
    736         cue->updateDisplay(m_videoDisplaySize.size(), *this);
    737     }
    738 
    739     // 11. Return output.
    740     if (hasChildNodes())
    741         show();
    742     else
    743         hide();
    744 }
    745 
    746 void MediaControlTextTrackContainerElement::updateSizes(bool forceUpdate)
    747 {
    748     HTMLMediaElement* mediaElement = toParentMediaElement(this);
    749     if (!mediaElement)
    750         return;
    751 
    752     if (!document().isActive())
    753         return;
    754 
    755     IntRect videoBox;
    756 
    757     if (!mediaElement->renderer() || !mediaElement->renderer()->isVideo())
    758         return;
    759     videoBox = toRenderVideo(mediaElement->renderer())->videoBox();
    760 
    761     if (!forceUpdate && m_videoDisplaySize == videoBox)
    762         return;
    763     m_videoDisplaySize = videoBox;
    764 
    765     float smallestDimension = std::min(m_videoDisplaySize.size().height(), m_videoDisplaySize.size().width());
    766 
    767     float fontSize = smallestDimension * 0.05f;
    768     if (fontSize != m_fontSize) {
    769         m_fontSize = fontSize;
    770         setInlineStyleProperty(CSSPropertyFontSize, fontSize, CSSPrimitiveValue::CSS_PX);
    771     }
    772 }
    773 
    774 // ----------------------------
    775 
    776 } // namespace WebCore
    777