Reviewed by Darin Adler and Simon Fraser.
REGRESSION (r87622): Scrubbing a Vimeo movie when in fullscreen stops playback; no way to make it start again
https://bugs.webkit.org/show_bug.cgi?id=61717
rdar://problem/9522272
May be some good way to test this later. No immediate idea about the best way.
When a media element is taken into full-screen mode, stop events from propagating
outside the media element's shadow DOM, EventDispatcher::determineDispatchBehavior()
has been changed to take a shadow root node. In our full screen media element check,
we check to see if the passed shadow root is the shadow root of the full screen media
element, and if so, specify events should StayInsideShadowDOM. The end result is that
inside EventDispatcher::ensureEventAncestors, an ancestor chain is built up all the
way from the SliderThumb to the video element's shadow root, but no further.
* dom/EventDispatcher.cpp:
(WebCore::EventDispatcher::determineDispatchBehavior): Restrict events to the
shadow DOM when showing a full screen video.
* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::HTMLMediaElement): Removed code to manage full screen controls.
The events telling us about activity in the shadow DOM no longer bubble out so we need to
handle this inside the shadow DOM on the root element.
(WebCore::HTMLMediaElement::play): Ditto.
(WebCore::HTMLMediaElement::playbackProgressTimerFired): Ditto.
(WebCore::HTMLMediaElement::defaultEventHandler): Ditto.
(WebCore::HTMLMediaElement::enterFullscreen): Ditto.
(WebCore::HTMLMediaElement::exitFullscreen): Ditto.
* html/HTMLMediaElement.h: Added isPlaying function, removed things moved to the root element.
* html/shadow/MediaControlElements.cpp:
(WebCore::MediaControlVolumeSliderContainerElement::defaultEventHandler): Rolled out
changes that tried to make special rules for events using preDispatchEventHandler and such.
This rolls out both r87622 and r87655.
(WebCore::MediaControlMuteButtonElement::defaultEventHandler): Ditto.
(WebCore::MediaControlPanelMuteButtonElement::defaultEventHandler): Ditto.
(WebCore::MediaControlPlayButtonElement::defaultEventHandler): Ditto.
(WebCore::MediaControlSeekButtonElement::defaultEventHandler): Ditto.
(WebCore::MediaControlRewindButtonElement::defaultEventHandler): Ditto.
(WebCore::MediaControlReturnToRealtimeButtonElement::defaultEventHandler): Ditto.
(WebCore::MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler): Ditto.
(WebCore::MediaControlTimelineElement::defaultEventHandler): Ditto.
(WebCore::MediaControlVolumeSliderElement::defaultEventHandler): Ditto.
(WebCore::MediaControlFullscreenButtonElement::defaultEventHandler): Ditto.
(WebCore::MediaControlFullscreenVolumeMinButtonElement::defaultEventHandler): Ditto.
(WebCore::MediaControlFullscreenVolumeMaxButtonElement::defaultEventHandler): Ditto.
* html/shadow/MediaControlElements.h: Ditto.
* html/shadow/MediaControlRootElement.cpp:
(WebCore::MediaControlRootElement::MediaControlRootElement): Initialize new data members.
(WebCore::MediaControlRootElement::playbackStarted): Start the timer so we will consider
hiding the controls later.
(WebCore::MediaControlRootElement::playbackProgressed): Hide the controls if the mouse
is no longer over the controls.
(WebCore::MediaControlRootElement::playbackStopped): Stop the timer since we only hide
automatically if we're playing.
(WebCore::MediaControlRootElement::enteredFullscreen): Start the timer.
(WebCore::MediaControlRootElement::exitedFullscreen): Stop the timer since we only care
if we are full screen.
(WebCore::MediaControlRootElement::containsRelatedTarget): Added. Helper for next function.
(WebCore::MediaControlRootElement::defaultEventHandler): Do the hide/show and timer functions
as the mouse is moved in and out.
(WebCore::MediaControlRootElement::startHideFullscreenControlsTimer): Start the timer if
needed.
(WebCore::MediaControlRootElement::hideFullscreenControlsTimerFired): Hide if the conditions
are met.
(WebCore::MediaControlRootElement::stopHideFullscreenControlsTimer): Stop the timer.
* html/shadow/MediaControlRootElement.h: Added new functions and data members.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@87692
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2011-05-30 Jer Noble <jer.noble@apple.com>
+
+ Reviewed by Darin Adler and Simon Fraser.
+
+ REGRESSION (r87622): Scrubbing a Vimeo movie when in fullscreen stops playback; no way to make it start again
+ https://bugs.webkit.org/show_bug.cgi?id=61717
+ rdar://problem/9522272
+
+ May be some good way to test this later. No immediate idea about the best way.
+
+ When a media element is taken into full-screen mode, stop events from propagating
+ outside the media element's shadow DOM, EventDispatcher::determineDispatchBehavior()
+ has been changed to take a shadow root node. In our full screen media element check,
+ we check to see if the passed shadow root is the shadow root of the full screen media
+ element, and if so, specify events should StayInsideShadowDOM. The end result is that
+ inside EventDispatcher::ensureEventAncestors, an ancestor chain is built up all the
+ way from the SliderThumb to the video element's shadow root, but no further.
+
+ * dom/EventDispatcher.cpp:
+ (WebCore::EventDispatcher::determineDispatchBehavior): Restrict events to the
+ shadow DOM when showing a full screen video.
+
+ * html/HTMLMediaElement.cpp:
+ (WebCore::HTMLMediaElement::HTMLMediaElement): Removed code to manage full screen controls.
+ The events telling us about activity in the shadow DOM no longer bubble out so we need to
+ handle this inside the shadow DOM on the root element.
+ (WebCore::HTMLMediaElement::play): Ditto.
+ (WebCore::HTMLMediaElement::playbackProgressTimerFired): Ditto.
+ (WebCore::HTMLMediaElement::defaultEventHandler): Ditto.
+ (WebCore::HTMLMediaElement::enterFullscreen): Ditto.
+ (WebCore::HTMLMediaElement::exitFullscreen): Ditto.
+ * html/HTMLMediaElement.h: Added isPlaying function, removed things moved to the root element.
+
+ * html/shadow/MediaControlElements.cpp:
+ (WebCore::MediaControlVolumeSliderContainerElement::defaultEventHandler): Rolled out
+ changes that tried to make special rules for events using preDispatchEventHandler and such.
+ This rolls out both r87622 and r87655.
+ (WebCore::MediaControlMuteButtonElement::defaultEventHandler): Ditto.
+ (WebCore::MediaControlPanelMuteButtonElement::defaultEventHandler): Ditto.
+ (WebCore::MediaControlPlayButtonElement::defaultEventHandler): Ditto.
+ (WebCore::MediaControlSeekButtonElement::defaultEventHandler): Ditto.
+ (WebCore::MediaControlRewindButtonElement::defaultEventHandler): Ditto.
+ (WebCore::MediaControlReturnToRealtimeButtonElement::defaultEventHandler): Ditto.
+ (WebCore::MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler): Ditto.
+ (WebCore::MediaControlTimelineElement::defaultEventHandler): Ditto.
+ (WebCore::MediaControlVolumeSliderElement::defaultEventHandler): Ditto.
+ (WebCore::MediaControlFullscreenButtonElement::defaultEventHandler): Ditto.
+ (WebCore::MediaControlFullscreenVolumeMinButtonElement::defaultEventHandler): Ditto.
+ (WebCore::MediaControlFullscreenVolumeMaxButtonElement::defaultEventHandler): Ditto.
+ * html/shadow/MediaControlElements.h: Ditto.
+
+ * html/shadow/MediaControlRootElement.cpp:
+ (WebCore::MediaControlRootElement::MediaControlRootElement): Initialize new data members.
+ (WebCore::MediaControlRootElement::playbackStarted): Start the timer so we will consider
+ hiding the controls later.
+ (WebCore::MediaControlRootElement::playbackProgressed): Hide the controls if the mouse
+ is no longer over the controls.
+ (WebCore::MediaControlRootElement::playbackStopped): Stop the timer since we only hide
+ automatically if we're playing.
+ (WebCore::MediaControlRootElement::enteredFullscreen): Start the timer.
+ (WebCore::MediaControlRootElement::exitedFullscreen): Stop the timer since we only care
+ if we are full screen.
+ (WebCore::MediaControlRootElement::containsRelatedTarget): Added. Helper for next function.
+ (WebCore::MediaControlRootElement::defaultEventHandler): Do the hide/show and timer functions
+ as the mouse is moved in and out.
+ (WebCore::MediaControlRootElement::startHideFullscreenControlsTimer): Start the timer if
+ needed.
+ (WebCore::MediaControlRootElement::hideFullscreenControlsTimerFired): Hide if the conditions
+ are met.
+ (WebCore::MediaControlRootElement::stopHideFullscreenControlsTimer): Stop the timer.
+
+ * html/shadow/MediaControlRootElement.h: Added new functions and data members.
+
+
2011-05-30 Gavin Peters <gavinp@chromium.org>
Reviewed by Adam Barth.
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
* (C) 1999 Antti Koivisto (koivisto@kde.org)
* (C) 2001 Dirk Mueller (mueller@kde.org)
- * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
* Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
* Copyright (C) 2011 Google Inc. All rights reserved.
#include "config.h"
#include "EventDispatcher.h"
-#include "Element.h"
-#include "Event.h"
#include "EventContext.h"
-#include "EventTarget.h"
#include "FrameView.h"
+#include "HTMLMediaElement.h"
#include "InspectorInstrumentation.h"
#include "MouseEvent.h"
-#include "Node.h"
#include "ScopedEventQueue.h"
+#include "WindowEventContext.h"
+#include <wtf/RefPtr.h>
#if ENABLE(SVG)
#include "SVGElementInstance.h"
#include "SVGUseElement.h"
#endif
-#include "UIEvent.h"
-#include "UIEventWithKeyState.h"
-#include "WindowEventContext.h"
-
-#include <wtf/RefPtr.h>
-
namespace WebCore {
static HashSet<Node*>* gNodesDispatchingSimulatedClicks = 0;
void EventDispatcher::ensureEventAncestors(Event* event)
{
- EventDispatchBehavior behavior = determineDispatchBehavior(event);
-
if (!m_node->inDocument())
return;
while (true) {
bool isSVGShadowRoot = ancestor->isSVGShadowRoot();
if (isSVGShadowRoot || ancestor->isShadowRoot()) {
- if (behavior == StayInsideShadowDOM)
+ if (determineDispatchBehavior(event, ancestor) == StayInsideShadowDOM)
return;
#if ENABLE(SVG)
ancestor = isSVGShadowRoot ? ancestor->svgShadowHost() : ancestor->shadowHost();
return m_ancestors.isEmpty() ? 0 : &m_ancestors.last();
}
-EventDispatchBehavior EventDispatcher::determineDispatchBehavior(Event* event)
+EventDispatchBehavior EventDispatcher::determineDispatchBehavior(Event* event, Node* shadowRoot)
{
+#if ENABLE(FULLSCREEN_API)
+ // Video-only full screen is a mode where we use the shadow DOM as an implementation
+ // detail that should not be detectable by the web content.
+ if (Element* element = m_node->document()->webkitCurrentFullScreenElement()) {
+ // FIXME: We assume that if the full screen element is a media element that it's
+ // the video-only full screen. Both here and elsewhere. But that is probably wrong.
+ if (element->isMediaElement() && shadowRoot && shadowRoot->shadowHost() == element)
+ return StayInsideShadowDOM;
+ }
+#endif
+
// Per XBL 2.0 spec, mutation events should never cross shadow DOM boundary:
// http://dev.w3.org/2006/xbl2/#event-flow-and-targeting-across-shadow-s
if (event->isMutationEvent())
EventDispatcher(Node*);
PassRefPtr<EventTarget> adjustToShadowBoundaries(PassRefPtr<Node> relatedTarget, const Vector<Node*> relatedTargetAncestors);
- EventDispatchBehavior determineDispatchBehavior(Event*);
+ EventDispatchBehavior determineDispatchBehavior(Event*, Node* shadowRoot);
void ensureEventAncestors(Event*);
const EventContext* topEventContext();
, m_asyncEventTimer(this, &HTMLMediaElement::asyncEventTimerFired)
, m_progressEventTimer(this, &HTMLMediaElement::progressEventTimerFired)
, m_playbackProgressTimer(this, &HTMLMediaElement::playbackProgressTimerFired)
- , m_hideFullscreenControlsTimer(this, &HTMLMediaElement::hideFullscreenControlsTimerFired)
, m_playedTimeRanges()
, m_playbackRate(1.0f)
, m_defaultPlaybackRate(1.0f)
, m_sendProgressEvents(true)
, m_isFullscreen(false)
, m_closedCaptionsVisible(false)
- , m_mouseOver(false)
#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
, m_needWidgetUpdate(false)
#endif
return;
}
- if (isFullscreen())
- startHideFullscreenControlsTimer();
-
playInternal();
}
return;
scheduleTimeupdateEvent(true);
- if (hasMediaControls()) {
- if (!m_mouseOver && controls() && hasVideo())
- mediaControls()->makeTransparent();
+ if (hasMediaControls())
mediaControls()->playbackProgressed();
- }
// FIXME: deal with cue ranges here
}
-void HTMLMediaElement::startHideFullscreenControlsTimer()
-{
- if (!isFullscreen())
- return;
-
- m_hideFullscreenControlsTimer.startOneShot(timeWithoutMouseMovementBeforeHidingControls);
-}
-
-void HTMLMediaElement::hideFullscreenControlsTimerFired(Timer<HTMLMediaElement>*)
-{
- if (!m_playing)
- return;
-
- if (!isFullscreen())
- return;
-
- if (!controls() || !hasMediaControls())
- return;
-
- if (!mediaControls()->shouldHideControls())
- return;
-
- mediaControls()->makeTransparent();
-}
-
-void HTMLMediaElement::stopHideFullscreenControlsTimer()
-{
- m_hideFullscreenControlsTimer.stop();
-}
-
void HTMLMediaElement::scheduleTimeupdateEvent(bool periodicEvent)
{
double now = WTF::currentTime();
if (widget)
widget->handleEvent(event);
#else
- if (event->isMouseEvent()) {
- MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
- if (mouseEvent->relatedTarget() != this) {
- if (event->type() == eventNames().mouseoverEvent) {
- m_mouseOver = true;
- if (hasMediaControls() && controls() && !canPlay()) {
- mediaControls()->makeOpaque();
- if (mediaControls()->shouldHideControls())
- startHideFullscreenControlsTimer();
- }
- } else if (event->type() == eventNames().mouseoutEvent) {
- m_mouseOver = false;
- stopHideFullscreenControlsTimer();
- } else if (event->type() == eventNames().mousemoveEvent) {
- if (isFullscreen() && hasMediaControls() && controls()) {
- // When we get a mouse move in fullscreen mode, show the media controls, and start a timer
- // that will hide the media controls after a 3 seconds without a mouse move.
- mediaControls()->makeOpaque();
- if (mediaControls()->shouldHideControls())
- startHideFullscreenControlsTimer();
- }
- }
-
- }
- }
-
HTMLElement::defaultEventHandler(event);
#endif
}
void HTMLMediaElement::enterFullscreen()
{
LOG(Media, "HTMLMediaElement::enterFullscreen");
-
- startHideFullscreenControlsTimer();
-
+
#if ENABLE(FULLSCREEN_API)
if (document() && document()->settings() && document()->settings()->fullScreenEnabled()) {
document()->requestFullScreenForElement(this, 0, Document::ExemptIFrameAllowFulScreenRequirement);
void HTMLMediaElement::exitFullscreen()
{
LOG(Media, "HTMLMediaElement::exitFullscreen");
-
- stopHideFullscreenControlsTimer();
-
+
#if ENABLE(FULLSCREEN_API)
if (document() && document()->settings() && document()->settings()->fullScreenEnabled()) {
if (document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == this)
/*
- * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
void beginScrubbing();
void endScrubbing();
- void stopHideFullscreenControlsTimer();
-
bool canPlay() const;
float percentLoaded() const;
static void clearMediaCache();
static void clearMediaCacheForSite(const String&);
+ bool isPlaying() const { return m_playing; }
+
protected:
HTMLMediaElement(const QualifiedName&, Document*);
virtual ~HTMLMediaElement();
void asyncEventTimerFired(Timer<HTMLMediaElement>*);
void progressEventTimerFired(Timer<HTMLMediaElement>*);
void playbackProgressTimerFired(Timer<HTMLMediaElement>*);
- void hideFullscreenControlsTimerFired(Timer<HTMLMediaElement>*);
void startPlaybackProgressTimer();
void startProgressEventTimer();
- void startHideFullscreenControlsTimer();
void stopPeriodicTimers();
void seek(float time, ExceptionCode&);
Timer<HTMLMediaElement> m_asyncEventTimer;
Timer<HTMLMediaElement> m_progressEventTimer;
Timer<HTMLMediaElement> m_playbackProgressTimer;
- Timer<HTMLMediaElement> m_hideFullscreenControlsTimer;
Vector<RefPtr<Event> > m_pendingEvents;
RefPtr<TimeRanges> m_playedTimeRanges;
bool m_isFullscreen : 1;
bool m_closedCaptionsVisible : 1;
- bool m_mouseOver : 1;
#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
bool m_needWidgetUpdate : 1;
/*
- * Copyright (C) 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
{
}
-void* MediaControlElement::preDispatchEventHandler(Event* event)
-{
- if (event->type() == eventNames().clickEvent) {
- event->preventDefault();
- event->stopPropagation();
- }
- return 0;
-}
-
static const String& displayString()
{
DEFINE_STATIC_LOCAL(String, s, ("display"));
return new (arena) RenderMediaVolumeSliderContainer(this);
}
-void* MediaControlVolumeSliderContainerElement::preDispatchEventHandler(Event* event)
+void MediaControlVolumeSliderContainerElement::defaultEventHandler(Event* event)
{
if (!event->isMouseEvent() || event->type() != eventNames().mouseoutEvent)
- return 0;
+ return;
// Poor man's mouseleave event detection.
MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
if (!mouseEvent->relatedTarget() || !mouseEvent->relatedTarget()->toNode())
- return 0;
+ return;
if (this->containsIncludingShadowDOM(mouseEvent->relatedTarget()->toNode()))
- return 0;
+ return;
hide();
- return 0;
}
{
}
-void* MediaControlMuteButtonElement::preDispatchEventHandler(Event* event)
+void MediaControlMuteButtonElement::defaultEventHandler(Event* event)
{
if (event->type() == eventNames().clickEvent) {
mediaElement()->setMuted(!mediaElement()->muted());
- event->preventDefault();
- event->stopPropagation();
+ event->setDefaultHandled();
}
- return 0;
+ HTMLInputElement::defaultEventHandler(event);
}
void MediaControlMuteButtonElement::changedMute()
return button.release();
}
-void* MediaControlPanelMuteButtonElement::preDispatchEventHandler(Event* event)
+void MediaControlPanelMuteButtonElement::defaultEventHandler(Event* event)
{
if (event->type() == eventNames().mouseoverEvent)
m_controls->showVolumeSlider();
- return 0;
+ MediaControlMuteButtonElement::defaultEventHandler(event);
}
const AtomicString& MediaControlPanelMuteButtonElement::shadowPseudoId() const
return button.release();
}
-void* MediaControlPlayButtonElement::preDispatchEventHandler(Event* event)
+void MediaControlPlayButtonElement::defaultEventHandler(Event* event)
{
if (event->type() == eventNames().clickEvent) {
mediaElement()->togglePlayState();
updateDisplayType();
- event->preventDefault();
- event->stopPropagation();
+ event->setDefaultHandled();
}
- return 0;
+ HTMLInputElement::defaultEventHandler(event);
}
void MediaControlPlayButtonElement::updateDisplayType()
{
}
-void* MediaControlSeekButtonElement::preDispatchEventHandler(Event* event)
+void MediaControlSeekButtonElement::defaultEventHandler(Event* event)
{
if (event->type() == eventNames().mousedownEvent) {
if (Frame* frame = document()->frame()) {
}
mediaElement()->pause(event->fromUserGesture());
m_seekTimer.startRepeating(cSeekRepeatDelay);
- event->preventDefault();
- event->stopPropagation();
+ event->setDefaultHandled();
} else if (event->type() == eventNames().mouseupEvent) {
if (m_capturing)
if (Frame* frame = document()->frame()) {
}
m_seekTimer.stop();
m_seeking = false;
- event->preventDefault();
- event->stopPropagation();
+ event->setDefaultHandled();
}
}
- return 0;
+ HTMLInputElement::defaultEventHandler(event);
}
void MediaControlSeekButtonElement::seekTimerFired(Timer<MediaControlSeekButtonElement>*)
return button.release();
}
-void* MediaControlRewindButtonElement::preDispatchEventHandler(Event* event)
+void MediaControlRewindButtonElement::defaultEventHandler(Event* event)
{
if (event->type() == eventNames().clickEvent) {
mediaElement()->rewind(30);
- event->preventDefault();
- event->stopPropagation();
+ event->setDefaultHandled();
}
- return 0;
+ HTMLInputElement::defaultEventHandler(event);
}
const AtomicString& MediaControlRewindButtonElement::shadowPseudoId() const
return button.release();
}
-void* MediaControlReturnToRealtimeButtonElement::preDispatchEventHandler(Event* event)
+void MediaControlReturnToRealtimeButtonElement::defaultEventHandler(Event* event)
{
if (event->type() == eventNames().clickEvent) {
mediaElement()->returnToRealtime();
- event->preventDefault();
- event->stopPropagation();
+ event->setDefaultHandled();
}
- return 0;
+ HTMLInputElement::defaultEventHandler(event);
}
const AtomicString& MediaControlReturnToRealtimeButtonElement::shadowPseudoId() const
return button.release();
}
-void* MediaControlToggleClosedCaptionsButtonElement::preDispatchEventHandler(Event* event)
+void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event)
{
if (event->type() == eventNames().clickEvent) {
mediaElement()->setClosedCaptionsVisible(!mediaElement()->closedCaptionsVisible());
setChecked(mediaElement()->closedCaptionsVisible());
updateDisplayType();
- event->preventDefault();
- event->stopPropagation();
+ event->setDefaultHandled();
}
- return 0;
+ HTMLInputElement::defaultEventHandler(event);
}
void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType()
return timeline.release();
}
-void* MediaControlTimelineElement::preDispatchEventHandler(Event* event)
+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 0;
+ return;
if (!attached())
- return 0;
+ return;
if (event->type() == eventNames().mousedownEvent)
mediaElement()->beginScrubbing();
+ if (event->type() == eventNames().mouseupEvent)
+ mediaElement()->endScrubbing();
+
MediaControlInputElement::defaultEventHandler(event);
if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
- return 0;
+ return;
float time = narrowPrecisionToFloat(value().toDouble());
if (time != mediaElement()->currentTime()) {
RenderSlider* slider = toRenderSlider(renderer());
if (slider && slider->inDragMode())
m_controls->updateTimeDisplay();
-
- if (event->type() == eventNames().mouseupEvent)
- mediaElement()->endScrubbing();
- return 0;
}
void MediaControlTimelineElement::setPosition(float currentTime)
return slider.release();
}
-void* MediaControlVolumeSliderElement::preDispatchEventHandler(Event* event)
+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 0;
+ return;
if (!attached())
- return 0;
+ return;
MediaControlInputElement::defaultEventHandler(event);
if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
- return 0;
+ return;
float volume = narrowPrecisionToFloat(value().toDouble());
if (volume != mediaElement()->volume()) {
mediaElement()->setVolume(volume, ec);
ASSERT(!ec);
}
- return 0;
}
void MediaControlVolumeSliderElement::setVolume(float volume)
return button.release();
}
-void* MediaControlFullscreenButtonElement::preDispatchEventHandler(Event* event)
+void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event)
{
if (event->type() == eventNames().clickEvent) {
#if ENABLE(FULLSCREEN_API)
} else
#endif
mediaElement()->enterFullscreen();
- event->preventDefault();
- event->stopPropagation();
+ event->setDefaultHandled();
}
- return 0;
+ HTMLInputElement::defaultEventHandler(event);
}
const AtomicString& MediaControlFullscreenButtonElement::shadowPseudoId() const
return button.release();
}
-void* MediaControlFullscreenVolumeMinButtonElement::preDispatchEventHandler(Event* event)
+void MediaControlFullscreenVolumeMinButtonElement::defaultEventHandler(Event* event)
{
if (event->type() == eventNames().clickEvent) {
ExceptionCode code = 0;
mediaElement()->setVolume(0, code);
- event->preventDefault();
- event->stopPropagation();
+ event->setDefaultHandled();
}
- return 0;
+ HTMLInputElement::defaultEventHandler(event);
}
const AtomicString& MediaControlFullscreenVolumeMinButtonElement::shadowPseudoId() const
return button.release();
}
-void* MediaControlFullscreenVolumeMaxButtonElement::preDispatchEventHandler(Event* event)
+void MediaControlFullscreenVolumeMaxButtonElement::defaultEventHandler(Event* event)
{
if (event->type() == eventNames().clickEvent) {
ExceptionCode code = 0;
mediaElement()->setVolume(1, code);
- event->preventDefault();
- event->stopPropagation();
+ event->setDefaultHandled();
}
- return 0;
+ HTMLInputElement::defaultEventHandler(event);
}
const AtomicString& MediaControlFullscreenVolumeMaxButtonElement::shadowPseudoId() const
/*
- * Copyright (C) 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
MediaControlElement(HTMLMediaElement*);
private:
- virtual void *preDispatchEventHandler(Event*);
virtual bool isMediaControlElement() const { return true; }
HTMLMediaElement* m_mediaElement;
private:
MediaControlVolumeSliderContainerElement(HTMLMediaElement*);
virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
- virtual void *preDispatchEventHandler(Event*);
+ virtual void defaultEventHandler(Event*);
virtual MediaControlElementType displayType() const;
virtual const AtomicString& shadowPseudoId() const;
};
protected:
MediaControlMuteButtonElement(HTMLMediaElement*, MediaControlElementType);
- virtual void *preDispatchEventHandler(Event*);
+ virtual void defaultEventHandler(Event*);
private:
private:
MediaControlPanelMuteButtonElement(HTMLMediaElement*, MediaControls*);
- virtual void *preDispatchEventHandler(Event*);
+ virtual void defaultEventHandler(Event*);
virtual const AtomicString& shadowPseudoId() const;
MediaControls* m_controls;
public:
static PassRefPtr<MediaControlPlayButtonElement> create(HTMLMediaElement*);
- virtual void *preDispatchEventHandler(Event*);
+ virtual void defaultEventHandler(Event*);
virtual void updateDisplayType();
private:
class MediaControlSeekButtonElement : public MediaControlInputElement {
public:
- virtual void *preDispatchEventHandler(Event*);
+ virtual void defaultEventHandler(Event*);
protected:
MediaControlSeekButtonElement(HTMLMediaElement*, MediaControlElementType);
public:
static PassRefPtr<MediaControlRewindButtonElement> create(HTMLMediaElement*);
- virtual void *preDispatchEventHandler(Event*);
+ virtual void defaultEventHandler(Event*);
private:
MediaControlRewindButtonElement(HTMLMediaElement*);
public:
static PassRefPtr<MediaControlReturnToRealtimeButtonElement> create(HTMLMediaElement*);
- virtual void *preDispatchEventHandler(Event*);
+ virtual void defaultEventHandler(Event*);
private:
MediaControlReturnToRealtimeButtonElement(HTMLMediaElement*);
public:
static PassRefPtr<MediaControlToggleClosedCaptionsButtonElement> create(HTMLMediaElement*);
- virtual void *preDispatchEventHandler(Event*);
+ virtual void defaultEventHandler(Event*);
virtual void updateDisplayType();
private:
public:
static PassRefPtr<MediaControlTimelineElement> create(HTMLMediaElement*, MediaControls*);
- virtual void *preDispatchEventHandler(Event*);
+ virtual void defaultEventHandler(Event*);
void setPosition(float);
void setDuration(float);
public:
static PassRefPtr<MediaControlVolumeSliderElement> create(HTMLMediaElement*);
- virtual void *preDispatchEventHandler(Event*);
+ virtual void defaultEventHandler(Event*);
void setVolume(float);
protected:
public:
static PassRefPtr<MediaControlFullscreenButtonElement> create(HTMLMediaElement*, MediaControls*);
- virtual void *preDispatchEventHandler(Event*);
+ virtual void defaultEventHandler(Event*);
private:
MediaControlFullscreenButtonElement(HTMLMediaElement*, MediaControls*);
public:
static PassRefPtr<MediaControlFullscreenVolumeMinButtonElement> create(HTMLMediaElement*);
- virtual void *preDispatchEventHandler(Event*);
+ virtual void defaultEventHandler(Event*);
private:
MediaControlFullscreenVolumeMinButtonElement(HTMLMediaElement*);
public:
static PassRefPtr<MediaControlFullscreenVolumeMaxButtonElement> create(HTMLMediaElement*);
- virtual void *preDispatchEventHandler(Event*);
+ virtual void defaultEventHandler(Event*);
private:
MediaControlFullscreenVolumeMaxButtonElement(HTMLMediaElement*);
/*
- * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
* Copyright (C) 2011 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#include "MediaControlRootElement.h"
#include "MediaControlElements.h"
+#include "MouseEvent.h"
#include "Page.h"
#include "RenderTheme.h"
namespace WebCore {
+static const double timeWithoutMouseMovementBeforeHidingControls = 3;
+
MediaControlRootElement::MediaControlRootElement(HTMLMediaElement* mediaElement)
: MediaControls(mediaElement)
, m_mediaElement(mediaElement)
, m_fullScreenMaxVolumeButton(0)
, m_panel(0)
, m_opaque(true)
+ , m_isMouseOverControls(false)
+ , m_hideFullscreenControlsTimer(this, &MediaControlRootElement::hideFullscreenControlsTimerFired)
{
}
m_playButton->updateDisplayType();
m_timeline->setPosition(m_mediaElement->currentTime());
updateTimeDisplay();
+
+ if (m_mediaElement->isFullscreen())
+ startHideFullscreenControlsTimer();
}
void MediaControlRootElement::playbackProgressed()
{
m_timeline->setPosition(m_mediaElement->currentTime());
updateTimeDisplay();
+
+ if (!m_isMouseOverControls && m_mediaElement->hasVideo())
+ makeTransparent();
}
void MediaControlRootElement::playbackStopped()
updateTimeDisplay();
makeOpaque();
- m_mediaElement->stopHideFullscreenControlsTimer();
+ stopHideFullscreenControlsTimer();
}
void MediaControlRootElement::updateTimeDisplay()
m_rewindButton->hide();
m_returnToRealTimeButton->hide();
}
+
+ startHideFullscreenControlsTimer();
}
void MediaControlRootElement::exitedFullscreen()
m_seekBackButton->show();
m_seekForwardButton->show();
m_returnToRealTimeButton->show();
+
+ stopHideFullscreenControlsTimer();
}
void MediaControlRootElement::showVolumeSlider()
return !m_panel->hovered();
}
+bool MediaControlRootElement::containsRelatedTarget(Event* event)
+{
+ if (!event->isMouseEvent())
+ return false;
+ EventTarget* relatedTarget = static_cast<MouseEvent*>(event)->relatedTarget();
+ if (!relatedTarget)
+ return false;
+ return contains(relatedTarget->toNode());
+}
+
+void MediaControlRootElement::defaultEventHandler(Event* event)
+{
+ MediaControls::defaultEventHandler(event);
+
+ if (event->type() == eventNames().mouseoverEvent) {
+ if (!containsRelatedTarget(event)) {
+ m_isMouseOverControls = true;
+ if (!m_mediaElement->canPlay()) {
+ makeOpaque();
+ if (shouldHideControls())
+ startHideFullscreenControlsTimer();
+ }
+ }
+ } else if (event->type() == eventNames().mouseoutEvent) {
+ if (!containsRelatedTarget(event)) {
+ m_isMouseOverControls = false;
+ stopHideFullscreenControlsTimer();
+ }
+ } else if (event->type() == eventNames().mousemoveEvent) {
+ if (m_mediaElement->isFullscreen()) {
+ // When we get a mouse move in fullscreen mode, show the media controls, and start a timer
+ // that will hide the media controls after a 3 seconds without a mouse move.
+ makeOpaque();
+ if (shouldHideControls())
+ startHideFullscreenControlsTimer();
+ }
+ }
+}
+
+void MediaControlRootElement::startHideFullscreenControlsTimer()
+{
+ if (!m_mediaElement->isFullscreen())
+ return;
+
+ m_hideFullscreenControlsTimer.startOneShot(timeWithoutMouseMovementBeforeHidingControls);
+}
+
+void MediaControlRootElement::hideFullscreenControlsTimerFired(Timer<MediaControlRootElement>*)
+{
+ if (!m_mediaElement->isPlaying())
+ return;
+
+ if (!m_mediaElement->isFullscreen())
+ return;
+
+ if (!shouldHideControls())
+ return;
+
+ makeTransparent();
+}
+
+void MediaControlRootElement::stopHideFullscreenControlsTimer()
+{
+ m_hideFullscreenControlsTimer.stop();
+}
+
const AtomicString& MediaControlRootElement::shadowPseudoId() const
{
DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls"));
/*
- * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
* Copyright (C) 2011 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
void updateStatusDisplay();
virtual bool shouldHideControls();
+
private:
MediaControlRootElement(HTMLMediaElement*);
+ virtual void defaultEventHandler(Event*);
+ void hideFullscreenControlsTimerFired(Timer<MediaControlRootElement>*);
+ void startHideFullscreenControlsTimer();
+ void stopHideFullscreenControlsTimer();
+
virtual const AtomicString& shadowPseudoId() const;
+ bool containsRelatedTarget(Event*);
+
HTMLMediaElement* m_mediaElement;
MediaControlRewindButtonElement* m_rewindButton;
MediaControlFullscreenVolumeSliderElement* m_fullScreenVolumeSlider;
MediaControlFullscreenVolumeMaxButtonElement* m_fullScreenMaxVolumeButton;
MediaControlPanelElement* m_panel;
-
bool m_opaque;
+ bool m_isMouseOverControls;
+ Timer<MediaControlRootElement> m_hideFullscreenControlsTimer;
};
}