2009-02-09 Eric Carlson <eric.carlson@apple.com>
authoreric.carlson@apple.com <eric.carlson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 9 Feb 2009 19:48:27 +0000 (19:48 +0000)
committereric.carlson@apple.com <eric.carlson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 9 Feb 2009 19:48:27 +0000 (19:48 +0000)
        Reviewed by Antti Koivisto

        https://bugs.webkit.org/show_bug.cgi?id=23737
        Make it possible to control media element playback without knowing so many
        internal implementation details.

        * html/HTMLMediaElement.cpp:
        (WebCore::HTMLMediaElement::togglePlayState): New, toggle between playing and paused state.
        (WebCore::HTMLMediaElement::beginScrubbing): New, pause as necessary for scrubbing mode.
        (WebCore::HTMLMediaElement::endScrubbing): New, resume playback if paused for scrubbing mode.
        * html/HTMLMediaElement.h:

        (WebCore::HTMLMediaElement::hasVideo): New, added so clients don't need to access MediaPlayer directly.
        * html/HTMLVideoElement.h:

        (WebCore::HTMLVideoElement::hasVideo): New.

        * rendering/MediaControlElements.cpp:
        (WebCore::MediaControlPlayButtonElement::defaultEventHandler): Use new media element
        togglePlayState method.
        (WebCore::MediaControlTimelineElement::defaultEventHandler): Tell media element when scrubbing
        begins and ends so it can deal with pausing logic. Don't call setCurrentTime unless the time
        will change.

        * rendering/RenderMedia.cpp:
        (WebCore::RenderMedia::updateControls): Ask media element if it is able to play instead of including
        internal logic here.
        (WebCore::RenderMedia::updateControlVisibility): Ditto.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@40789 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebCore/ChangeLog
WebCore/html/HTMLMediaElement.cpp
WebCore/html/HTMLMediaElement.h
WebCore/html/HTMLVideoElement.h
WebCore/rendering/MediaControlElements.cpp
WebCore/rendering/RenderMedia.cpp

index ae25fab31838e2c3c2b6454801991bd1da2b4f65..a726f7bd2525b5fc5ea658a74302658e160b8e55 100644 (file)
@@ -1,3 +1,34 @@
+2009-02-09  Eric Carlson  <eric.carlson@apple.com>
+
+        Reviewed by Antti Koivisto
+        
+        https://bugs.webkit.org/show_bug.cgi?id=23737
+        Make it possible to control media element playback without knowing so many
+        internal implementation details.
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::togglePlayState): New, toggle between playing and paused state.
+        (WebCore::HTMLMediaElement::beginScrubbing): New, pause as necessary for scrubbing mode.
+        (WebCore::HTMLMediaElement::endScrubbing): New, resume playback if paused for scrubbing mode.
+        * html/HTMLMediaElement.h:
+
+        (WebCore::HTMLMediaElement::hasVideo): New, added so clients don't need to access MediaPlayer directly.
+        * html/HTMLVideoElement.h:
+
+        (WebCore::HTMLVideoElement::hasVideo): New.
+
+        * rendering/MediaControlElements.cpp:
+        (WebCore::MediaControlPlayButtonElement::defaultEventHandler): Use new media element 
+        togglePlayState method.
+        (WebCore::MediaControlTimelineElement::defaultEventHandler): Tell media element when scrubbing
+        begins and ends so it can deal with pausing logic. Don't call setCurrentTime unless the time
+        will change.
+
+        * rendering/RenderMedia.cpp:
+        (WebCore::RenderMedia::updateControls): Ask media element if it is able to play instead of including
+        internal logic here.
+        (WebCore::RenderMedia::updateControlVisibility): Ditto.
+
 2009-02-09  Eric Carlson  <eric.carlson@apple.com>
 
         Reviewed by Antti Koivisto
 2009-02-09  Eric Carlson  <eric.carlson@apple.com>
 
         Reviewed by Antti Koivisto
index d7ee70d2d2db916b7dbadb13eebcf0cb4bdf2ba1..3d2edc5e068d743a13b1460c0a07152cf49b5e32 100644 (file)
@@ -807,6 +807,39 @@ void HTMLMediaElement::setMuted(bool muted)
     }
 }
 
     }
 }
 
