2011-05-30 Jer Noble <jer.noble@apple.com>
authordarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 30 May 2011 17:09:48 +0000 (17:09 +0000)
committerdarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 30 May 2011 17:09:48 +0000 (17:09 +0000)
        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

Source/WebCore/ChangeLog
Source/WebCore/dom/EventDispatcher.cpp
Source/WebCore/dom/EventDispatcher.h
Source/WebCore/html/HTMLMediaElement.cpp
Source/WebCore/html/HTMLMediaElement.h
Source/WebCore/html/shadow/MediaControlElements.cpp
Source/WebCore/html/shadow/MediaControlElements.h
Source/WebCore/html/shadow/MediaControlRootElement.cpp
Source/WebCore/html/shadow/MediaControlRootElement.h

index 6431152..827c5ca 100644 (file)
@@ -1,3 +1,77 @@
+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.
index 2b57285..47eae8d 100644 (file)
@@ -2,7 +2,7 @@
  * 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;
@@ -235,8 +228,6 @@ EventDispatcher::EventDispatcher(Node* node)
 
 void EventDispatcher::ensureEventAncestors(Event* event)
 {
-    EventDispatchBehavior behavior = determineDispatchBehavior(event);
-
     if (!m_node->inDocument())
         return;
 
@@ -251,7 +242,7 @@ void EventDispatcher::ensureEventAncestors(Event* event)
     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();
@@ -375,8 +366,19 @@ const EventContext* EventDispatcher::topEventContext()
     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())
index 88e9756..3c9548b 100644 (file)
@@ -61,7 +61,7 @@ private:
     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();
 
index faace8d..b6dcbee 100644 (file)
@@ -123,7 +123,6 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* docum
     , 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)
@@ -165,7 +164,6 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* docum
     , m_sendProgressEvents(true)
     , m_isFullscreen(false)
     , m_closedCaptionsVisible(false)
-    , m_mouseOver(false)
 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
     , m_needWidgetUpdate(false)
 #endif
@@ -1426,9 +1424,6 @@ void HTMLMediaElement::play(bool isUserGesture)
             return;
     }
     
-    if (isFullscreen())
-        startHideFullscreenControlsTimer();
-    
     playInternal();
 }
 
@@ -1633,44 +1628,11 @@ void HTMLMediaElement::playbackProgressTimerFired(Timer<HTMLMediaElement>*)
         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();
@@ -2409,32 +2371,6 @@ void HTMLMediaElement::defaultEventHandler(Event* event)
     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
 }
@@ -2568,9 +2504,7 @@ bool HTMLMediaElement::isFullscreen() const
 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);
@@ -2590,9 +2524,7 @@ void HTMLMediaElement::enterFullscreen()
 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)
index c824e18..271639e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -147,8 +147,6 @@ public:
     void beginScrubbing();
     void endScrubbing();
     
-    void stopHideFullscreenControlsTimer();
-
     bool canPlay() const;
 
     float percentLoaded() const;
@@ -203,6 +201,8 @@ public:
     static void clearMediaCache();
     static void clearMediaCacheForSite(const String&);
 
+    bool isPlaying() const { return m_playing; }
+
 protected:
     HTMLMediaElement(const QualifiedName&, Document*);
     virtual ~HTMLMediaElement();
@@ -272,10 +272,8 @@ private:
     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&);
@@ -345,7 +343,6 @@ private:
     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;
 
@@ -421,7 +418,6 @@ private:
 
     bool m_isFullscreen : 1;
     bool m_closedCaptionsVisible : 1;
-    bool m_mouseOver : 1;
 
 #if ENABLE(PLUGIN_PROXY_FOR_VIDEO)
     bool m_needWidgetUpdate : 1;
index 5b11180..94cb3d6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -75,15 +75,6 @@ MediaControlElement::MediaControlElement(HTMLMediaElement* mediaElement)
 {
 }
 
-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"));
@@ -200,21 +191,20 @@ RenderObject* MediaControlVolumeSliderContainerElement::createRenderer(RenderAre
     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;
 }
 
 
