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