blob: fcaf3684115877bdac07e0bc5e1f4e148cd1904c [file] [log] [blame]
/*
* 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 "EventNames.h"
#include "FloatConversion.h"
#include "Frame.h"
#include "HTMLNames.h"
#include "LocalizedStrings.h"
#include "MouseEvent.h"
#include "Page.h"
#include "RenderMedia.h"
#include "RenderSlider.h"
#include "RenderTheme.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;
inline MediaControlShadowRootElement::MediaControlShadowRootElement(HTMLMediaElement* mediaElement)
: HTMLDivElement(divTag, mediaElement->document())
{
setShadowHost(mediaElement);
}
PassRefPtr<MediaControlShadowRootElement> MediaControlShadowRootElement::create(HTMLMediaElement* mediaElement)
{
RefPtr<MediaControlShadowRootElement> element = adoptRef(new MediaControlShadowRootElement(mediaElement));
RefPtr<RenderStyle> rootStyle = RenderStyle::create();
rootStyle->inheritFrom(mediaElement->renderer()->style());
rootStyle->setDisplay(BLOCK);
rootStyle->setPosition(RelativePosition);
RenderMediaControlShadowRoot* renderer = new (mediaElement->renderer()->renderArena()) RenderMediaControlShadowRoot(element.get());
renderer->setStyle(rootStyle.release());
element->setRenderer(renderer);
element->setAttached();
element->setInDocument();
return element.release();
}
void MediaControlShadowRootElement::updateStyle()
{
if (renderer()) {
RenderStyle* timelineContainerStyle = shadowHost()->renderer()->getCachedPseudoStyle(MEDIA_CONTROLS_TIMELINE_CONTAINER);
renderer()->setStyle(timelineContainerStyle);
}
}
void MediaControlShadowRootElement::detach()
{
HTMLDivElement::detach();
// FIXME: Remove once shadow DOM uses Element::setShadowRoot().
setShadowHost(0);
}
// ----------------------------
MediaControlElement::MediaControlElement(HTMLMediaElement* mediaElement, PseudoId pseudo)
: HTMLDivElement(divTag, mediaElement->document())
, m_mediaElement(mediaElement)
, m_pseudoStyleId(pseudo)
{
setInDocument();
switch (pseudo) {
case MEDIA_CONTROLS_CURRENT_TIME_DISPLAY:
m_displayType = MediaCurrentTimeDisplay;
break;
case MEDIA_CONTROLS_TIME_REMAINING_DISPLAY:
m_displayType = MediaTimeRemainingDisplay;
break;
case MEDIA_CONTROLS_TIMELINE_CONTAINER:
m_displayType = MediaTimelineContainer;
break;
case MEDIA_CONTROLS_STATUS_DISPLAY:
m_displayType = MediaStatusDisplay;
break;
case MEDIA_CONTROLS_PANEL:
m_displayType = MediaControlsPanel;
break;
case MEDIA_CONTROLS_VOLUME_SLIDER_CONTAINER:
m_displayType = MediaVolumeSliderContainer;
break;
default:
ASSERT_NOT_REACHED();
break;
}
}
PassRefPtr<MediaControlElement> MediaControlElement::create(HTMLMediaElement* mediaElement, PseudoId pseudoStyleId)
{
return adoptRef(new MediaControlElement(mediaElement, pseudoStyleId));
}
void MediaControlElement::attachToParent(Element* parent)
{
// FIXME: This code seems very wrong. Why are we magically adding |this| to the DOM here?
// We shouldn't be calling parser API methods outside of the parser!
parent->parserAddChild(this);
}
void MediaControlElement::update()
{
if (renderer())
renderer()->updateFromElement();
updateStyle();
}
PassRefPtr<RenderStyle> MediaControlElement::styleForElement()
{
RenderStyle* style = m_mediaElement->renderer()->getCachedPseudoStyle(m_pseudoStyleId);
if (!style)
return 0;
// text-decoration can't be overrided from CSS. So we do it here.
// See https://bugs.webkit.org/show_bug.cgi?id=27015
style->setTextDecoration(TDNONE);
style->setTextDecorationsInEffect(TDNONE);
return style;
}
bool MediaControlElement::rendererIsNeeded(RenderStyle* style)
{
ASSERT(document()->page());
return HTMLDivElement::rendererIsNeeded(style) && parentNode() && parentNode()->renderer()
&& (!style->hasAppearance() || document()->page()->theme()->shouldRenderMediaControlPart(style->appearance(), m_mediaElement));
}
void MediaControlElement::attach()
{
RefPtr<RenderStyle> style = styleForElement();
if (!style)
return;
bool needsRenderer = rendererIsNeeded(style.get());
if (!needsRenderer)
return;
RenderObject* renderer = createRenderer(m_mediaElement->renderer()->renderArena(), style.get());
if (!renderer)
return;
renderer->setStyle(style.get());
setRenderer(renderer);
if (parentNode() && parentNode()->renderer()) {
// Find next sibling with a renderer to determine where to insert.
Node* sibling = nextSibling();
while (sibling && !sibling->renderer())
sibling = sibling->nextSibling();
parentNode()->renderer()->addChild(renderer, sibling ? sibling->renderer() : 0);
}
ContainerNode::attach();
}
void MediaControlElement::updateStyle()
{
if (!m_mediaElement || !m_mediaElement->renderer())
return;
RefPtr<RenderStyle> style = styleForElement();
if (!style)
return;
bool needsRenderer = rendererIsNeeded(style.get()) && parentNode() && parentNode()->renderer();
if (renderer() && !needsRenderer)
detach();
else if (!renderer() && needsRenderer)
attach();
else if (renderer()) {
renderer()->setStyle(style.get());
// Make sure that if there is any innerText renderer, it is updated as well.
if (firstChild() && firstChild()->renderer())
firstChild()->renderer()->setStyle(style.get());
}
}
// ----------------------------
inline MediaControlTimelineContainerElement::MediaControlTimelineContainerElement(HTMLMediaElement* mediaElement)
: MediaControlElement(mediaElement, MEDIA_CONTROLS_TIMELINE_CONTAINER)
{
}
PassRefPtr<MediaControlTimelineContainerElement> MediaControlTimelineContainerElement::create(HTMLMediaElement* mediaElement)
{
return adoptRef(new MediaControlTimelineContainerElement(mediaElement));
}
bool MediaControlTimelineContainerElement::rendererIsNeeded(RenderStyle* style)
{
if (!MediaControlElement::rendererIsNeeded(style))
return false;
// This is for MediaControllerThemeClassic:
// If there is no style for MediaControlStatusDisplayElement style, don't hide
// the timeline.
if (!mediaElement()->renderer()->getCachedPseudoStyle(MEDIA_CONTROLS_STATUS_DISPLAY))
return true;
float duration = mediaElement()->duration();
return !isnan(duration) && !isinf(duration);
}
// ----------------------------
inline MediaControlVolumeSliderContainerElement::MediaControlVolumeSliderContainerElement(HTMLMediaElement* mediaElement)
: MediaControlElement(mediaElement, MEDIA_CONTROLS_VOLUME_SLIDER_CONTAINER)
, m_isVisible(false)
, m_x(0)
, m_y(0)
{
}
PassRefPtr<MediaControlVolumeSliderContainerElement> MediaControlVolumeSliderContainerElement::create(HTMLMediaElement* mediaElement)
{
return adoptRef(new MediaControlVolumeSliderContainerElement(mediaElement));
}
PassRefPtr<RenderStyle> MediaControlVolumeSliderContainerElement::styleForElement()
{
RefPtr<RenderStyle> style = MediaControlElement::styleForElement();
style->setPosition(AbsolutePosition);
style->setLeft(Length(m_x, Fixed));
style->setTop(Length(m_y, Fixed));
style->setDisplay(m_isVisible ? BLOCK : NONE);
return style;
}
void MediaControlVolumeSliderContainerElement::setVisible(bool visible)
{
if (visible == m_isVisible)
return;
m_isVisible = visible;
}
void MediaControlVolumeSliderContainerElement::setPosition(int x, int y)
{
if (x == m_x && y == m_y)
return;
m_x = x;
m_y = y;
}
bool MediaControlVolumeSliderContainerElement::hitTest(const IntPoint& absPoint)
{
if (renderer() && renderer()->style()->hasAppearance())
return renderer()->theme()->hitTestMediaControlPart(renderer(), absPoint);
return false;
}
// ----------------------------
inline MediaControlStatusDisplayElement::MediaControlStatusDisplayElement(HTMLMediaElement* mediaElement)
: MediaControlElement(mediaElement, MEDIA_CONTROLS_STATUS_DISPLAY)
, m_stateBeingDisplayed(Nothing)
{
}
PassRefPtr<MediaControlStatusDisplayElement> MediaControlStatusDisplayElement::create(HTMLMediaElement* mediaElement)
{
return adoptRef(new MediaControlStatusDisplayElement(mediaElement));
}
void MediaControlStatusDisplayElement::update()
{
MediaControlElement::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;
// Propagate only if needed.
if (newStateToDisplay == m_stateBeingDisplayed)
return;
m_stateBeingDisplayed = newStateToDisplay;
ExceptionCode e;
switch (m_stateBeingDisplayed) {
case Nothing:
setInnerText("", e);
break;
case Loading:
setInnerText(mediaElementLoadingStateText(), e);
break;
case LiveBroadcast:
setInnerText(mediaElementLiveBroadcastStateText(), e);
break;
}
}
bool MediaControlStatusDisplayElement::rendererIsNeeded(RenderStyle* style)
{
if (!MediaControlElement::rendererIsNeeded(style))
return false;
float duration = mediaElement()->duration();
return (isnan(duration) || isinf(duration));
}
// ----------------------------
MediaControlInputElement::MediaControlInputElement(HTMLMediaElement* mediaElement, PseudoId pseudo)
: HTMLInputElement(inputTag, mediaElement->document())
, m_mediaElement(mediaElement)
, m_pseudoStyleId(pseudo)
{
setInDocument();
switch (pseudo) {
case MEDIA_CONTROLS_MUTE_BUTTON:
m_displayType = MediaMuteButton;
break;
case MEDIA_CONTROLS_PLAY_BUTTON:
m_displayType = MediaPlayButton;
break;
case MEDIA_CONTROLS_SEEK_FORWARD_BUTTON:
m_displayType = MediaSeekForwardButton;
break;
case MEDIA_CONTROLS_SEEK_BACK_BUTTON:
m_displayType = MediaSeekBackButton;
break;
case MEDIA_CONTROLS_FULLSCREEN_BUTTON:
m_displayType = MediaFullscreenButton;
break;
case MEDIA_CONTROLS_TIMELINE:
m_displayType = MediaSlider;
break;
case MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON:
m_displayType = MediaReturnToRealtimeButton;
break;
case MEDIA_CONTROLS_REWIND_BUTTON:
m_displayType = MediaRewindButton;
break;
case MEDIA_CONTROLS_VOLUME_SLIDER:
m_displayType = MediaVolumeSlider;
break;
case MEDIA_CONTROLS_VOLUME_SLIDER_MUTE_BUTTON:
m_displayType = MediaVolumeSliderMuteButton;
break;
case MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON:
m_displayType = MediaShowClosedCaptionsButton;
break;
default:
ASSERT_NOT_REACHED();
break;
}
}
void MediaControlInputElement::attachToParent(Element* parent)
{
// FIXME: This code seems very wrong. Why are we magically adding |this| to the DOM here?
// We shouldn't be calling parser API methods outside of the parser!
parent->parserAddChild(this);
}
void MediaControlInputElement::update()
{
updateDisplayType();
if (renderer())
renderer()->updateFromElement();
updateStyle();
}
PassRefPtr<RenderStyle> MediaControlInputElement::styleForElement()
{
return mediaElement()->renderer()->getCachedPseudoStyle(m_pseudoStyleId);
}
bool MediaControlInputElement::rendererIsNeeded(RenderStyle* style)
{
ASSERT(document()->page());
return HTMLInputElement::rendererIsNeeded(style) && parentNode() && parentNode()->renderer()
&& (!style->hasAppearance() || document()->page()->theme()->shouldRenderMediaControlPart(style->appearance(), mediaElement()));
}
void MediaControlInputElement::attach()
{
RefPtr<RenderStyle> style = styleForElement();
if (!style)
return;
bool needsRenderer = rendererIsNeeded(style.get());
if (!needsRenderer)
return;
RenderObject* renderer = createRenderer(mediaElement()->renderer()->renderArena(), style.get());
if (!renderer)
return;
renderer->setStyle(style.get());
setRenderer(renderer);
if (parentNode() && parentNode()->renderer()) {
// Find next sibling with a renderer to determine where to insert.
Node* sibling = nextSibling();
while (sibling && !sibling->renderer())
sibling = sibling->nextSibling();
parentNode()->renderer()->addChild(renderer, sibling ? sibling->renderer() : 0);
}
ContainerNode::attach();
}
void MediaControlInputElement::updateStyle()
{
if (!mediaElement() || !mediaElement()->renderer())
return;
RefPtr<RenderStyle> style = styleForElement();
if (!style)
return;
bool needsRenderer = rendererIsNeeded(style.get()) && parentNode() && parentNode()->renderer();
if (renderer() && !needsRenderer)
detach();
else if (!renderer() && needsRenderer)
attach();
else if (renderer())
renderer()->setStyle(style.get());
}
bool MediaControlInputElement::hitTest(const IntPoint& absPoint)
{
if (renderer() && renderer()->style()->hasAppearance())
return renderer()->theme()->hitTestMediaControlPart(renderer(), absPoint);
return false;
}
void MediaControlInputElement::setDisplayType(MediaControlElementType displayType)
{
if (displayType == m_displayType)
return;
m_displayType = displayType;
if (RenderObject* object = renderer())
object->repaint();
}
// ----------------------------
inline MediaControlMuteButtonElement::MediaControlMuteButtonElement(HTMLMediaElement* mediaElement, ButtonLocation location)
: MediaControlInputElement(mediaElement, location == Controller ? MEDIA_CONTROLS_MUTE_BUTTON : MEDIA_CONTROLS_VOLUME_SLIDER_MUTE_BUTTON)
{
}
PassRefPtr<MediaControlMuteButtonElement> MediaControlMuteButtonElement::create(HTMLMediaElement* mediaElement, ButtonLocation location)
{
RefPtr<MediaControlMuteButtonElement> button = adoptRef(new MediaControlMuteButtonElement(mediaElement, location));
button->setType("button");
return button.release();
}
void MediaControlMuteButtonElement::defaultEventHandler(Event* event)
{
if (event->type() == eventNames().clickEvent) {
mediaElement()->setMuted(!mediaElement()->muted());
event->setDefaultHandled();
}
HTMLInputElement::defaultEventHandler(event);
}
void MediaControlMuteButtonElement::updateDisplayType()
{
setDisplayType(mediaElement()->muted() ? MediaUnMuteButton : MediaMuteButton);
}
// ----------------------------
inline MediaControlPlayButtonElement::MediaControlPlayButtonElement(HTMLMediaElement* mediaElement)
: MediaControlInputElement(mediaElement, MEDIA_CONTROLS_PLAY_BUTTON)
{
}
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();
event->setDefaultHandled();
}
HTMLInputElement::defaultEventHandler(event);
}
void MediaControlPlayButtonElement::updateDisplayType()
{
setDisplayType(mediaElement()->canPlay() ? MediaPlayButton : MediaPauseButton);
}
// ----------------------------
inline MediaControlSeekButtonElement::MediaControlSeekButtonElement(HTMLMediaElement* mediaElement, PseudoId pseudoId)
: MediaControlInputElement(mediaElement, pseudoId)
, m_seeking(false)
, m_capturing(false)
, m_seekTimer(this, &MediaControlSeekButtonElement::seekTimerFired)
{
}
PassRefPtr<MediaControlSeekButtonElement> MediaControlSeekButtonElement::create(HTMLMediaElement* mediaElement, PseudoId pseudoStyleId)
{
RefPtr<MediaControlSeekButtonElement> button = adoptRef(new MediaControlSeekButtonElement(mediaElement, pseudoStyleId));
button->setType("button");
return button.release();
}
inline bool MediaControlSeekButtonElement::isForwardButton() const
{
return pseudoStyleId() == MEDIA_CONTROLS_SEEK_FORWARD_BUTTON;
}
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 MediaControlRewindButtonElement::MediaControlRewindButtonElement(HTMLMediaElement* element)
: MediaControlInputElement(element, MEDIA_CONTROLS_REWIND_BUTTON)
{
}
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);
}
// ----------------------------
inline MediaControlReturnToRealtimeButtonElement::MediaControlReturnToRealtimeButtonElement(HTMLMediaElement* mediaElement)
: MediaControlInputElement(mediaElement, MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON)
{
}
PassRefPtr<MediaControlReturnToRealtimeButtonElement> MediaControlReturnToRealtimeButtonElement::create(HTMLMediaElement* mediaElement)
{
RefPtr<MediaControlReturnToRealtimeButtonElement> button = adoptRef(new MediaControlReturnToRealtimeButtonElement(mediaElement));
button->setType("button");
return button.release();
}
void MediaControlReturnToRealtimeButtonElement::defaultEventHandler(Event* event)
{
if (event->type() == eventNames().clickEvent) {
mediaElement()->returnToRealtime();
event->setDefaultHandled();
}
HTMLInputElement::defaultEventHandler(event);
}
// ----------------------------
inline MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement(HTMLMediaElement* mediaElement)
: MediaControlInputElement(mediaElement, MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON)
{
}
PassRefPtr<MediaControlToggleClosedCaptionsButtonElement> MediaControlToggleClosedCaptionsButtonElement::create(HTMLMediaElement* mediaElement)
{
RefPtr<MediaControlToggleClosedCaptionsButtonElement> button = adoptRef(new MediaControlToggleClosedCaptionsButtonElement(mediaElement));
button->setType("button");
return button.release();
}
void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event)
{
if (event->type() == eventNames().clickEvent) {
mediaElement()->setClosedCaptionsVisible(!mediaElement()->closedCaptionsVisible());
setChecked(mediaElement()->closedCaptionsVisible());
event->setDefaultHandled();
}
HTMLInputElement::defaultEventHandler(event);
}
void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType()
{
setDisplayType(mediaElement()->closedCaptionsVisible() ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton);
}
// ----------------------------
MediaControlTimelineElement::MediaControlTimelineElement(HTMLMediaElement* mediaElement)
: MediaControlInputElement(mediaElement, MEDIA_CONTROLS_TIMELINE)
{
}
PassRefPtr<MediaControlTimelineElement> MediaControlTimelineElement::create(HTMLMediaElement* mediaElement)
{
RefPtr<MediaControlTimelineElement> timeline = adoptRef(new MediaControlTimelineElement(mediaElement));
timeline->setType("range");
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();
MediaControlInputElement::defaultEventHandler(event);
if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
return;
float time = narrowPrecisionToFloat(value().toDouble());
if (time != mediaElement()->currentTime()) {
ExceptionCode ec;
mediaElement()->setCurrentTime(time, ec);
}
RenderSlider* slider = toRenderSlider(renderer());
if (slider && slider->inDragMode()) {
toRenderMedia(mediaElement()->renderer())->updateTimeDisplay();
#if PLATFORM(ANDROID)
toRenderMedia(mediaElement()->renderer())->updateLastTouch();
#endif
}
if (event->type() == eventNames().mouseupEvent)
mediaElement()->endScrubbing();
}
void MediaControlTimelineElement::update(bool updateDuration)
{
if (updateDuration) {
float duration = mediaElement()->duration();
setAttribute(maxAttr, String::number(isfinite(duration) ? duration : 0));
}
setValue(String::number(mediaElement()->currentTime()));
MediaControlInputElement::update();
}
// ----------------------------
inline MediaControlVolumeSliderElement::MediaControlVolumeSliderElement(HTMLMediaElement* mediaElement)
: MediaControlInputElement(mediaElement, MEDIA_CONTROLS_VOLUME_SLIDER)
{
}
PassRefPtr<MediaControlVolumeSliderElement> MediaControlVolumeSliderElement::create(HTMLMediaElement* mediaElement)
{
RefPtr<MediaControlVolumeSliderElement> slider = adoptRef(new MediaControlVolumeSliderElement(mediaElement));
slider->setType("range");
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::update()
{
float volume = mediaElement()->volume();
if (value().toFloat() != volume)
setValue(String::number(volume));
MediaControlInputElement::update();
}
// ----------------------------
inline MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(HTMLMediaElement* mediaElement)
: MediaControlInputElement(mediaElement, MEDIA_CONTROLS_FULLSCREEN_BUTTON)
{
}
PassRefPtr<MediaControlFullscreenButtonElement> MediaControlFullscreenButtonElement::create(HTMLMediaElement* mediaElement)
{
RefPtr<MediaControlFullscreenButtonElement> button = adoptRef(new MediaControlFullscreenButtonElement(mediaElement));
button->setType("button");
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()->webkitFullScreen() && document()->webkitCurrentFullScreenElement() == mediaElement())
document()->webkitCancelFullScreen();
else
mediaElement()->webkitRequestFullScreen(0);
} else
#endif
mediaElement()->enterFullscreen();
event->setDefaultHandled();
}
HTMLInputElement::defaultEventHandler(event);
}
// ----------------------------
inline MediaControlTimeDisplayElement::MediaControlTimeDisplayElement(HTMLMediaElement* mediaElement, PseudoId pseudo)
: MediaControlElement(mediaElement, pseudo)
, m_currentValue(0)
, m_isVisible(true)
{
}
PassRefPtr<MediaControlTimeDisplayElement> MediaControlTimeDisplayElement::create(HTMLMediaElement* mediaElement, PseudoId pseudoStyleId)
{
return adoptRef(new MediaControlTimeDisplayElement(mediaElement, pseudoStyleId));
}
PassRefPtr<RenderStyle> MediaControlTimeDisplayElement::styleForElement()
{
RefPtr<RenderStyle> style = MediaControlElement::styleForElement();
if (!m_isVisible) {
style = RenderStyle::clone(style.get());
style->setWidth(Length(0, Fixed));
}
return style;
}
void MediaControlTimeDisplayElement::setVisible(bool visible)
{
if (visible == m_isVisible)
return;
m_isVisible = visible;
// This function is used during the RenderMedia::layout()
// call, where we cannot change the renderer at this time.
if (!renderer() || !renderer()->style())
return;
RefPtr<RenderStyle> style = styleForElement();
renderer()->setStyle(style.get());
}
void MediaControlTimeDisplayElement::setCurrentValue(float time)
{
m_currentValue = time;
}
} // namespace WebCore
#endif // ENABLE(VIDEO)