+void HTMLMediaElement::togglePlayState(ExceptionCode& ec)
+{
+    if (canPlay())
+        play(ec);
+    else 
+        pause(ec);
+}
+
+void HTMLMediaElement::beginScrubbing()
+{
+    if (!paused()) {
+        if (ended()) {
+            // because a media element stays in non-paused state when it reaches end, playback resumes 
+            //  when the slider is dragged from the end to another position unless we pause first. do 
+            //  a "hard pause" so an event is generated, since we want to stay paused after scrubbing finishes
+            ExceptionCode ec;
+            pause(ec);
+        } else {
+            // not at the end but we still want to pause playback so the media engine doesn't try to
+            //  continue playing during scrubbing. pause without generating an event as we will 
+            //  unpause after scrubbing finishes
+            setPausedInternal(true);
+        }
+    }
+}
+
+void HTMLMediaElement::endScrubbing()
+{
+    if (m_pausedInternal) {
+        setPausedInternal(false);
+    }
+}
+
 bool HTMLMediaElement::canPlay() const
 {
     return paused() || ended() || networkState() < LOADED_METADATA;
 bool HTMLMediaElement::canPlay() const
 {
     return paused() || ended() || networkState() < LOADED_METADATA;
index 6dd562cbe74edd301a1d7dff0446fabb247382dd..a70dd7ddaae16db729b072ed21347f5f280ffef3 100644 (file)
@@ -58,6 +58,7 @@ public:
     MediaPlayer* player() const { return m_player.get(); }
     
     virtual bool isVideo() const { return false; }
     MediaPlayer* player() const { return m_player.get(); }
     
     virtual bool isVideo() const { return false; }
+    virtual bool hasVideo() const { return false; }
     
     void scheduleLoad();
     
     
     void scheduleLoad();
     
@@ -126,6 +127,9 @@ public:
     void setVolume(float, ExceptionCode&);
     bool muted() const;
     void setMuted(bool);
     void setVolume(float, ExceptionCode&);
     bool muted() const;
     void setMuted(bool);
+    void togglePlayState(ExceptionCode& ec);
+    void beginScrubbing();
+    void endScrubbing();
 
     bool canPlay() const;
 
 
     bool canPlay() const;
 
index 8779c85d1e93ec52075f616a9a6e6ef6ae0002c5..e543ab40a384f1397bf943357c8570b6a58e0d42 100644 (file)
@@ -47,6 +47,7 @@ public:
     virtual void detach();
     virtual void parseMappedAttribute(MappedAttribute* attr);
     virtual bool isVideo() const { return true; }
     virtual void detach();
     virtual void parseMappedAttribute(MappedAttribute* attr);
     virtual bool isVideo() const { return true; }
+    virtual bool hasVideo() const { return player() && player()->hasVideo(); }
     virtual bool isURLAttribute(Attribute*) const;
     virtual const QualifiedName& imageSourceAttributeName() const;
 
     virtual bool isURLAttribute(Attribute*) const;
     virtual const QualifiedName& imageSourceAttributeName() const;
 
index dc3dce013621eb7b65ca5fc5838811d9cc3e65ca..489a87b94608df4f436a96d4fdf3a8964dd34a2c 100644 (file)
@@ -166,10 +166,7 @@ void MediaControlPlayButtonElement::defaultEventHandler(Event* event)
 {
     if (event->type() == eventNames().clickEvent) {
         ExceptionCode ec;
 {
     if (event->type() == eventNames().clickEvent) {
         ExceptionCode ec;
-        if (m_mediaElement->canPlay())
-            m_mediaElement->play(ec);
-        else 
-            m_mediaElement->pause(ec);
+        m_mediaElement->togglePlayState(ec);
         event->setDefaultHandled();
     }
     HTMLInputElement::defaultEventHandler(event);
         event->setDefaultHandled();
     }
     HTMLInputElement::defaultEventHandler(event);
@@ -235,33 +232,27 @@ MediaControlTimelineElement::MediaControlTimelineElement(Document* doc, HTMLMedi
 
 void MediaControlTimelineElement::defaultEventHandler(Event* event)
 {
 
 void MediaControlTimelineElement::defaultEventHandler(Event* event)
 {
-    RenderSlider* slider = static_cast<RenderSlider*>(renderer());
-    bool oldInDragMode = slider && slider->inDragMode();
-    float oldTime = narrowPrecisionToFloat(value().toDouble());
-    bool oldEnded = m_mediaElement->ended();
+    if (event->type() == eventNames().mousedownEvent)
+        m_mediaElement->beginScrubbing();
 
     HTMLInputElement::defaultEventHandler(event);
 
 
     HTMLInputElement::defaultEventHandler(event);
 
-    float time = narrowPrecisionToFloat(value().toDouble());
-    if (oldTime != time || event->type() == eventNames().inputEvent) {
-        ExceptionCode ec;
-        m_mediaElement->setCurrentTime(time, ec);
+     if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent ) {
+        return;
     }
 
     }
 
-    // Media element stays in non-paused state when it reaches end. If the slider is now dragged
-    // to some other position the playback resumes which does not match usual media player UIs.
-    // Get the expected behavior by pausing explicitly in this case.
-    if (oldEnded && !m_mediaElement->ended() && !m_mediaElement->paused()) {
+    float time = narrowPrecisionToFloat(value().toDouble());
+    if (time != m_mediaElement->currentTime()) {
         ExceptionCode ec;
         ExceptionCode ec;
-        m_mediaElement->pause(ec);
+        m_mediaElement->setCurrentTime(time, ec);
     }
 
     }
 
-    // Pause playback during drag, but do it without using DOM API which would generate events 
-    bool inDragMode = slider && slider->inDragMode();
-    if (inDragMode != oldInDragMode)
-        m_mediaElement->setPausedInternal(inDragMode);
-    if (inDragMode)
+    RenderSlider* slider = static_cast<RenderSlider*>(renderer());
+    if (slider && slider->inDragMode())
         static_cast<RenderMedia*>(m_mediaElement->renderer())->updateTimeDisplay();
         static_cast<RenderMedia*>(m_mediaElement->renderer())->updateTimeDisplay();
+
+    if (event->type() == eventNames().mouseupEvent)
+        m_mediaElement->endScrubbing();
 }
 
 void MediaControlTimelineElement::update(bool updateDuration) 
 }
 
 void MediaControlTimelineElement::update(bool updateDuration) 
index daab23fed97bb5fe1412b2b49da6fbe0fbfe825f..f4b42174ea9b949aa6fff39d980d83a5e2c066fb 100644 (file)
@@ -279,7 +279,7 @@ void RenderMedia::updateControls()
         createFullscreenButton();
     }
 
         createFullscreenButton();
     }
 
-    if (media->paused() || media->ended() || media->networkState() < HTMLMediaElement::LOADED_METADATA) {
+    if (media->canPlay()) {
         if (m_timeUpdateTimer.isActive())
             m_timeUpdateTimer.stop();
     } else if (style()->visibility() == VISIBLE && m_timeline && m_timeline->renderer() && m_timeline->renderer()->style()->display() != NONE ) {
         if (m_timeUpdateTimer.isActive())
             m_timeUpdateTimer.stop();
     } else if (style()->visibility() == VISIBLE && m_timeline && m_timeline->renderer() && m_timeline->renderer()->style()->display() != NONE ) {
@@ -351,11 +351,11 @@ void RenderMedia::updateControlVisibility()
 
     // Don't fade for audio controls.
     HTMLMediaElement* media = mediaElement();
 
     // Don't fade for audio controls.
     HTMLMediaElement* media = mediaElement();
-    if (player() && !player()->hasVideo() || !media->isVideo())
+    if (!media->hasVideo())
         return;
 
     // do fading manually, css animations don't work well with shadow trees
         return;
 
     // do fading manually, css animations don't work well with shadow trees
-    bool visible = style()->visibility() == VISIBLE && (m_mouseOver || media->paused() || media->ended() || media->networkState() < HTMLMediaElement::LOADED_METADATA);
+    bool visible = style()->visibility() == VISIBLE && (m_mouseOver || media->canPlay());
     if (visible == (m_opacityAnimationTo > 0))
         return;
 
     if (visible == (m_opacityAnimationTo > 0))
         return;