<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[206350] trunk/Source</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/206350">206350</a></dd>
<dt>Author</dt> <dd>wenson_hsieh@apple.com</dd>
<dt>Date</dt> <dd>2016-09-23 18:38:52 -0700 (Fri, 23 Sep 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Media controls playhead does not animate smoothly while playing
https://bugs.webkit.org/show_bug.cgi?id=162399
&lt;rdar://problem/28115680&gt;

Reviewed by Beth Dakin.

Source/WebCore:

The media controls playhead currently does not animate smoothly during playback because we don't specify a
playback rate when updating the WebPlaybackControlsManager's timing value. However, simply setting this timing
value to the current playback rate (as known to the UI process) results in the UI process receiving multiple
updates from the web process where the current time is equal (or even less than) the time at which media began
to play, which results in the playhead seeking backwards to the start time multiple times when playing or
resuming media.

To address this, in WebCore, we inform the playback session model of the media time when playback begins (i.e.
a `playing` or `play` event is fired). This message precedes both the &quot;rate changed&quot; and &quot;current time changed&quot;
messages.

Unit tests to be added in a future patch.

* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::notifyAboutPlaying):
(WebCore::HTMLMediaElement::setReadyState):
(WebCore::HTMLMediaElement::playInternal):
* html/HTMLMediaElement.h:
(WebCore::HTMLMediaElement::playbackStartedTime):
* platform/cocoa/WebPlaybackSessionModel.h:
(WebCore::WebPlaybackSessionModelClient::playbackStartedTimeChanged):
(WebCore::WebPlaybackSessionModelClient::bufferedTimeChanged): Deleted.
* platform/cocoa/WebPlaybackSessionModelMediaElement.h:
* platform/cocoa/WebPlaybackSessionModelMediaElement.mm:
(WebPlaybackSessionModelMediaElement::updateForEventName):
(WebPlaybackSessionModelMediaElement::playbackStartedTime):
* platform/ios/WebVideoFullscreenControllerAVKit.mm:
* platform/mac/WebPlaybackSessionInterfaceMac.h:
* platform/mac/WebPlaybackSessionInterfaceMac.mm:
(WebCore::WebPlaybackSessionInterfaceMac::currentTimeChanged):
(WebCore::WebPlaybackSessionInterfaceMac::rateChanged):
(WebCore::WebPlaybackSessionInterfaceMac::beginScrubbing):
(WebCore::WebPlaybackSessionInterfaceMac::endScrubbing):
(WebCore::WebPlaybackSessionInterfaceMac::updatePlaybackControlsManagerTiming):

Source/WebKit2:

See WebCore ChangeLog for more details.

In the UI process, we update the WebPlaybackSessionManager's timing value when the rate or current time changes.
Each AVValueTiming is generated from the current time, system anchor time, and playback rate. The behavior of
the first two properties is unaffected. However, the rate used to update the timing value is the effective
playback rate, which is equal to the playback rate unless we are (1) not playing, (2) interacting with the media
controls in such a way that the media is essentially not playing, or (3) the current time precedes the playback
start time, accounting for playback direction. In these cases, our effective playback rate is 0, which means
that we do not animate the playhead.

