/* * Copyright (C) 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. * Copyright (C) 2012 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "core/html/shadow/MediaControlElements.h" #include "bindings/v8/ExceptionStatePlaceholder.h" #include "core/dom/EventNames.h" #include "core/dom/FullscreenElementStack.h" #include "core/dom/MouseEvent.h" #include "core/html/DOMTokenList.h" #include "core/html/HTMLVideoElement.h" #include "core/html/shadow/MediaControls.h" #include "core/html/track/TextTrack.h" #include "core/html/track/TextTrackRegionList.h" #include "core/page/EventHandler.h" #include "core/page/Frame.h" #include "core/page/Page.h" #include "core/page/Settings.h" #include "core/rendering/RenderMediaControlElements.h" #include "core/rendering/RenderSlider.h" #include "core/rendering/RenderTheme.h" #include "core/rendering/RenderVideo.h" namespace WebCore { using namespace HTMLNames; static const AtomicString& getMediaControlCurrentTimeDisplayElementShadowPseudoId(); static const AtomicString& getMediaControlTimeRemainingDisplayElementShadowPseudoId(); static const char* textTracksOffAttrValue = "-1"; // This must match HTMLMediaElement::textTracksOffIndex() MediaControlPanelElement::MediaControlPanelElement(Document* document) : MediaControlDivElement(document, MediaControlsPanel) , m_canBeDragged(false) , m_isBeingDragged(false) , m_isDisplayed(false) , m_opaque(true) , m_transitionTimer(this, &MediaControlPanelElement::transitionTimerFired) { } PassRefPtr MediaControlPanelElement::create(Document* document) { return adoptRef(new MediaControlPanelElement(document)); } const AtomicString& MediaControlPanelElement::part() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-panel", AtomicString::ConstructFromLiteral)); return id; } void MediaControlPanelElement::startDrag(const LayoutPoint& eventLocation) { if (!m_canBeDragged) return; if (m_isBeingDragged) return; RenderObject* renderer = this->renderer(); if (!renderer || !renderer->isBox()) return; Frame* frame = document()->frame(); if (!frame) return; m_lastDragEventLocation = eventLocation; frame->eventHandler()->setCapturingMouseEventsNode(this); m_isBeingDragged = true; } void MediaControlPanelElement::continueDrag(const LayoutPoint& eventLocation) { if (!m_isBeingDragged) return; LayoutSize distanceDragged = eventLocation - m_lastDragEventLocation; m_cumulativeDragOffset.move(distanceDragged); m_lastDragEventLocation = eventLocation; setPosition(m_cumulativeDragOffset); } void MediaControlPanelElement::endDrag() { if (!m_isBeingDragged) return; m_isBeingDragged = false; Frame* frame = document()->frame(); if (!frame) return; frame->eventHandler()->setCapturingMouseEventsNode(0); } void MediaControlPanelElement::startTimer() { stopTimer(); // The timer is required to set the property display:'none' on the panel, // such that captions are correctly displayed at the bottom of the video // at the end of the fadeout transition. double duration = document()->page() ? document()->page()->theme()->mediaControlsFadeOutDuration() : 0; m_transitionTimer.startOneShot(duration); } void MediaControlPanelElement::stopTimer() { if (m_transitionTimer.isActive()) m_transitionTimer.stop(); } void MediaControlPanelElement::transitionTimerFired(Timer*) { if (!m_opaque) hide(); stopTimer(); } void MediaControlPanelElement::setPosition(const LayoutPoint& position) { double left = position.x(); double top = position.y(); // Set the left and top to control the panel's position; this depends on it being absolute positioned. // Set the margin to zero since the position passed in will already include the effect of the margin. setInlineStyleProperty(CSSPropertyLeft, left, CSSPrimitiveValue::CSS_PX); setInlineStyleProperty(CSSPropertyTop, top, CSSPrimitiveValue::CSS_PX); setInlineStyleProperty(CSSPropertyMarginLeft, 0.0, CSSPrimitiveValue::CSS_PX); setInlineStyleProperty(CSSPropertyMarginTop, 0.0, CSSPrimitiveValue::CSS_PX); classList()->add("dragged", IGNORE_EXCEPTION); } void MediaControlPanelElement::resetPosition() { removeInlineStyleProperty(CSSPropertyLeft); removeInlineStyleProperty(CSSPropertyTop); removeInlineStyleProperty(CSSPropertyMarginLeft); removeInlineStyleProperty(CSSPropertyMarginTop); classList()->remove("dragged", IGNORE_EXCEPTION); m_cumulativeDragOffset.setX(0); m_cumulativeDragOffset.setY(0); } void MediaControlPanelElement::makeOpaque() { if (m_opaque) return; double duration = document()->page() ? document()->page()->theme()->mediaControlsFadeInDuration() : 0; setInlineStyleProperty(CSSPropertyTransitionProperty, CSSPropertyOpacity); setInlineStyleProperty(CSSPropertyTransitionDuration, duration, CSSPrimitiveValue::CSS_S); setInlineStyleProperty(CSSPropertyOpacity, 1.0, CSSPrimitiveValue::CSS_NUMBER); m_opaque = true; if (m_isDisplayed) show(); } void MediaControlPanelElement::makeTransparent() { if (!m_opaque) return; double duration = document()->page() ? document()->page()->theme()->mediaControlsFadeOutDuration() : 0; setInlineStyleProperty(CSSPropertyTransitionProperty, CSSPropertyOpacity); setInlineStyleProperty(CSSPropertyTransitionDuration, duration, CSSPrimitiveValue::CSS_S); setInlineStyleProperty(CSSPropertyOpacity, 0.0, CSSPrimitiveValue::CSS_NUMBER); m_opaque = false; startTimer(); } void MediaControlPanelElement::defaultEventHandler(Event* event) { MediaControlDivElement::defaultEventHandler(event); if (event->isMouseEvent()) { LayoutPoint location = toMouseEvent(event)->absoluteLocation(); if (event->type() == eventNames().mousedownEvent && event->target() == this) { startDrag(location); event->setDefaultHandled(); } else if (event->type() == eventNames().mousemoveEvent && m_isBeingDragged) continueDrag(location); else if (event->type() == eventNames().mouseupEvent && m_isBeingDragged) { continueDrag(location); endDrag(); event->setDefaultHandled(); } } } void MediaControlPanelElement::setCanBeDragged(bool canBeDragged) { if (m_canBeDragged == canBeDragged) return; m_canBeDragged = canBeDragged; if (!canBeDragged) endDrag(); } void MediaControlPanelElement::setIsDisplayed(bool isDisplayed) { m_isDisplayed = isDisplayed; } // ---------------------------- MediaControlPanelEnclosureElement::MediaControlPanelEnclosureElement(Document* document) // Mapping onto same MediaControlElementType as panel element, since it has similar properties. : MediaControlDivElement(document, MediaControlsPanel) { } PassRefPtr MediaControlPanelEnclosureElement::create(Document* document) { return adoptRef(new MediaControlPanelEnclosureElement(document)); } const AtomicString& MediaControlPanelEnclosureElement::part() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-enclosure", AtomicString::ConstructFromLiteral)); return id; } // ---------------------------- MediaControlOverlayEnclosureElement::MediaControlOverlayEnclosureElement(Document* document) // Mapping onto same MediaControlElementType as panel element, since it has similar properties. : MediaControlDivElement(document, MediaControlsPanel) { } PassRefPtr MediaControlOverlayEnclosureElement::create(Document* document) { return adoptRef(new MediaControlOverlayEnclosureElement(document)); } const AtomicString& MediaControlOverlayEnclosureElement::part() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-overlay-enclosure", AtomicString::ConstructFromLiteral)); return id; } // ---------------------------- MediaControlPanelMuteButtonElement::MediaControlPanelMuteButtonElement(Document* document, MediaControls* controls) : MediaControlMuteButtonElement(document, MediaMuteButton) , m_controls(controls) { } PassRefPtr MediaControlPanelMuteButtonElement::create(Document* document, MediaControls* controls) { ASSERT(controls); RefPtr button = adoptRef(new MediaControlPanelMuteButtonElement(document, controls)); button->ensureUserAgentShadowRoot(); button->setType("button"); return button.release(); } void MediaControlPanelMuteButtonElement::defaultEventHandler(Event* event) { if (event->type() == eventNames().mouseoverEvent) m_controls->showVolumeSlider(); MediaControlMuteButtonElement::defaultEventHandler(event); } const AtomicString& MediaControlPanelMuteButtonElement::part() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-mute-button", AtomicString::ConstructFromLiteral)); return id; } // ---------------------------- MediaControlVolumeSliderMuteButtonElement::MediaControlVolumeSliderMuteButtonElement(Document* document) : MediaControlMuteButtonElement(document, MediaMuteButton) { } PassRefPtr MediaControlVolumeSliderMuteButtonElement::create(Document* document) { RefPtr button = adoptRef(new MediaControlVolumeSliderMuteButtonElement(document)); button->ensureUserAgentShadowRoot(); button->setType("button"); return button.release(); } const AtomicString& MediaControlVolumeSliderMuteButtonElement::part() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider-mute-button", AtomicString::ConstructFromLiteral)); return id; } // ---------------------------- MediaControlPlayButtonElement::MediaControlPlayButtonElement(Document* document) : MediaControlInputElement(document, MediaPlayButton) { } PassRefPtr MediaControlPlayButtonElement::create(Document* document) { RefPtr button = adoptRef(new MediaControlPlayButtonElement(document)); button->ensureUserAgentShadowRoot(); button->setType("button"); return button.release(); } void MediaControlPlayButtonElement::defaultEventHandler(Event* event) { if (event->type() == eventNames().clickEvent) { if (mediaController()->canPlay()) mediaController()->play(); else mediaController()->pause(); updateDisplayType(); event->setDefaultHandled(); } HTMLInputElement::defaultEventHandler(event); } void MediaControlPlayButtonElement::updateDisplayType() { setDisplayType(mediaController()->canPlay() ? MediaPlayButton : MediaPauseButton); } const AtomicString& MediaControlPlayButtonElement::part() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-play-button", AtomicString::ConstructFromLiteral)); return id; } // ---------------------------- MediaControlOverlayPlayButtonElement::MediaControlOverlayPlayButtonElement(Document* document) : MediaControlInputElement(document, MediaOverlayPlayButton) { } PassRefPtr MediaControlOverlayPlayButtonElement::create(Document* document) { RefPtr button = adoptRef(new MediaControlOverlayPlayButtonElement(document)); button->ensureUserAgentShadowRoot(); button->setType("button"); return button.release(); } void MediaControlOverlayPlayButtonElement::defaultEventHandler(Event* event) { if (event->type() == eventNames().clickEvent && mediaController()->canPlay()) { mediaController()->play(); updateDisplayType(); event->setDefaultHandled(); } HTMLInputElement::defaultEventHandler(event); } void MediaControlOverlayPlayButtonElement::updateDisplayType() { if (mediaController()->canPlay()) { show(); } else hide(); } const AtomicString& MediaControlOverlayPlayButtonElement::part() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-overlay-play-button", AtomicString::ConstructFromLiteral)); return id; } // ---------------------------- MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement(Document* document, MediaControls* controls) : MediaControlInputElement(document, MediaShowClosedCaptionsButton) { UNUSED_PARAM(controls); } PassRefPtr MediaControlToggleClosedCaptionsButtonElement::create(Document* document, MediaControls* controls) { ASSERT(controls); RefPtr button = adoptRef(new MediaControlToggleClosedCaptionsButtonElement(document, controls)); button->ensureUserAgentShadowRoot(); button->setType("button"); button->hide(); return button.release(); } void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType() { bool captionsVisible = mediaController()->closedCaptionsVisible(); setDisplayType(captionsVisible ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton); setChecked(captionsVisible); } void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event) { if (event->type() == eventNames().clickEvent) { mediaController()->setClosedCaptionsVisible(!mediaController()->closedCaptionsVisible()); setChecked(mediaController()->closedCaptionsVisible()); updateDisplayType(); event->setDefaultHandled(); } HTMLInputElement::defaultEventHandler(event); } const AtomicString& MediaControlToggleClosedCaptionsButtonElement::part() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-toggle-closed-captions-button", AtomicString::ConstructFromLiteral)); return id; } // ---------------------------- MediaControlTimelineElement::MediaControlTimelineElement(Document* document, MediaControls* controls) : MediaControlInputElement(document, MediaSlider) , m_controls(controls) { } PassRefPtr MediaControlTimelineElement::create(Document* document, MediaControls* controls) { ASSERT(controls); RefPtr timeline = adoptRef(new MediaControlTimelineElement(document, controls)); timeline->ensureUserAgentShadowRoot(); timeline->setType("range"); timeline->setAttribute(precisionAttr, "float"); return timeline.release(); } void MediaControlTimelineElement::defaultEventHandler(Event* event) { // Left button is 0. Rejects mouse events not from left button. if (event->isMouseEvent() && toMouseEvent(event)->button()) return; if (!attached()) return; if (event->type() == eventNames().mousedownEvent) mediaController()->beginScrubbing(); if (event->type() == eventNames().mouseupEvent) mediaController()->endScrubbing(); MediaControlInputElement::defaultEventHandler(event); if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent) return; double time = value().toDouble(); if (event->type() == eventNames().inputEvent && time != mediaController()->currentTime()) mediaController()->setCurrentTime(time, IGNORE_EXCEPTION); RenderSlider* slider = toRenderSlider(renderer()); if (slider && slider->inDragMode()) m_controls->updateCurrentTimeDisplay(); } bool MediaControlTimelineElement::willRespondToMouseClickEvents() { if (!attached()) return false; return true; } void MediaControlTimelineElement::setPosition(double currentTime) { setValue(String::number(currentTime)); } void MediaControlTimelineElement::setDuration(double duration) { setAttribute(maxAttr, String::number(std::isfinite(duration) ? duration : 0)); } const AtomicString& MediaControlTimelineElement::part() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-timeline", AtomicString::ConstructFromLiteral)); return id; } // ---------------------------- MediaControlPanelVolumeSliderElement::MediaControlPanelVolumeSliderElement(Document* document) : MediaControlVolumeSliderElement(document) { } PassRefPtr MediaControlPanelVolumeSliderElement::create(Document* document) { RefPtr slider = adoptRef(new MediaControlPanelVolumeSliderElement(document)); slider->ensureUserAgentShadowRoot(); slider->setType("range"); slider->setAttribute(precisionAttr, "float"); slider->setAttribute(maxAttr, "1"); return slider.release(); } const AtomicString& MediaControlPanelVolumeSliderElement::part() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider", AtomicString::ConstructFromLiteral)); return id; } // ---------------------------- MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(Document* document) : MediaControlInputElement(document, MediaEnterFullscreenButton) { } PassRefPtr MediaControlFullscreenButtonElement::create(Document* document) { RefPtr button = adoptRef(new MediaControlFullscreenButtonElement(document)); button->ensureUserAgentShadowRoot(); button->setType("button"); button->hide(); return button.release(); } void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event) { if (event->type() == eventNames().clickEvent) { // Only use the new full screen API if the fullScreenEnabled setting has // been explicitly enabled. Otherwise, use the old fullscreen API. This // allows apps which embed a WebView to retain the existing full screen // video implementation without requiring them to implement their own full // screen behavior. if (document()->settings() && document()->settings()->fullScreenEnabled()) { if (FullscreenElementStack::isActiveFullScreenElement(toParentMediaElement(this))) FullscreenElementStack::from(document())->webkitCancelFullScreen(); else FullscreenElementStack::from(document())->requestFullScreenForElement(toParentMediaElement(this), 0, FullscreenElementStack::ExemptIFrameAllowFullScreenRequirement); } else mediaController()->enterFullscreen(); event->setDefaultHandled(); } HTMLInputElement::defaultEventHandler(event); } const AtomicString& MediaControlFullscreenButtonElement::part() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-button", AtomicString::ConstructFromLiteral)); return id; } void MediaControlFullscreenButtonElement::setIsFullscreen(bool isFullscreen) { setDisplayType(isFullscreen ? MediaExitFullscreenButton : MediaEnterFullscreenButton); } // ---------------------------- MediaControlTimeRemainingDisplayElement::MediaControlTimeRemainingDisplayElement(Document* document) : MediaControlTimeDisplayElement(document, MediaTimeRemainingDisplay) { } PassRefPtr MediaControlTimeRemainingDisplayElement::create(Document* document) { return adoptRef(new MediaControlTimeRemainingDisplayElement(document)); } static const AtomicString& getMediaControlTimeRemainingDisplayElementShadowPseudoId() { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-time-remaining-display", AtomicString::ConstructFromLiteral)); return id; } const AtomicString& MediaControlTimeRemainingDisplayElement::part() const { return getMediaControlTimeRemainingDisplayElementShadowPseudoId(); } // ---------------------------- MediaControlCurrentTimeDisplayElement::MediaControlCurrentTimeDisplayElement(Document* document) : MediaControlTimeDisplayElement(document, MediaCurrentTimeDisplay) { } PassRefPtr MediaControlCurrentTimeDisplayElement::create(Document* document) { return adoptRef(new MediaControlCurrentTimeDisplayElement(document)); } static const AtomicString& getMediaControlCurrentTimeDisplayElementShadowPseudoId() { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-current-time-display", AtomicString::ConstructFromLiteral)); return id; } const AtomicString& MediaControlCurrentTimeDisplayElement::part() const { return getMediaControlCurrentTimeDisplayElementShadowPseudoId(); } // ---------------------------- MediaControlTextTrackContainerElement::MediaControlTextTrackContainerElement(Document* document) : MediaControlDivElement(document, MediaTextTrackDisplayContainer) , m_fontSize(0) { } PassRefPtr MediaControlTextTrackContainerElement::create(Document* document) { RefPtr element = adoptRef(new MediaControlTextTrackContainerElement(document)); element->hide(); return element.release(); } RenderObject* MediaControlTextTrackContainerElement::createRenderer(RenderStyle*) { return new RenderTextTrackContainerElement(this); } const AtomicString& MediaControlTextTrackContainerElement::textTrackContainerElementShadowPseudoId() { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-text-track-container", AtomicString::ConstructFromLiteral)); return id; } const AtomicString& MediaControlTextTrackContainerElement::part() const { return textTrackContainerElementShadowPseudoId(); } void MediaControlTextTrackContainerElement::updateDisplay() { if (!mediaController()->closedCaptionsVisible()) { removeChildren(); return; } HTMLMediaElement* mediaElement = toParentMediaElement(this); // 1. If the media element is an audio element, or is another playback // mechanism with no rendering area, abort these steps. There is nothing to // render. if (!mediaElement || !mediaElement->isVideo()) return; // 2. Let video be the media element or other playback mechanism. HTMLVideoElement* video = toHTMLVideoElement(mediaElement); // 3. Let output be an empty list of absolutely positioned CSS block boxes. Vector > output; // 4. If the user agent is exposing a user interface for video, add to // output one or more completely transparent positioned CSS block boxes that // cover the same region as the user interface. // 5. If the last time these rules were run, the user agent was not exposing // a user interface for video, but now it is, let reset be true. Otherwise, // let reset be false. // There is nothing to be done explicitly for 4th and 5th steps, as // everything is handled through CSS. The caption box is on top of the // controls box, in a container set with the -webkit-box display property. // 6. Let tracks be the subset of video's list of text tracks that have as // their rules for updating the text track rendering these rules for // updating the display of WebVTT text tracks, and whose text track mode is // showing or showing by default. // 7. Let cues be an empty list of text track cues. // 8. For each track track in tracks, append to cues all the cues from // track's list of cues that have their text track cue active flag set. CueList activeCues = video->currentlyActiveCues(); // 9. If reset is false, then, for each text track cue cue in cues: if cue's // text track cue display state has a set of CSS boxes, then add those boxes // to output, and remove cue from cues. // There is nothing explicitly to be done here, as all the caching occurs // within the TextTrackCue instance itself. If parameters of the cue change, // the display tree is cleared. // 10. For each text track cue cue in cues that has not yet had // corresponding CSS boxes added to output, in text track cue order, run the // following substeps: for (size_t i = 0; i < activeCues.size(); ++i) { TextTrackCue* cue = activeCues[i].data(); ASSERT(cue->isActive()); if (!cue->track() || !cue->track()->isRendered() || !cue->isActive()) continue; RefPtr displayBox = cue->getDisplayTree(m_videoDisplaySize.size()); #if ENABLE(WEBVTT_REGIONS) String regionId = cue->regionId(); TextTrackRegion* region = cue->track()->regions()->getRegionById(regionId); if (!region) { // If cue has an empty text track cue region identifier or there is no // WebVTT region whose region identifier is identical to cue's text // track cue region identifier, run the following substeps: #endif if (displayBox->hasChildNodes() && !contains(displayBox.get())) { // Note: the display tree of a cue is removed when the active flag of the cue is unset. appendChild(displayBox, ASSERT_NO_EXCEPTION, AttachNow); } #if ENABLE(WEBVTT_REGIONS) } else { // Let region be the WebVTT region whose region identifier // matches the text track cue region identifier of cue. RefPtr regionNode = region->getDisplayTree(); // Append the region to the viewport, if it was not already. if (!contains(regionNode.get())) appendChild(region->getDisplayTree()); region->appendTextTrackCueBox(displayBox); } #endif } // 11. Return output. if (hasChildNodes()) show(); else hide(); } void MediaControlTextTrackContainerElement::updateSizes(bool forceUpdate) { HTMLMediaElement* mediaElement = toParentMediaElement(this); if (!mediaElement) return; if (!document()->page()) return; IntRect videoBox; if (!mediaElement->renderer() || !mediaElement->renderer()->isVideo()) return; videoBox = toRenderVideo(mediaElement->renderer())->videoBox(); if (!forceUpdate && m_videoDisplaySize == videoBox) return; m_videoDisplaySize = videoBox; float smallestDimension = std::min(m_videoDisplaySize.size().height(), m_videoDisplaySize.size().width()); float fontSize = smallestDimension * 0.05f; if (fontSize != m_fontSize) { m_fontSize = fontSize; setInlineStyleProperty(CSSPropertyFontSize, fontSize, CSSPrimitiveValue::CSS_PX); } CueList activeCues = mediaElement->currentlyActiveCues(); for (size_t i = 0; i < activeCues.size(); ++i) { TextTrackCue* cue = activeCues[i].data(); cue->videoSizeDidChange(m_videoDisplaySize.size()); } } // ---------------------------- } // namespace WebCore