@@ -330,15 +320,14 @@ inline MediaControlMuteButtonElement::MediaControlMuteButtonElement(HTMLMediaEle
 {
 }
 
-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()
@@ -368,12 +357,12 @@ PassRefPtr<MediaControlPanelMuteButtonElement> MediaControlPanelMuteButtonElemen
     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
@@ -416,15 +405,14 @@ PassRefPtr<MediaControlPlayButtonElement> MediaControlPlayButtonElement::create(
     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()
@@ -448,7 +436,7 @@ inline MediaControlSeekButtonElement::MediaControlSeekButtonElement(HTMLMediaEle
 {
 }
 
-void* MediaControlSeekButtonElement::preDispatchEventHandler(Event* event)
+void MediaControlSeekButtonElement::defaultEventHandler(Event* event)
 {
     if (event->type() == eventNames().mousedownEvent) {
         if (Frame* frame = document()->frame()) {
@@ -457,8 +445,7 @@ void* MediaControlSeekButtonElement::preDispatchEventHandler(Event* event)
         }
         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()) {
@@ -473,11 +460,10 @@ void* MediaControlSeekButtonElement::preDispatchEventHandler(Event* event)
             }
             m_seekTimer.stop();
             m_seeking = false;
-            event->preventDefault();
-            event->stopPropagation();
+            event->setDefaultHandled();
         }
     }
-    return 0;
+    HTMLInputElement::defaultEventHandler(event);
 }
 
 void MediaControlSeekButtonElement::seekTimerFired(Timer<MediaControlSeekButtonElement>*)
@@ -551,14 +537,13 @@ PassRefPtr<MediaControlRewindButtonElement> MediaControlRewindButtonElement::cre
     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
@@ -582,14 +567,13 @@ PassRefPtr<MediaControlReturnToRealtimeButtonElement> MediaControlReturnToRealti
     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
@@ -613,17 +597,16 @@ PassRefPtr<MediaControlToggleClosedCaptionsButtonElement> MediaControlToggleClos
     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()
@@ -655,22 +638,25 @@ PassRefPtr<MediaControlTimelineElement> MediaControlTimelineElement::create(HTML
     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()) {
@@ -682,10 +668,6 @@ void* MediaControlTimelineElement::preDispatchEventHandler(Event* event)
     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) 
@@ -722,19 +704,19 @@ PassRefPtr<MediaControlVolumeSliderElement> MediaControlVolumeSliderElement::cre
     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()) {
@@ -742,7 +724,6 @@ void* MediaControlVolumeSliderElement::preDispatchEventHandler(Event* event)
         mediaElement()->setVolume(volume, ec);
         ASSERT(!ec);
     }
-    return 0;
 }
 
 void MediaControlVolumeSliderElement::setVolume(float volume)
@@ -798,7 +779,7 @@ PassRefPtr<MediaControlFullscreenButtonElement> MediaControlFullscreenButtonElem
     return button.release();
 }
 
-void* MediaControlFullscreenButtonElement::preDispatchEventHandler(Event* event)
+void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event)
 {
     if (event->type() == eventNames().clickEvent) {
 #if ENABLE(FULLSCREEN_API)
@@ -815,10 +796,9 @@ void* MediaControlFullscreenButtonElement::preDispatchEventHandler(Event* event)
         } else
 #endif
             mediaElement()->enterFullscreen();
-        event->preventDefault();
-        event->stopPropagation();
+        event->setDefaultHandled();
     }
-    return 0;
+    HTMLInputElement::defaultEventHandler(event);
 }
 
 const AtomicString& MediaControlFullscreenButtonElement::shadowPseudoId() const
@@ -841,15 +821,14 @@ PassRefPtr<MediaControlFullscreenVolumeMinButtonElement> MediaControlFullscreenV
     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
@@ -872,15 +851,14 @@ PassRefPtr<MediaControlFullscreenVolumeMaxButtonElement> MediaControlFullscreenV
     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
