/* * Copyright (C) 2008, 2009, 2010 Apple 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" #if ENABLE(VIDEO) #include "MediaControlElements.h" #include "CSSStyleSelector.h" #include "EventNames.h" #include "FloatConversion.h" #include "Frame.h" #include "HTMLNames.h" #include "LocalizedStrings.h" #include "MediaControls.h" #include "MouseEvent.h" #include "Page.h" #include "RenderFlexibleBox.h" #include "RenderMedia.h" #include "RenderSlider.h" #include "RenderTheme.h" #include "RenderView.h" #include "Settings.h" namespace WebCore { using namespace HTMLNames; HTMLMediaElement* toParentMediaElement(RenderObject* o) { Node* node = o->node(); Node* mediaNode = node ? node->shadowAncestorNode() : 0; if (!mediaNode || (!mediaNode->hasTagName(HTMLNames::videoTag) && !mediaNode->hasTagName(HTMLNames::audioTag))) return 0; return static_cast<HTMLMediaElement*>(mediaNode); } // FIXME: These constants may need to be tweaked to better match the seeking in the QuickTime plug-in. static const float cSeekRepeatDelay = 0.1f; static const float cStepTime = 0.07f; static const float cSeekTime = 0.2f; // ---------------------------- MediaControlElement::MediaControlElement(HTMLMediaElement* mediaElement) : HTMLDivElement(divTag, mediaElement->document()) , m_mediaElement(mediaElement) { } static const String& displayString() { DEFINE_STATIC_LOCAL(String, s, ("display")); return s; } void MediaControlElement::show() { ExceptionCode ec; // FIXME: Make more efficient <http://webkit.org/b/58157> style()->removeProperty(displayString(), ec); } void MediaControlElement::hide() { ExceptionCode ec; // FIXME: Make more efficient <http://webkit.org/b/58157> DEFINE_STATIC_LOCAL(String, none, ("none")); style()->setProperty(displayString(), none, ec); } // ---------------------------- inline MediaControlPanelElement::MediaControlPanelElement(HTMLMediaElement* mediaElement) : MediaControlElement(mediaElement) { } PassRefPtr<MediaControlPanelElement> MediaControlPanelElement::create(HTMLMediaElement* mediaElement) { return adoptRef(new MediaControlPanelElement(mediaElement)); } MediaControlElementType MediaControlPanelElement::displayType() const { return MediaControlsPanel; } const AtomicString& MediaControlPanelElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-panel")); return id; } // ---------------------------- inline MediaControlTimelineContainerElement::MediaControlTimelineContainerElement(HTMLMediaElement* mediaElement) : MediaControlElement(mediaElement) { } PassRefPtr<MediaControlTimelineContainerElement> MediaControlTimelineContainerElement::create(HTMLMediaElement* mediaElement) { RefPtr<MediaControlTimelineContainerElement> element = adoptRef(new MediaControlTimelineContainerElement(mediaElement)); element->hide(); return element.release(); } MediaControlElementType MediaControlTimelineContainerElement::displayType() const { return MediaTimelineContainer; } const AtomicString& MediaControlTimelineContainerElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-timeline-container")); return id; } // ---------------------------- class RenderMediaVolumeSliderContainer : public RenderBlock { public: RenderMediaVolumeSliderContainer(Node*); private: virtual void layout(); }; RenderMediaVolumeSliderContainer::RenderMediaVolumeSliderContainer(Node* node) : RenderBlock(node) { } void RenderMediaVolumeSliderContainer::layout() { RenderBlock::layout(); if (style()->display() == NONE || !previousSibling() || !previousSibling()->isBox()) return; RenderBox* buttonBox = toRenderBox(previousSibling()); if (view()) view()->disableLayoutState(); IntPoint offset = theme()->volumeSliderOffsetFromMuteButton(buttonBox, IntSize(width(), height())); setX(offset.x() + buttonBox->offsetLeft()); setY(offset.y() + buttonBox->offsetTop()); if (view()) view()->enableLayoutState(); } inline MediaControlVolumeSliderContainerElement::MediaControlVolumeSliderContainerElement(HTMLMediaElement* mediaElement) : MediaControlElement(mediaElement) { } PassRefPtr<MediaControlVolumeSliderContainerElement> MediaControlVolumeSliderContainerElement::create(HTMLMediaElement* mediaElement) { RefPtr<MediaControlVolumeSliderContainerElement> element = adoptRef(new MediaControlVolumeSliderContainerElement(mediaElement)); element->hide(); return element.release(); } RenderObject* MediaControlVolumeSliderContainerElement::createRenderer(RenderArena* arena, RenderStyle*) { return new (arena) RenderMediaVolumeSliderContainer(this); } void MediaControlVolumeSliderContainerElement::defaultEventHandler(Event* event) { if (!event->isMouseEvent() || event->type() != eventNames().mouseoutEvent) return; // Poor man's mouseleave event detection. MouseEvent* mouseEvent = static_cast<MouseEvent*>(event); if (!mouseEvent->relatedTarget() || !mouseEvent->relatedTarget()->toNode()) return; if (this->containsIncludingShadowDOM(mouseEvent->relatedTarget()->toNode())) return; hide(); } MediaControlElementType MediaControlVolumeSliderContainerElement::displayType() const { return MediaVolumeSliderContainer; } const AtomicString& MediaControlVolumeSliderContainerElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider-container")); return id; } // ---------------------------- inline MediaControlStatusDisplayElement::MediaControlStatusDisplayElement(HTMLMediaElement* mediaElement) : MediaControlElement(mediaElement) , m_stateBeingDisplayed(Nothing) { } PassRefPtr<MediaControlStatusDisplayElement> MediaControlStatusDisplayElement::create(HTMLMediaElement* mediaElement) { RefPtr<MediaControlStatusDisplayElement> element = adoptRef(new MediaControlStatusDisplayElement(mediaElement)); element->hide(); return element.release(); } void MediaControlStatusDisplayElement::update() { // Get the new state that we'll have to display. StateBeingDisplayed newStateToDisplay = Nothing; if (mediaElement()->readyState() != HTMLMediaElement::HAVE_ENOUGH_DATA && !mediaElement()->currentSrc().isEmpty()) newStateToDisplay = Loading; else if (mediaElement()->movieLoadType() == MediaPlayer::LiveStream) newStateToDisplay = LiveBroadcast; if (newStateToDisplay == m_stateBeingDisplayed) return; ExceptionCode e; if (m_stateBeingDisplayed == Nothing) show(); else if (newStateToDisplay == Nothing) hide(); m_stateBeingDisplayed = newStateToDisplay; switch (m_stateBeingDisplayed) { case Nothing: setInnerText("", e); break; case Loading: setInnerText(mediaElementLoadingStateText(), e); break; case LiveBroadcast: setInnerText(mediaElementLiveBroadcastStateText(), e); break; } } MediaControlElementType MediaControlStatusDisplayElement::displayType() const { return MediaStatusDisplay; } const AtomicString& MediaControlStatusDisplayElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-status-display")); return id; } // ---------------------------- MediaControlInputElement::MediaControlInputElement(HTMLMediaElement* mediaElement, MediaControlElementType displayType) : HTMLInputElement(inputTag, mediaElement->document(), 0, false) , m_mediaElement(mediaElement) , m_displayType(displayType) { } void MediaControlInputElement::show() { ExceptionCode ec; style()->removeProperty(displayString(), ec); } void MediaControlInputElement::hide() { ExceptionCode ec; DEFINE_STATIC_LOCAL(String, none, ("none")); style()->setProperty(displayString(), none, ec); } void MediaControlInputElement::setDisplayType(MediaControlElementType displayType) { if (displayType == m_displayType) return; m_displayType = displayType; if (RenderObject* object = renderer()) object->repaint(); } // ---------------------------- inline MediaControlMuteButtonElement::MediaControlMuteButtonElement(HTMLMediaElement* mediaElement, MediaControlElementType displayType) : MediaControlInputElement(mediaElement, displayType) { } void MediaControlMuteButtonElement::defaultEventHandler(Event* event) { if (event->type() == eventNames().clickEvent) { mediaElement()->setMuted(!mediaElement()->muted()); event->setDefaultHandled(); } HTMLInputElement::defaultEventHandler(event); } void MediaControlMuteButtonElement::changedMute() { updateDisplayType(); } void MediaControlMuteButtonElement::updateDisplayType() { setDisplayType(mediaElement()->muted() ? MediaUnMuteButton : MediaMuteButton); } // ---------------------------- inline MediaControlPanelMuteButtonElement::MediaControlPanelMuteButtonElement(HTMLMediaElement* mediaElement, MediaControls* controls) : MediaControlMuteButtonElement(mediaElement, MediaMuteButton) , m_controls(controls) { } PassRefPtr<MediaControlPanelMuteButtonElement> MediaControlPanelMuteButtonElement::create(HTMLMediaElement* mediaElement, MediaControls* controls) { ASSERT(controls); RefPtr<MediaControlPanelMuteButtonElement> button = adoptRef(new MediaControlPanelMuteButtonElement(mediaElement, controls)); 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::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-mute-button")); return id; } // ---------------------------- inline MediaControlVolumeSliderMuteButtonElement::MediaControlVolumeSliderMuteButtonElement(HTMLMediaElement* mediaElement) : MediaControlMuteButtonElement(mediaElement, MediaMuteButton) { } PassRefPtr<MediaControlVolumeSliderMuteButtonElement> MediaControlVolumeSliderMuteButtonElement::create(HTMLMediaElement* mediaElement) { RefPtr<MediaControlVolumeSliderMuteButtonElement> button = adoptRef(new MediaControlVolumeSliderMuteButtonElement(mediaElement)); button->setType("button"); return button.release(); } const AtomicString& MediaControlVolumeSliderMuteButtonElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider-mute-button")); return id; } // ---------------------------- inline MediaControlPlayButtonElement::MediaControlPlayButtonElement(HTMLMediaElement* mediaElement) : MediaControlInputElement(mediaElement, MediaPlayButton) { } PassRefPtr<MediaControlPlayButtonElement> MediaControlPlayButtonElement::create(HTMLMediaElement* mediaElement) { RefPtr<MediaControlPlayButtonElement> button = adoptRef(new MediaControlPlayButtonElement(mediaElement)); button->setType("button"); return button.release(); } void MediaControlPlayButtonElement::defaultEventHandler(Event* event) { if (event->type() == eventNames().clickEvent) { mediaElement()->togglePlayState(); updateDisplayType(); event->setDefaultHandled(); } HTMLInputElement::defaultEventHandler(event); } void MediaControlPlayButtonElement::updateDisplayType() { setDisplayType(mediaElement()->canPlay() ? MediaPlayButton : MediaPauseButton); } const AtomicString& MediaControlPlayButtonElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-play-button")); return id; } // ---------------------------- inline MediaControlSeekButtonElement::MediaControlSeekButtonElement(HTMLMediaElement* mediaElement, MediaControlElementType displayType) : MediaControlInputElement(mediaElement, displayType) , m_seeking(false) , m_capturing(false) , m_seekTimer(this, &MediaControlSeekButtonElement::seekTimerFired) { } void MediaControlSeekButtonElement::defaultEventHandler(Event* event) { if (event->type() == eventNames().mousedownEvent) { if (Frame* frame = document()->frame()) { m_capturing = true; frame->eventHandler()->setCapturingMouseEventsNode(this); } mediaElement()->pause(event->fromUserGesture()); m_seekTimer.startRepeating(cSeekRepeatDelay); event->setDefaultHandled(); } else if (event->type() == eventNames().mouseupEvent) { if (m_capturing) if (Frame* frame = document()->frame()) { m_capturing = false; frame->eventHandler()->setCapturingMouseEventsNode(0); } ExceptionCode ec; if (m_seeking || m_seekTimer.isActive()) { if (!m_seeking) { float stepTime = isForwardButton() ? cStepTime : -cStepTime; mediaElement()->setCurrentTime(mediaElement()->currentTime() + stepTime, ec); } m_seekTimer.stop(); m_seeking = false; event->setDefaultHandled(); } } HTMLInputElement::defaultEventHandler(event); } void MediaControlSeekButtonElement::seekTimerFired(Timer<MediaControlSeekButtonElement>*) { ExceptionCode ec; m_seeking = true; float seekTime = isForwardButton() ? cSeekTime : -cSeekTime; mediaElement()->setCurrentTime(mediaElement()->currentTime() + seekTime, ec); } void MediaControlSeekButtonElement::detach() { if (m_capturing) { if (Frame* frame = document()->frame()) frame->eventHandler()->setCapturingMouseEventsNode(0); } MediaControlInputElement::detach(); } // ---------------------------- inline MediaControlSeekForwardButtonElement::MediaControlSeekForwardButtonElement(HTMLMediaElement* mediaElement) : MediaControlSeekButtonElement(mediaElement, MediaSeekForwardButton) { } PassRefPtr<MediaControlSeekForwardButtonElement> MediaControlSeekForwardButtonElement::create(HTMLMediaElement* mediaElement) { RefPtr<MediaControlSeekForwardButtonElement> button = adoptRef(new MediaControlSeekForwardButtonElement(mediaElement)); button->setType("button"); return button.release(); } const AtomicString& MediaControlSeekForwardButtonElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-seek-forward-button")); return id; } // ---------------------------- inline MediaControlSeekBackButtonElement::MediaControlSeekBackButtonElement(HTMLMediaElement* mediaElement) : MediaControlSeekButtonElement(mediaElement, MediaSeekBackButton) { } PassRefPtr<MediaControlSeekBackButtonElement> MediaControlSeekBackButtonElement::create(HTMLMediaElement* mediaElement) { RefPtr<MediaControlSeekBackButtonElement> button = adoptRef(new MediaControlSeekBackButtonElement(mediaElement)); button->setType("button"); return button.release(); } const AtomicString& MediaControlSeekBackButtonElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-seek-back-button")); return id; } // ---------------------------- inline MediaControlRewindButtonElement::MediaControlRewindButtonElement(HTMLMediaElement* element) : MediaControlInputElement(element, MediaRewindButton) { } PassRefPtr<MediaControlRewindButtonElement> MediaControlRewindButtonElement::create(HTMLMediaElement* mediaElement) { RefPtr<MediaControlRewindButtonElement> button = adoptRef(new MediaControlRewindButtonElement(mediaElement)); button->setType("button"); return button.release(); } void MediaControlRewindButtonElement::defaultEventHandler(Event* event) { if (event->type() == eventNames().clickEvent) { mediaElement()->rewind(30); event->setDefaultHandled(); } HTMLInputElement::defaultEventHandler(event); } const AtomicString& MediaControlRewindButtonElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-rewind-button")); return id; } // ---------------------------- inline MediaControlReturnToRealtimeButtonElement::MediaControlReturnToRealtimeButtonElement(HTMLMediaElement* mediaElement) : MediaControlInputElement(mediaElement, MediaReturnToRealtimeButton) { } PassRefPtr<MediaControlReturnToRealtimeButtonElement> MediaControlReturnToRealtimeButtonElement::create(HTMLMediaElement* mediaElement) { RefPtr<MediaControlReturnToRealtimeButtonElement> button = adoptRef(new MediaControlReturnToRealtimeButtonElement(mediaElement)); button->setType("button"); button->hide(); return button.release(); } void MediaControlReturnToRealtimeButtonElement::defaultEventHandler(Event* event) { if (event->type() == eventNames().clickEvent) { mediaElement()->returnToRealtime(); event->setDefaultHandled(); } HTMLInputElement::defaultEventHandler(event); } const AtomicString& MediaControlReturnToRealtimeButtonElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-return-to-realtime-button")); return id; } // ---------------------------- inline MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement(HTMLMediaElement* mediaElement) : MediaControlInputElement(mediaElement, MediaShowClosedCaptionsButton) { } PassRefPtr<MediaControlToggleClosedCaptionsButtonElement> MediaControlToggleClosedCaptionsButtonElement::create(HTMLMediaElement* mediaElement) { RefPtr<MediaControlToggleClosedCaptionsButtonElement> button = adoptRef(new MediaControlToggleClosedCaptionsButtonElement(mediaElement)); button->setType("button"); button->hide(); return button.release(); } void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event) { if (event->type() == eventNames().clickEvent) { mediaElement()->setClosedCaptionsVisible(!mediaElement()->closedCaptionsVisible()); setChecked(mediaElement()->closedCaptionsVisible()); updateDisplayType(); event->setDefaultHandled(); } HTMLInputElement::defaultEventHandler(event); } void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType() { setDisplayType(mediaElement()->closedCaptionsVisible() ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton); } const AtomicString& MediaControlToggleClosedCaptionsButtonElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-toggle-closed-captions-button")); return id; } // ---------------------------- MediaControlTimelineElement::MediaControlTimelineElement(HTMLMediaElement* mediaElement, MediaControls* controls) : MediaControlInputElement(mediaElement, MediaSlider) , m_controls(controls) { } PassRefPtr<MediaControlTimelineElement> MediaControlTimelineElement::create(HTMLMediaElement* mediaElement, MediaControls* controls) { ASSERT(controls); RefPtr<MediaControlTimelineElement> timeline = adoptRef(new MediaControlTimelineElement(mediaElement, controls)); 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() && static_cast<MouseEvent*>(event)->button()) return; if (!attached()) return; if (event->type() == eventNames().mousedownEvent) mediaElement()->beginScrubbing(); #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS) if (event->type() == eventNames().touchstartEvent) mediaElement()->beginScrubbing(); #endif MediaControlInputElement::defaultEventHandler(event); if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent) return; #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS) if (event->type() == eventNames().touchmoveEvent || event->type() == eventNames().touchcancelEvent) return; #endif float time = narrowPrecisionToFloat(value().toDouble()); if (time != mediaElement()->currentTime()) { // FIXME: This is fired 3 times on every click. We should not be doing that <http:/webkit.org/b/58160>. ExceptionCode ec; mediaElement()->setCurrentTime(time, ec); } RenderSlider* slider = toRenderSlider(renderer()); if (slider && slider->inDragMode()) m_controls->updateTimeDisplay(); if (event->type() == eventNames().mouseupEvent) mediaElement()->endScrubbing(); #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS) if (event->type() == eventNames().touchendEvent) mediaElement()->endScrubbing(); #endif } void MediaControlTimelineElement::setPosition(float currentTime) { setValue(String::number(currentTime)); } void MediaControlTimelineElement::setDuration(float duration) { setAttribute(maxAttr, String::number(isfinite(duration) ? duration : 0)); } const AtomicString& MediaControlTimelineElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-timeline")); return id; } // ---------------------------- inline MediaControlVolumeSliderElement::MediaControlVolumeSliderElement(HTMLMediaElement* mediaElement) : MediaControlInputElement(mediaElement, MediaVolumeSlider) { } PassRefPtr<MediaControlVolumeSliderElement> MediaControlVolumeSliderElement::create(HTMLMediaElement* mediaElement) { RefPtr<MediaControlVolumeSliderElement> slider = adoptRef(new MediaControlVolumeSliderElement(mediaElement)); slider->setType("range"); slider->setAttribute(precisionAttr, "float"); slider->setAttribute(maxAttr, "1"); slider->setAttribute(valueAttr, String::number(mediaElement->volume())); return slider.release(); } void MediaControlVolumeSliderElement::defaultEventHandler(Event* event) { // Left button is 0. Rejects mouse events not from left button. if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button()) return; if (!attached()) return; MediaControlInputElement::defaultEventHandler(event); if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent) return; float volume = narrowPrecisionToFloat(value().toDouble()); if (volume != mediaElement()->volume()) { ExceptionCode ec = 0; mediaElement()->setVolume(volume, ec); ASSERT(!ec); } } void MediaControlVolumeSliderElement::setVolume(float volume) { if (value().toFloat() != volume) setValue(String::number(volume)); } const AtomicString& MediaControlVolumeSliderElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider")); return id; } // ---------------------------- inline MediaControlFullscreenVolumeSliderElement::MediaControlFullscreenVolumeSliderElement(HTMLMediaElement* mediaElement) : MediaControlVolumeSliderElement(mediaElement) { } PassRefPtr<MediaControlFullscreenVolumeSliderElement> MediaControlFullscreenVolumeSliderElement::create(HTMLMediaElement* mediaElement) { RefPtr<MediaControlFullscreenVolumeSliderElement> slider = adoptRef(new MediaControlFullscreenVolumeSliderElement(mediaElement)); slider->setType("range"); slider->setAttribute(precisionAttr, "float"); slider->setAttribute(maxAttr, "1"); slider->setAttribute(valueAttr, String::number(mediaElement->volume())); return slider.release(); } const AtomicString& MediaControlFullscreenVolumeSliderElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-slider")); return id; } // ---------------------------- inline MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(HTMLMediaElement* mediaElement, MediaControls* controls) : MediaControlInputElement(mediaElement, MediaFullscreenButton) , m_controls(controls) { } PassRefPtr<MediaControlFullscreenButtonElement> MediaControlFullscreenButtonElement::create(HTMLMediaElement* mediaElement, MediaControls* controls) { ASSERT(controls); RefPtr<MediaControlFullscreenButtonElement> button = adoptRef(new MediaControlFullscreenButtonElement(mediaElement, controls)); button->setType("button"); button->hide(); return button.release(); } void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event) { if (event->type() == eventNames().clickEvent) { #if ENABLE(FULLSCREEN_API) // 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 (document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == mediaElement()) { document()->webkitCancelFullScreen(); m_controls->exitedFullscreen(); } else { mediaElement()->webkitRequestFullScreen(0); m_controls->enteredFullscreen(); } } else #endif mediaElement()->enterFullscreen(); event->setDefaultHandled(); } HTMLInputElement::defaultEventHandler(event); } const AtomicString& MediaControlFullscreenButtonElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-button")); return id; } // ---------------------------- inline MediaControlFullscreenVolumeMinButtonElement::MediaControlFullscreenVolumeMinButtonElement(HTMLMediaElement* mediaElement) : MediaControlInputElement(mediaElement, MediaUnMuteButton) { } PassRefPtr<MediaControlFullscreenVolumeMinButtonElement> MediaControlFullscreenVolumeMinButtonElement::create(HTMLMediaElement* mediaElement) { RefPtr<MediaControlFullscreenVolumeMinButtonElement> button = adoptRef(new MediaControlFullscreenVolumeMinButtonElement(mediaElement)); button->setType("button"); return button.release(); } void MediaControlFullscreenVolumeMinButtonElement::defaultEventHandler(Event* event) { if (event->type() == eventNames().clickEvent) { ExceptionCode code = 0; mediaElement()->setVolume(0, code); event->setDefaultHandled(); } HTMLInputElement::defaultEventHandler(event); } const AtomicString& MediaControlFullscreenVolumeMinButtonElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-min-button")); return id; } // ---------------------------- inline MediaControlFullscreenVolumeMaxButtonElement::MediaControlFullscreenVolumeMaxButtonElement(HTMLMediaElement* mediaElement) : MediaControlInputElement(mediaElement, MediaMuteButton) { } PassRefPtr<MediaControlFullscreenVolumeMaxButtonElement> MediaControlFullscreenVolumeMaxButtonElement::create(HTMLMediaElement* mediaElement) { RefPtr<MediaControlFullscreenVolumeMaxButtonElement> button = adoptRef(new MediaControlFullscreenVolumeMaxButtonElement(mediaElement)); button->setType("button"); return button.release(); } void MediaControlFullscreenVolumeMaxButtonElement::defaultEventHandler(Event* event) { if (event->type() == eventNames().clickEvent) { ExceptionCode code = 0; mediaElement()->setVolume(1, code); event->setDefaultHandled(); } HTMLInputElement::defaultEventHandler(event); } const AtomicString& MediaControlFullscreenVolumeMaxButtonElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-max-button")); return id; } // ---------------------------- class RenderMediaControlTimeDisplay : public RenderFlexibleBox { public: RenderMediaControlTimeDisplay(Node*); private: virtual void layout(); }; RenderMediaControlTimeDisplay::RenderMediaControlTimeDisplay(Node* node) : RenderFlexibleBox(node) { } // We want the timeline slider to be at least 100 pixels wide. // FIXME: Eliminate hard-coded widths altogether. static const int minWidthToDisplayTimeDisplays = 45 + 100 + 45; void RenderMediaControlTimeDisplay::layout() { RenderFlexibleBox::layout(); RenderBox* timelineContainerBox = parentBox(); while (timelineContainerBox && timelineContainerBox->isAnonymous()) timelineContainerBox = timelineContainerBox->parentBox(); if (timelineContainerBox && timelineContainerBox->width() < minWidthToDisplayTimeDisplays) setWidth(0); } inline MediaControlTimeDisplayElement::MediaControlTimeDisplayElement(HTMLMediaElement* mediaElement) : MediaControlElement(mediaElement) , m_currentValue(0) { } void MediaControlTimeDisplayElement::setCurrentValue(float time) { m_currentValue = time; } RenderObject* MediaControlTimeDisplayElement::createRenderer(RenderArena* arena, RenderStyle*) { return new (arena) RenderMediaControlTimeDisplay(this); } // ---------------------------- PassRefPtr<MediaControlTimeRemainingDisplayElement> MediaControlTimeRemainingDisplayElement::create(HTMLMediaElement* mediaElement) { return adoptRef(new MediaControlTimeRemainingDisplayElement(mediaElement)); } MediaControlTimeRemainingDisplayElement::MediaControlTimeRemainingDisplayElement(HTMLMediaElement* mediaElement) : MediaControlTimeDisplayElement(mediaElement) { } MediaControlElementType MediaControlTimeRemainingDisplayElement::displayType() const { return MediaTimeRemainingDisplay; } const AtomicString& MediaControlTimeRemainingDisplayElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-time-remaining-display")); return id; } // ---------------------------- PassRefPtr<MediaControlCurrentTimeDisplayElement> MediaControlCurrentTimeDisplayElement::create(HTMLMediaElement* mediaElement) { return adoptRef(new MediaControlCurrentTimeDisplayElement(mediaElement)); } MediaControlCurrentTimeDisplayElement::MediaControlCurrentTimeDisplayElement(HTMLMediaElement* mediaElement) : MediaControlTimeDisplayElement(mediaElement) { } MediaControlElementType MediaControlCurrentTimeDisplayElement::displayType() const { return MediaCurrentTimeDisplay; } const AtomicString& MediaControlCurrentTimeDisplayElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-current-time-display")); return id; } } // namespace WebCore #endif // ENABLE(VIDEO)