* UIProcess/Cocoa/WebPlaybackSessionManagerProxy.h:
* UIProcess/Cocoa/WebPlaybackSessionManagerProxy.messages.in:
* UIProcess/Cocoa/WebPlaybackSessionManagerProxy.mm:
(WebKit::WebPlaybackSessionModelContext::beginScrubbing):
(WebKit::WebPlaybackSessionModelContext::endScrubbing):
(WebKit::WebPlaybackSessionModelContext::setPlaybackStartedTime):
(WebKit::WebPlaybackSessionModelContext::setCurrentTime):
(WebKit::WebPlaybackSessionManagerProxy::setPlaybackStartedTime):
* WebProcess/cocoa/WebPlaybackSessionManager.h:
* WebProcess/cocoa/WebPlaybackSessionManager.mm:
(WebKit::WebPlaybackSessionInterfaceContext::playbackStartedTimeChanged):
(WebKit::WebPlaybackSessionManager::playbackStartedTimeChanged):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorehtmlHTMLMediaElementcpp">trunk/Source/WebCore/html/HTMLMediaElement.cpp</a></li>
<li><a href="#trunkSourceWebCorehtmlHTMLMediaElementh">trunk/Source/WebCore/html/HTMLMediaElement.h</a></li>
<li><a href="#trunkSourceWebCoreplatformcocoaWebPlaybackSessionModelh">trunk/Source/WebCore/platform/cocoa/WebPlaybackSessionModel.h</a></li>
<li><a href="#trunkSourceWebCoreplatformcocoaWebPlaybackSessionModelMediaElementh">trunk/Source/WebCore/platform/cocoa/WebPlaybackSessionModelMediaElement.h</a></li>
<li><a href="#trunkSourceWebCoreplatformcocoaWebPlaybackSessionModelMediaElementmm">trunk/Source/WebCore/platform/cocoa/WebPlaybackSessionModelMediaElement.mm</a></li>
<li><a href="#trunkSourceWebCoreplatformiosWebVideoFullscreenControllerAVKitmm">trunk/Source/WebCore/platform/ios/WebVideoFullscreenControllerAVKit.mm</a></li>
<li><a href="#trunkSourceWebCoreplatformmacWebPlaybackSessionInterfaceMach">trunk/Source/WebCore/platform/mac/WebPlaybackSessionInterfaceMac.h</a></li>
<li><a href="#trunkSourceWebCoreplatformmacWebPlaybackSessionInterfaceMacmm">trunk/Source/WebCore/platform/mac/WebPlaybackSessionInterfaceMac.mm</a></li>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2UIProcessCocoaWebPlaybackSessionManagerProxyh">trunk/Source/WebKit2/UIProcess/Cocoa/WebPlaybackSessionManagerProxy.h</a></li>
<li><a href="#trunkSourceWebKit2UIProcessCocoaWebPlaybackSessionManagerProxymessagesin">trunk/Source/WebKit2/UIProcess/Cocoa/WebPlaybackSessionManagerProxy.messages.in</a></li>
<li><a href="#trunkSourceWebKit2UIProcessCocoaWebPlaybackSessionManagerProxymm">trunk/Source/WebKit2/UIProcess/Cocoa/WebPlaybackSessionManagerProxy.mm</a></li>
<li><a href="#trunkSourceWebKit2WebProcesscocoaWebPlaybackSessionManagerh">trunk/Source/WebKit2/WebProcess/cocoa/WebPlaybackSessionManager.h</a></li>
<li><a href="#trunkSourceWebKit2WebProcesscocoaWebPlaybackSessionManagermm">trunk/Source/WebKit2/WebProcess/cocoa/WebPlaybackSessionManager.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (206349 => 206350)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-09-24 01:18:52 UTC (rev 206349)
+++ trunk/Source/WebCore/ChangeLog        2016-09-24 01:38:52 UTC (rev 206350)
</span><span class="lines">@@ -1,3 +1,46 @@
</span><ins>+2016-09-23  Wenson Hsieh  &lt;wenson_hsieh@apple.com&gt;
+
+        Media controls playhead does not animate smoothly while playing
+        https://bugs.webkit.org/show_bug.cgi?id=162399
+        &lt;rdar://problem/28115680&gt;
+
+        Reviewed by Beth Dakin.
+
+        The media controls playhead currently does not animate smoothly during playback because we don't specify a
+        playback rate when updating the WebPlaybackControlsManager's timing value. However, simply setting this timing
+        value to the current playback rate (as known to the UI process) results in the UI process receiving multiple
+        updates from the web process where the current time is equal (or even less than) the time at which media began
+        to play, which results in the playhead seeking backwards to the start time multiple times when playing or
+        resuming media.
+
+        To address this, in WebCore, we inform the playback session model of the media time when playback begins (i.e.
+        a `playing` or `play` event is fired). This message precedes both the &quot;rate changed&quot; and &quot;current time changed&quot;
+        messages.
+
+        Unit tests to be added in a future patch.
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::notifyAboutPlaying):
+        (WebCore::HTMLMediaElement::setReadyState):
+        (WebCore::HTMLMediaElement::playInternal):
+        * html/HTMLMediaElement.h:
+        (WebCore::HTMLMediaElement::playbackStartedTime):
+        * platform/cocoa/WebPlaybackSessionModel.h:
+        (WebCore::WebPlaybackSessionModelClient::playbackStartedTimeChanged):
+        (WebCore::WebPlaybackSessionModelClient::bufferedTimeChanged): Deleted.
+        * platform/cocoa/WebPlaybackSessionModelMediaElement.h:
+        * platform/cocoa/WebPlaybackSessionModelMediaElement.mm:
+        (WebPlaybackSessionModelMediaElement::updateForEventName):
+        (WebPlaybackSessionModelMediaElement::playbackStartedTime):
+        * platform/ios/WebVideoFullscreenControllerAVKit.mm:
+        * platform/mac/WebPlaybackSessionInterfaceMac.h:
+        * platform/mac/WebPlaybackSessionInterfaceMac.mm:
+        (WebCore::WebPlaybackSessionInterfaceMac::currentTimeChanged):
+        (WebCore::WebPlaybackSessionInterfaceMac::rateChanged):
+        (WebCore::WebPlaybackSessionInterfaceMac::beginScrubbing):
+        (WebCore::WebPlaybackSessionInterfaceMac::endScrubbing):
+        (WebCore::WebPlaybackSessionInterfaceMac::updatePlaybackControlsManagerTiming):
+
</ins><span class="cx"> 2016-09-23  Zalan Bujtas  &lt;zalan@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         ASSERTION FAILED: !newRelayoutRoot.container() || is&lt;RenderView&gt;(newRelayoutRoot.container()) || !newRelayoutRoot.container()-&gt;needsLayout() while loading sohu.com
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlHTMLMediaElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/HTMLMediaElement.cpp (206349 => 206350)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/HTMLMediaElement.cpp        2016-09-24 01:18:52 UTC (rev 206349)
+++ trunk/Source/WebCore/html/HTMLMediaElement.cpp        2016-09-24 01:38:52 UTC (rev 206350)
</span><span class="lines">@@ -1028,6 +1028,7 @@
</span><span class="cx"> 
</span><span class="cx"> void HTMLMediaElement::notifyAboutPlaying()
</span><span class="cx"> {
</span><ins>+    m_playbackStartedTime = currentMediaTime().toDouble();
</ins><span class="cx">     dispatchEvent(Event::create(eventNames().playingEvent, false, true));
</span><span class="cx">     resolvePendingPlayPromises();
</span><span class="cx"> 
</span><span class="lines">@@ -2421,6 +2422,7 @@
</span><span class="cx">         if (canTransitionFromAutoplayToPlay()) {
</span><span class="cx">             m_paused = false;
</span><span class="cx">             invalidateCachedTime();
</span><ins>+            m_playbackStartedTime = currentMediaTime().toDouble();
</ins><span class="cx">             scheduleEvent(eventNames().playEvent);
</span><span class="cx">             scheduleNotifyAboutPlaying();
</span><span class="cx">         }
</span><span class="lines">@@ -3210,6 +3212,7 @@
</span><span class="cx">     if (m_paused) {
</span><span class="cx">         m_paused = false;
</span><span class="cx">         invalidateCachedTime();
</span><ins>+        m_playbackStartedTime = currentMediaTime().toDouble();
</ins><span class="cx">         scheduleEvent(eventNames().playEvent);
</span><span class="cx"> 
</span><span class="cx">         if (m_readyState &lt;= HAVE_CURRENT_DATA)
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlHTMLMediaElementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/HTMLMediaElement.h (206349 => 206350)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/HTMLMediaElement.h        2016-09-24 01:18:52 UTC (rev 206349)
+++ trunk/Source/WebCore/html/HTMLMediaElement.h        2016-09-24 01:38:52 UTC (rev 206350)
</span><span class="lines">@@ -478,6 +478,8 @@
</span><span class="cx">     bool hasEverHadAudio() const { return m_hasEverHadAudio; }
</span><span class="cx">     bool hasEverHadVideo() const { return m_hasEverHadVideo; }
</span><span class="cx"> 
</span><ins>+    double playbackStartedTime() const { return m_playbackStartedTime; }
+
</ins><span class="cx"> protected:
</span><span class="cx">     HTMLMediaElement(const QualifiedName&amp;, Document&amp;, bool createdByParser);
</span><span class="cx">     virtual ~HTMLMediaElement();
</span><span class="lines">@@ -858,6 +860,7 @@
</span><span class="cx">     MediaTime m_lastSeekTime;
</span><span class="cx">     
</span><span class="cx">     double m_previousProgressTime;
</span><ins>+    double m_playbackStartedTime { 0 };
</ins><span class="cx"> 
</span><span class="cx">     // The last time a timeupdate event was sent (based on monotonic clock).
</span><span class="cx">     double m_clockTimeAtLastUpdateEvent;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformcocoaWebPlaybackSessionModelh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/cocoa/WebPlaybackSessionModel.h (206349 => 206350)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/cocoa/WebPlaybackSessionModel.h        2016-09-24 01:18:52 UTC (rev 206349)
+++ trunk/Source/WebCore/platform/cocoa/WebPlaybackSessionModel.h        2016-09-24 01:38:52 UTC (rev 206350)
</span><span class="lines">@@ -59,10 +59,12 @@
</span><span class="cx"> 
</span><span class="cx">     enum ExternalPlaybackTargetType { TargetTypeNone, TargetTypeAirPlay, TargetTypeTVOut };
</span><span class="cx"> 
</span><ins>+    virtual double playbackStartedTime() const = 0;
</ins><span class="cx">     virtual double duration() const = 0;
</span><span class="cx">     virtual double currentTime() const = 0;
</span><span class="cx">     virtual double bufferedTime() const = 0;
</span><span class="cx">     virtual bool isPlaying() const = 0;
</span><ins>+    virtual bool isScrubbing() const = 0;
</ins><span class="cx">     virtual float playbackRate() const = 0;
</span><span class="cx">     virtual Ref&lt;TimeRanges&gt; seekableRanges() const = 0;
</span><span class="cx">     virtual bool canPlayFastReverse() const = 0;
</span><span class="lines">@@ -82,6 +84,7 @@
</span><span class="cx">     virtual void durationChanged(double) { }
</span><span class="cx">     virtual void currentTimeChanged(double /* currentTime */, double /* anchorTime */) { }
</span><span class="cx">     virtual void bufferedTimeChanged(double) { }
</span><ins>+    virtual void playbackStartedTimeChanged(double /* playbackStartedTime */) { }
</ins><span class="cx">     virtual void rateChanged(bool /* isPlaying */, float /* playbackRate */) { }
</span><span class="cx">     virtual void seekableRangesChanged(const TimeRanges&amp;) { }
</span><span class="cx">     virtual void canPlayFastReverseChanged(bool) { }
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformcocoaWebPlaybackSessionModelMediaElementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/cocoa/WebPlaybackSessionModelMediaElement.h (206349 => 206350)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/cocoa/WebPlaybackSessionModelMediaElement.h        2016-09-24 01:18:52 UTC (rev 206349)
+++ trunk/Source/WebCore/platform/cocoa/WebPlaybackSessionModelMediaElement.h        2016-09-24 01:38:52 UTC (rev 206350)
</span><span class="lines">@@ -73,6 +73,7 @@
</span><span class="cx">     double currentTime() const final;
</span><span class="cx">     double bufferedTime() const final;
</span><span class="cx">     bool isPlaying() const final;
</span><ins>+    bool isScrubbing() const final { return false; }
</ins><span class="cx">     float playbackRate() const final;
</span><span class="cx">     Ref&lt;TimeRanges&gt; seekableRanges() const final;
</span><span class="cx">     bool canPlayFastReverse() const final;
</span><span class="lines">@@ -98,6 +99,7 @@
</span><span class="cx">     Vector&lt;RefPtr&lt;TextTrack&gt;&gt; m_legibleTracksForMenu;
</span><span class="cx">     Vector&lt;RefPtr&lt;AudioTrack&gt;&gt; m_audioTracksForMenu;
</span><span class="cx">     
</span><ins>+    double playbackStartedTime() const;
</ins><span class="cx">     void updateLegibleOptions();
</span><span class="cx"> };
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformcocoaWebPlaybackSessionModelMediaElementmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/cocoa/WebPlaybackSessionModelMediaElement.mm (206349 => 206350)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/cocoa/WebPlaybackSessionModelMediaElement.mm        2016-09-24 01:18:52 UTC (rev 206349)
+++ trunk/Source/WebCore/platform/cocoa/WebPlaybackSessionModelMediaElement.mm        2016-09-24 01:38:52 UTC (rev 206350)
</span><span class="lines">@@ -106,6 +106,13 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (all
</span><ins>+        || eventName == eventNames().playEvent
+        || eventName == eventNames().playingEvent) {
+        for (auto client : m_clients)
+            client-&gt;playbackStartedTimeChanged(playbackStartedTime());
+    }
+
+    if (all
</ins><span class="cx">         || eventName == eventNames().pauseEvent
</span><span class="cx">         || eventName == eventNames().playEvent
</span><span class="cx">         || eventName == eventNames().ratechangeEvent) {
</span><span class="lines">@@ -287,6 +294,14 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+double WebPlaybackSessionModelMediaElement::playbackStartedTime() const
+{
+    if (!m_mediaElement)
+        return 0;
+
+    return m_mediaElement-&gt;playbackStartedTime();
+}
+
</ins><span class="cx"> const Vector&lt;AtomicString&gt;&amp; WebPlaybackSessionModelMediaElement::observedEventNames()
</span><span class="cx"> {
</span><span class="cx">     // FIXME(157452): Remove the right-hand constructor notation once NeverDestroyed supports initializer_lists.
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformiosWebVideoFullscreenControllerAVKitmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/ios/WebVideoFullscreenControllerAVKit.mm (206349 => 206350)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/ios/WebVideoFullscreenControllerAVKit.mm        2016-09-24 01:18:52 UTC (rev 206349)
+++ trunk/Source/WebCore/platform/ios/WebVideoFullscreenControllerAVKit.mm        2016-09-24 01:38:52 UTC (rev 206350)
</span><span class="lines">@@ -147,9 +147,11 @@
</span><span class="cx">     void selectAudioMediaOption(uint64_t) override;
</span><span class="cx">     void selectLegibleMediaOption(uint64_t) override;
</span><span class="cx">     double duration() const override;
</span><ins>+    double playbackStartedTime() const override { return 0; }
</ins><span class="cx">     double currentTime() const override;
</span><span class="cx">     double bufferedTime() const override;
</span><span class="cx">     bool isPlaying() const override;
</span><ins>+    bool isScrubbing() const override { return false; }
</ins><span class="cx">     float playbackRate() const override;
</span><span class="cx">     Ref&lt;TimeRanges&gt; seekableRanges() const override;
</span><span class="cx">     bool canPlayFastReverse() const override;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmacWebPlaybackSessionInterfaceMach"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mac/WebPlaybackSessionInterfaceMac.h (206349 => 206350)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mac/WebPlaybackSessionInterfaceMac.h        2016-09-24 01:18:52 UTC (rev 206349)
+++ trunk/Source/WebCore/platform/mac/WebPlaybackSessionInterfaceMac.h        2016-09-24 01:38:52 UTC (rev 206350)
</span><span class="lines">@@ -63,6 +63,8 @@
</span><span class="cx">     WEBCORE_EXPORT void invalidate();
</span><span class="cx">     WEBCORE_EXPORT void ensureControlsManager();
</span><span class="cx">     WEBCORE_EXPORT void setPlayBackControlsManager(WebPlaybackControlsManager *);
</span><ins>+    WEBCORE_EXPORT void beginScrubbing();
+    WEBCORE_EXPORT void endScrubbing();
</ins><span class="cx">     WEBCORE_EXPORT WebPlaybackControlsManager *playBackControlsManager();
</span><span class="cx"> 
</span><span class="cx"> private:
</span><span class="lines">@@ -69,6 +71,8 @@
</span><span class="cx">     WebPlaybackSessionInterfaceMac(WebPlaybackSessionModel&amp;);
</span><span class="cx">     WebPlaybackSessionModel* m_playbackSessionModel { nullptr };
</span><span class="cx">     WebPlaybackControlsManager *m_playbackControlsManager  { nullptr };
</span><ins>+
+    void updatePlaybackControlsManagerTiming(double currentTime, double anchorTime, double playbackRate, bool isPlaying);
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmacWebPlaybackSessionInterfaceMacmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mac/WebPlaybackSessionInterfaceMac.mm (206349 => 206350)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mac/WebPlaybackSessionInterfaceMac.mm        2016-09-24 01:18:52 UTC (rev 206349)
+++ trunk/Source/WebCore/platform/mac/WebPlaybackSessionInterfaceMac.mm        2016-09-24 01:38:52 UTC (rev 206350)
</span><span class="lines">@@ -76,12 +76,7 @@
</span><span class="cx"> void WebPlaybackSessionInterfaceMac::currentTimeChanged(double currentTime, double anchorTime)
</span><span class="cx"> {
</span><span class="cx">     WebPlaybackControlsManager* controlsManager = playBackControlsManager();
</span><del>-
-    NSTimeInterval anchorTimeStamp = ![controlsManager rate] ? NAN : anchorTime;
-    AVValueTiming *timing = [getAVValueTimingClass() valueTimingWithAnchorValue:currentTime
-        anchorTimeStamp:anchorTimeStamp rate:0];
-
-    [controlsManager setTiming:timing];
</del><ins>+    updatePlaybackControlsManagerTiming(currentTime, anchorTime, controlsManager.rate, controlsManager.playing);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void WebPlaybackSessionInterfaceMac::rateChanged(bool isPlaying, float playbackRate)
</span><span class="lines">@@ -89,8 +84,20 @@
</span><span class="cx">     WebPlaybackControlsManager* controlsManager = playBackControlsManager();
</span><span class="cx">     [controlsManager setRate:isPlaying ? playbackRate : 0.];
</span><span class="cx">     [controlsManager setPlaying:isPlaying];
</span><ins>+    updatePlaybackControlsManagerTiming(m_playbackSessionModel ? m_playbackSessionModel-&gt;currentTime() : 0, [[NSProcessInfo processInfo] systemUptime], playbackRate, isPlaying);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void WebPlaybackSessionInterfaceMac::beginScrubbing()
+{
+    updatePlaybackControlsManagerTiming(m_playbackSessionModel ? m_playbackSessionModel-&gt;currentTime() : 0, [[NSProcessInfo processInfo] systemUptime], 0, false);
+    webPlaybackSessionModel()-&gt;beginScrubbing();
+}
+
+void WebPlaybackSessionInterfaceMac::endScrubbing()
+{
+    webPlaybackSessionModel()-&gt;endScrubbing();
+}
+
</ins><span class="cx"> static RetainPtr&lt;NSMutableArray&gt; timeRangesToArray(const TimeRanges&amp; timeRanges)
</span><span class="cx"> {
</span><span class="cx">     RetainPtr&lt;NSMutableArray&gt; rangeArray = adoptNS([[NSMutableArray alloc] init]);
</span><span class="lines">@@ -163,6 +170,27 @@
</span><span class="cx">     [manager setLegibleMediaSelectionOptions:m_playbackSessionModel-&gt;legibleMediaSelectionOptions() withSelectedIndex:static_cast&lt;NSUInteger&gt;(m_playbackSessionModel-&gt;legibleMediaSelectedIndex())];
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void WebPlaybackSessionInterfaceMac::updatePlaybackControlsManagerTiming(double currentTime, double anchorTime, double playbackRate, bool isPlaying)
+{
+    WebPlaybackControlsManager *manager = playBackControlsManager();
+    if (!manager)
+        return;
+
+    WebPlaybackSessionModel *model = webPlaybackSessionModel();
+    if (!model)
+        return;
+
+    double effectiveAnchorTime = playbackRate ? anchorTime : NAN;
+    double effectivePlaybackRate = playbackRate;
+    if (!isPlaying
+        || model-&gt;isScrubbing()
+        || (manager.rate &gt; 0 &amp;&amp; model-&gt;playbackStartedTime() &gt;= currentTime)
+        || (manager.rate &lt; 0 &amp;&amp; model-&gt;playbackStartedTime() &lt;= currentTime))
+        effectivePlaybackRate = 0;
+
+    manager.timing = [getAVValueTimingClass() valueTimingWithAnchorValue:currentTime anchorTimeStamp:effectiveAnchorTime rate:effectivePlaybackRate];
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+}
+
</ins><span class="cx"> #endif // PLATFORM(MAC) &amp;&amp; ENABLE(VIDEO_PRESENTATION_MODE)
</span></span></pre></div>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (206349 => 206350)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2016-09-24 01:18:52 UTC (rev 206349)
+++ trunk/Source/WebKit2/ChangeLog        2016-09-24 01:38:52 UTC (rev 206350)
</span><span class="lines">@@ -1,3 +1,34 @@
</span><ins>+2016-09-23  Wenson Hsieh  &lt;wenson_hsieh@apple.com&gt;
+
+        Media controls playhead does not animate smoothly while playing
+        https://bugs.webkit.org/show_bug.cgi?id=162399
+        &lt;rdar://problem/28115680&gt;
+
+        Reviewed by Beth Dakin.
+
+        See WebCore ChangeLog for more details.
+
+        In the UI process, we update the WebPlaybackSessionManager's timing value when the rate or current time changes.
+        Each AVValueTiming is generated from the current time, system anchor time, and playback rate. The behavior of
+        the first two properties is unaffected. However, the rate used to update the timing value is the effective
+        playback rate, which is equal to the playback rate unless we are (1) not playing, (2) interacting with the media
+        controls in such a way that the media is essentially not playing, or (3) the current time precedes the playback
+        start time, accounting for playback direction. In these cases, our effective playback rate is 0, which means
+        that we do not animate the playhead.
+
+        * UIProcess/Cocoa/WebPlaybackSessionManagerProxy.h:
+        * UIProcess/Cocoa/WebPlaybackSessionManagerProxy.messages.in:
+        * UIProcess/Cocoa/WebPlaybackSessionManagerProxy.mm:
+        (WebKit::WebPlaybackSessionModelContext::beginScrubbing):
+        (WebKit::WebPlaybackSessionModelContext::endScrubbing):
+        (WebKit::WebPlaybackSessionModelContext::setPlaybackStartedTime):
+        (WebKit::WebPlaybackSessionModelContext::setCurrentTime):
+        (WebKit::WebPlaybackSessionManagerProxy::setPlaybackStartedTime):
+        * WebProcess/cocoa/WebPlaybackSessionManager.h:
+        * WebProcess/cocoa/WebPlaybackSessionManager.mm:
+        (WebKit::WebPlaybackSessionInterfaceContext::playbackStartedTimeChanged):
+        (WebKit::WebPlaybackSessionManager::playbackStartedTimeChanged):
+
</ins><span class="cx"> 2016-09-23  Caitlin Potter  &lt;caitp@igalia.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [JSC] Implement parsing of Async Functions
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessCocoaWebPlaybackSessionManagerProxyh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/Cocoa/WebPlaybackSessionManagerProxy.h (206349 => 206350)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/Cocoa/WebPlaybackSessionManagerProxy.h        2016-09-24 01:18:52 UTC (rev 206349)
+++ trunk/Source/WebKit2/UIProcess/Cocoa/WebPlaybackSessionManagerProxy.h        2016-09-24 01:38:52 UTC (rev 206350)
</span><span class="lines">@@ -71,6 +71,7 @@
</span><span class="cx">     void setDuration(double);
</span><span class="cx">     void setCurrentTime(double);
</span><span class="cx">     void setBufferedTime(double);
</span><ins>+    void setPlaybackStartedTime(double);
</ins><span class="cx">     void setRate(bool isPlaying, float playbackRate);
</span><span class="cx">     void setSeekableRanges(WebCore::TimeRanges&amp;);
</span><span class="cx">     void setCanPlayFastReverse(bool);
</span><span class="lines">@@ -102,10 +103,12 @@
</span><span class="cx">     void selectAudioMediaOption(uint64_t) final;
</span><span class="cx">     void selectLegibleMediaOption(uint64_t) final;
</span><span class="cx"> 
</span><ins>+    double playbackStartedTime() const final { return m_playbackStartedTime; }
</ins><span class="cx">     double duration() const final { return m_duration; }
</span><span class="cx">     double currentTime() const final { return m_currentTime; }
</span><span class="cx">     double bufferedTime() const final { return m_bufferedTime; }
</span><span class="cx">     bool isPlaying() const final { return m_isPlaying; }
</span><ins>+    bool isScrubbing() const final { return m_isScrubbing; }
</ins><span class="cx">     float playbackRate() const final { return m_playbackRate; }
</span><span class="cx">     Ref&lt;WebCore::TimeRanges&gt; seekableRanges() const final { return m_seekableRanges.copyRef(); }
</span><span class="cx">     bool canPlayFastReverse() const final { return m_canPlayFastReverse; }
</span><span class="lines">@@ -121,10 +124,13 @@
</span><span class="cx">     WebPlaybackSessionManagerProxy* m_manager;
</span><span class="cx">     uint64_t m_contextId;
</span><span class="cx">     HashSet&lt;WebCore::WebPlaybackSessionModelClient*&gt; m_clients;
</span><ins>+    double m_playbackStartedTime { 0 };
+    bool m_playbackStartedTimeNeedsUpdate { false };
</ins><span class="cx">     double m_duration { 0 };
</span><span class="cx">     double m_currentTime { 0 };
</span><span class="cx">     double m_bufferedTime { 0 };
</span><span class="cx">     bool m_isPlaying { false };
</span><ins>+    bool m_isScrubbing { false };
</ins><span class="cx">     float m_playbackRate { 0 };
</span><span class="cx">     Ref&lt;WebCore::TimeRanges&gt; m_seekableRanges { WebCore::TimeRanges::create() };
</span><span class="cx">     bool m_canPlayFastReverse { false };
</span><span class="lines">@@ -176,6 +182,7 @@
</span><span class="cx">     void setExternalPlaybackProperties(uint64_t contextId, bool enabled, uint32_t targetType, String localizedDeviceName);
</span><span class="cx">     void setWirelessVideoPlaybackDisabled(uint64_t contextId, bool);
</span><span class="cx">     void setDuration(uint64_t contextId, double duration);
</span><ins>+    void setPlaybackStartedTime(uint64_t contextId, double playbackStartedTime);
</ins><span class="cx">     void setRate(uint64_t contextId, bool isPlaying, double rate);
</span><span class="cx">     void handleControlledElementIDResponse(uint64_t, String) const;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessCocoaWebPlaybackSessionManagerProxymessagesin"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/Cocoa/WebPlaybackSessionManagerProxy.messages.in (206349 => 206350)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/Cocoa/WebPlaybackSessionManagerProxy.messages.in        2016-09-24 01:18:52 UTC (rev 206349)
+++ trunk/Source/WebKit2/UIProcess/Cocoa/WebPlaybackSessionManagerProxy.messages.in        2016-09-24 01:38:52 UTC (rev 206350)
</span><span class="lines">@@ -32,6 +32,7 @@
</span><span class="cx">     SetExternalPlaybackProperties(uint64_t contextId, bool enabled, uint32_t targetType, String localizedDeviceName)
</span><span class="cx">     SetWirelessVideoPlaybackDisabled(uint64_t contextId, bool disabled)
</span><span class="cx">     SetDuration(uint64_t contextId, double duration)
</span><ins>+    SetPlaybackStartedTime(uint64_t contextId, double playbackStartedTime)
</ins><span class="cx">     SetRate(uint64_t contextId, bool isPlaying, double rate)
</span><span class="cx">     SetUpPlaybackControlsManagerWithID(uint64_t contextId)
</span><span class="cx">     ClearPlaybackControlsManager()
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessCocoaWebPlaybackSessionManagerProxymm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/Cocoa/WebPlaybackSessionManagerProxy.mm (206349 => 206350)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/Cocoa/WebPlaybackSessionManagerProxy.mm        2016-09-24 01:18:52 UTC (rev 206349)
+++ trunk/Source/WebKit2/UIProcess/Cocoa/WebPlaybackSessionManagerProxy.mm        2016-09-24 01:38:52 UTC (rev 206350)
</span><span class="lines">@@ -74,6 +74,8 @@
</span><span class="cx"> {
</span><span class="cx">     if (m_manager)
</span><span class="cx">         m_manager-&gt;beginScrubbing(m_contextId);
</span><ins>+
+    m_isScrubbing = true;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void WebPlaybackSessionModelContext::endScrubbing()
</span><span class="lines">@@ -80,6 +82,9 @@
</span><span class="cx"> {
</span><span class="cx">     if (m_manager)
</span><span class="cx">         m_manager-&gt;endScrubbing(m_contextId);
</span><ins>+
+    m_isScrubbing = false;
+    m_playbackStartedTimeNeedsUpdate = isPlaying();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void WebPlaybackSessionModelContext::seekToTime(double time)
</span><span class="lines">@@ -124,6 +129,12 @@
</span><span class="cx">         m_manager-&gt;selectLegibleMediaOption(m_contextId, optionId);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void WebPlaybackSessionModelContext::setPlaybackStartedTime(double playbackStartedTime)
+{
+    m_playbackStartedTime = playbackStartedTime;
+    m_playbackStartedTimeNeedsUpdate = false;
+}
+
</ins><span class="cx"> void WebPlaybackSessionModelContext::setDuration(double duration)
</span><span class="cx"> {
</span><span class="cx">     m_duration = duration;
</span><span class="lines">@@ -135,6 +146,8 @@
</span><span class="cx"> {
</span><span class="cx">     m_currentTime = currentTime;
</span><span class="cx">     auto anchorTime = [[NSProcessInfo processInfo] systemUptime];
</span><ins>+    if (m_playbackStartedTimeNeedsUpdate)
+        setPlaybackStartedTime(currentTime);
</ins><span class="cx"> 
</span><span class="cx">     for (auto* client : m_clients)
</span><span class="cx">         client-&gt;currentTimeChanged(currentTime, anchorTime);
</span><span class="lines">@@ -389,6 +402,11 @@
</span><span class="cx">     ensureModel(contextId).setDuration(duration);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void WebPlaybackSessionManagerProxy::setPlaybackStartedTime(uint64_t contextId, double playbackStartedTime)
+{
+    ensureModel(contextId).setPlaybackStartedTime(playbackStartedTime);
+}
+
</ins><span class="cx"> void WebPlaybackSessionManagerProxy::setRate(uint64_t contextId, bool isPlaying, double rate)
</span><span class="cx"> {
</span><span class="cx">     ensureModel(contextId).setRate(isPlaying, rate);
</span></span></pre></div>
<a id="trunkSourceWebKit2WebProcesscocoaWebPlaybackSessionManagerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebProcess/cocoa/WebPlaybackSessionManager.h (206349 => 206350)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebProcess/cocoa/WebPlaybackSessionManager.h        2016-09-24 01:18:52 UTC (rev 206349)
+++ trunk/Source/WebKit2/WebProcess/cocoa/WebPlaybackSessionManager.h        2016-09-24 01:38:52 UTC (rev 206350)
</span><span class="lines">@@ -77,6 +77,7 @@
</span><span class="cx">     void durationChanged(double) final;
</span><span class="cx">     void currentTimeChanged(double currentTime, double anchorTime) final;
</span><span class="cx">     void bufferedTimeChanged(double) final;
</span><ins>+    void playbackStartedTimeChanged(double playbackStartedTime) final;
</ins><span class="cx">     void rateChanged(bool isPlaying, float playbackRate) final;
</span><span class="cx">     void seekableRangesChanged(const WebCore::TimeRanges&amp;) final;
</span><span class="cx">     void canPlayFastReverseChanged(bool value) final;
</span><span class="lines">@@ -122,6 +123,7 @@
</span><span class="cx">     void durationChanged(uint64_t contextId, double);
</span><span class="cx">     void currentTimeChanged(uint64_t contextId, double currentTime, double anchorTime);
</span><span class="cx">     void bufferedTimeChanged(uint64_t contextId, double bufferedTime);
</span><ins>+    void playbackStartedTimeChanged(uint64_t contextId, double playbackStartedTime);
</ins><span class="cx">     void rateChanged(uint64_t contextId, bool isPlaying, float playbackRate);
</span><span class="cx">     void seekableRangesChanged(uint64_t contextId, const WebCore::TimeRanges&amp;);
</span><span class="cx">     void canPlayFastReverseChanged(uint64_t contextId, bool value);
</span></span></pre></div>
<a id="trunkSourceWebKit2WebProcesscocoaWebPlaybackSessionManagermm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebProcess/cocoa/WebPlaybackSessionManager.mm (206349 => 206350)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebProcess/cocoa/WebPlaybackSessionManager.mm        2016-09-24 01:18:52 UTC (rev 206349)
+++ trunk/Source/WebKit2/WebProcess/cocoa/WebPlaybackSessionManager.mm        2016-09-24 01:38:52 UTC (rev 206350)
</span><span class="lines">@@ -96,6 +96,12 @@
</span><span class="cx">         m_manager-&gt;rateChanged(m_contextId, isPlaying, playbackRate);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void WebPlaybackSessionInterfaceContext::playbackStartedTimeChanged(double playbackStartedTime)
+{
+    if (m_manager)
+        m_manager-&gt;playbackStartedTimeChanged(m_contextId, playbackStartedTime);
+}
+
</ins><span class="cx"> void WebPlaybackSessionInterfaceContext::seekableRangesChanged(const WebCore::TimeRanges&amp; ranges)
</span><span class="cx"> {
</span><span class="cx">     if (m_manager)
</span><span class="lines">@@ -297,6 +303,11 @@
</span><span class="cx">     m_page-&gt;send(Messages::WebPlaybackSessionManagerProxy::SetBufferedTime(contextId, bufferedTime), m_page-&gt;pageID());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void WebPlaybackSessionManager::playbackStartedTimeChanged(uint64_t contextId, double playbackStartedTime)
+{
+    m_page-&gt;send(Messages::WebPlaybackSessionManagerProxy::SetPlaybackStartedTime(contextId, playbackStartedTime), m_page-&gt;pageID());
+}
+
</ins><span class="cx"> void WebPlaybackSessionManager::rateChanged(uint64_t contextId, bool isPlaying, float playbackRate)
</span><span class="cx"> {
</span><span class="cx">     m_page-&gt;send(Messages::WebPlaybackSessionManagerProxy::SetRate(contextId, isPlaying, playbackRate), m_page-&gt;pageID());
</span></span></pre>
</div>
</div>

</body>
</html>