index f75b448..ff8f461 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -87,7 +87,6 @@ protected:
     MediaControlElement(HTMLMediaElement*);
 
 private:
-    virtual void *preDispatchEventHandler(Event*);
     virtual bool isMediaControlElement() const { return true; }
 
     HTMLMediaElement* m_mediaElement;   
@@ -127,7 +126,7 @@ public:
 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;
 };
@@ -183,7 +182,7 @@ public:
 
 protected:
     MediaControlMuteButtonElement(HTMLMediaElement*, MediaControlElementType);
-    virtual void *preDispatchEventHandler(Event*);
+    virtual void defaultEventHandler(Event*);
 
 
 private:
@@ -199,7 +198,7 @@ public:
 private:
     MediaControlPanelMuteButtonElement(HTMLMediaElement*, MediaControls*);
 
-    virtual void *preDispatchEventHandler(Event*);
+    virtual void defaultEventHandler(Event*);
     virtual const AtomicString& shadowPseudoId() const;
 
     MediaControls* m_controls;
@@ -224,7 +223,7 @@ class MediaControlPlayButtonElement : public MediaControlInputElement {
 public:
     static PassRefPtr<MediaControlPlayButtonElement> create(HTMLMediaElement*);
 
-    virtual void *preDispatchEventHandler(Event*);
+    virtual void defaultEventHandler(Event*);
     virtual void updateDisplayType();
 
 private:
@@ -237,7 +236,7 @@ private:
 
 class MediaControlSeekButtonElement : public MediaControlInputElement {
 public:
-    virtual void *preDispatchEventHandler(Event*);
+    virtual void defaultEventHandler(Event*);
 
 protected:
     MediaControlSeekButtonElement(HTMLMediaElement*, MediaControlElementType);
@@ -285,7 +284,7 @@ class MediaControlRewindButtonElement : public MediaControlInputElement {
 public:
     static PassRefPtr<MediaControlRewindButtonElement> create(HTMLMediaElement*);
 
-    virtual void *preDispatchEventHandler(Event*);
+    virtual void defaultEventHandler(Event*);
 
 private:
     MediaControlRewindButtonElement(HTMLMediaElement*);
@@ -299,7 +298,7 @@ class MediaControlReturnToRealtimeButtonElement : public MediaControlInputElemen
 public:
     static PassRefPtr<MediaControlReturnToRealtimeButtonElement> create(HTMLMediaElement*);
 
-    virtual void *preDispatchEventHandler(Event*);
+    virtual void defaultEventHandler(Event*);
 
 private:
     MediaControlReturnToRealtimeButtonElement(HTMLMediaElement*);
@@ -313,7 +312,7 @@ class MediaControlToggleClosedCaptionsButtonElement : public MediaControlInputEl
 public:
     static PassRefPtr<MediaControlToggleClosedCaptionsButtonElement> create(HTMLMediaElement*);
 
-    virtual void *preDispatchEventHandler(Event*);
+    virtual void defaultEventHandler(Event*);
     virtual void updateDisplayType();
 
 private:
@@ -328,7 +327,7 @@ class MediaControlTimelineElement : public MediaControlInputElement {
 public:
     static PassRefPtr<MediaControlTimelineElement> create(HTMLMediaElement*, MediaControls*);
 
-    virtual void *preDispatchEventHandler(Event*);
+    virtual void defaultEventHandler(Event*);
     void setPosition(float);
     void setDuration(float);
 
@@ -346,7 +345,7 @@ class MediaControlVolumeSliderElement : public MediaControlInputElement {
 public:
     static PassRefPtr<MediaControlVolumeSliderElement> create(HTMLMediaElement*);
 
-    virtual void *preDispatchEventHandler(Event*);
+    virtual void defaultEventHandler(Event*);
     void setVolume(float);
 
 protected:
@@ -362,7 +361,7 @@ class MediaControlFullscreenButtonElement : public MediaControlInputElement {
 public:
     static PassRefPtr<MediaControlFullscreenButtonElement> create(HTMLMediaElement*, MediaControls*);
 
-    virtual void *preDispatchEventHandler(Event*);
+    virtual void defaultEventHandler(Event*);
 
 private:
     MediaControlFullscreenButtonElement(HTMLMediaElement*, MediaControls*);
@@ -390,7 +389,7 @@ class MediaControlFullscreenVolumeMinButtonElement : public MediaControlInputEle
 public:
     static PassRefPtr<MediaControlFullscreenVolumeMinButtonElement> create(HTMLMediaElement*);
     
-    virtual void *preDispatchEventHandler(Event*);
+    virtual void defaultEventHandler(Event*);
     
 private:
     MediaControlFullscreenVolumeMinButtonElement(HTMLMediaElement*);
@@ -404,7 +403,7 @@ class MediaControlFullscreenVolumeMaxButtonElement : public MediaControlInputEle
 public:
     static PassRefPtr<MediaControlFullscreenVolumeMaxButtonElement> create(HTMLMediaElement*);
     
-    virtual void *preDispatchEventHandler(Event*);
+    virtual void defaultEventHandler(Event*);
     
 private:
     MediaControlFullscreenVolumeMaxButtonElement(HTMLMediaElement*);
index e31f290..4458d4d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -30,6 +30,7 @@
 #include "MediaControlRootElement.h"
 
 #include "MediaControlElements.h"
+#include "MouseEvent.h"
 #include "Page.h"
 #include "RenderTheme.h"
 
@@ -37,6 +38,8 @@ using namespace std;
 
 namespace WebCore {
 
+static const double timeWithoutMouseMovementBeforeHidingControls = 3;
+
 MediaControlRootElement::MediaControlRootElement(HTMLMediaElement* mediaElement)
     : MediaControls(mediaElement)
     , m_mediaElement(mediaElement)
@@ -61,6 +64,8 @@ MediaControlRootElement::MediaControlRootElement(HTMLMediaElement* mediaElement)
     , m_fullScreenMaxVolumeButton(0)
     , m_panel(0)
     , m_opaque(true)
+    , m_isMouseOverControls(false)
+    , m_hideFullscreenControlsTimer(this, &MediaControlRootElement::hideFullscreenControlsTimerFired)
 {
 }
 
@@ -336,12 +341,18 @@ void MediaControlRootElement::playbackStarted()
     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()
@@ -351,7 +362,7 @@ void MediaControlRootElement::playbackStopped()
     updateTimeDisplay();
     makeOpaque();
     
-    m_mediaElement->stopHideFullscreenControlsTimer();
+    stopHideFullscreenControlsTimer();
 }
 
 void MediaControlRootElement::updateTimeDisplay()
@@ -437,6 +448,8 @@ void MediaControlRootElement::enteredFullscreen()
         m_rewindButton->hide();
         m_returnToRealTimeButton->hide();
     }
+
+    startHideFullscreenControlsTimer();
 }
 
 void MediaControlRootElement::exitedFullscreen()
@@ -448,6 +461,8 @@ void MediaControlRootElement::exitedFullscreen()
     m_seekBackButton->show();
     m_seekForwardButton->show();
     m_returnToRealTimeButton->show();
+
+    stopHideFullscreenControlsTimer();    
 }
 
 void MediaControlRootElement::showVolumeSlider()
@@ -464,6 +479,72 @@ bool MediaControlRootElement::shouldHideControls()
     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"));
index 7e0722f..78ce06f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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
@@ -97,11 +97,19 @@ public:
     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;
@@ -124,8 +132,9 @@ private:
     MediaControlFullscreenVolumeSliderElement* m_fullScreenVolumeSlider;
     MediaControlFullscreenVolumeMaxButtonElement* m_fullScreenMaxVolumeButton;
     MediaControlPanelElement* m_panel;
-
     bool m_opaque;
+    bool m_isMouseOverControls;
+    Timer<MediaControlRootElement> m_hideFullscreenControlsTimer;
 };
 
 }