<!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>[170336] trunk</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/170336">170336</a></dd>
<dt>Author</dt> <dd>jer.noble@apple.com</dd>
<dt>Date</dt> <dd>2014-06-23 17:08:25 -0700 (Mon, 23 Jun 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>HTMLMediaElement seek algorithm should allow cancelling previous seeks.
https://bugs.webkit.org/show_bug.cgi?id=134116

Reviewed by Eric Carlson.

Source/WebCore:
Test: media/video-seek-double.html

Fulfill the requirement of the §4.7.14.9 seeking algorithm to do steps 5+ asynchronously and cancel
previous instances of the algorithm.

For the html/ parts of the algorithm, implement this by adding a seek timer, which when fired will
issue steps 5-12. MediaPlayerPrivateAVFoundation will already coalesce multiple seek operations, so nothing
additional needs be done there.  However, MediaPlayerPrivateMediaSourceAVFObjC needs to implement the same
pending seek logic in case additional seeks were issued after the html/ algorithm reached step 12.

* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::HTMLMediaElement): Initialize the new m_seekTimer.
(WebCore::HTMLMediaElement::parseAttribute): Clear the seek timer.
(WebCore::HTMLMediaElement::seekInternal): Differentiate between DOM seeks and internal seeks.
(WebCore::HTMLMediaElement::seekWithTolerance:) Split into the seekTimerFired() method.
(WebCore::HTMLMediaElement::seekTimerFired:) Added, split from seekWithTolerance().
* html/HTMLMediaElement.h:
* html/MediaController.cpp:
(MediaController::bringElementUpToSpeed): Call seekInternal().
(WebCore::HTMLMediaElement::PendingSeek::PendingSeek): Added convenience struct for storing seek requests.
* platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h:
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::PendingSeek::PendingSeek): Ditto.
* platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm:
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::MediaPlayerPrivateMediaSourceAVFObjC): Modify the time jumped
    handler to not clear the m_seeking flag if another seek request is pending.
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::seekWithTolerance):
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::seekInternal):

LayoutTests:
* media/video-seek-double-expected.txt: Added.
* media/video-seek-double.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<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="#trunkSourceWebCorehtmlMediaControllercpp">trunk/Source/WebCore/html/MediaController.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsavfoundationobjcMediaPlayerPrivateMediaSourceAVFObjCh">trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsavfoundationobjcMediaPlayerPrivateMediaSourceAVFObjCmm">trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsmediavideoseekdoubleexpectedtxt">trunk/LayoutTests/media/video-seek-double-expected.txt</a></li>
<li><a href="#trunkLayoutTestsmediavideoseekdoublehtml">trunk/LayoutTests/media/video-seek-double.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (170335 => 170336)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2014-06-24 00:03:15 UTC (rev 170335)
+++ trunk/LayoutTests/ChangeLog        2014-06-24 00:08:25 UTC (rev 170336)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2014-06-20  Jer Noble  &lt;jer.noble@apple.com&gt;
+
+        HTMLMediaElement seek algorithm should allow cancelling previous seeks.
+        https://bugs.webkit.org/show_bug.cgi?id=134116
+
+        Reviewed by Eric Carlson.
+
+        * media/video-seek-double-expected.txt: Added.
+        * media/video-seek-double.html: Added.
+
</ins><span class="cx"> 2014-06-19  Jeffrey Pfau  &lt;jpfau@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Database process crashes when multiple transactions attempt to run at once
</span></span></pre></div>
<a id="trunkLayoutTestsmediavideoseekdoubleexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/video-seek-double-expected.txt (0 => 170336)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/video-seek-double-expected.txt                                (rev 0)
+++ trunk/LayoutTests/media/video-seek-double-expected.txt        2014-06-24 00:08:25 UTC (rev 170336)
</span><span class="lines">@@ -0,0 +1,13 @@
</span><ins>+Test that seeking twice in the same run loop will cancel the first seek.
+
+
+EVENT(canplaythrough)
+RUN(video.currentTime = 2)
+RUN(video.currentTime = 0.5)
+
+EVENT(seeked)
+EXPECTED (video.currentTime == '0.5') OK
+RUN(video.play())
+EVENT(play)
+END OF TEST
+
</ins></span></pre></div>
<a id="trunkLayoutTestsmediavideoseekdoublehtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/media/video-seek-double.html (0 => 170336)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/media/video-seek-double.html                                (rev 0)
+++ trunk/LayoutTests/media/video-seek-double.html        2014-06-24 00:08:25 UTC (rev 170336)
</span><span class="lines">@@ -0,0 +1,36 @@
</span><ins>+&lt;!doctype html&gt;
+&lt;html&gt;
+&lt;head&gt;
+    &lt;script src=media-file.js&gt;&lt;/script&gt;
+    &lt;script src=video-test.js&gt;&lt;/script&gt;
+    &lt;script&gt;
+        function runTest()
+        {
+            findMediaElement();
+            waitForEvent('canplaythrough', canplaythrough);
+            video.src = findMediaFile('video', 'content/test');
+        }
+
+        function canplaythrough() 
+        {
+            waitForEventOnce('seeked', seeked );
+            run('video.currentTime = 2');
+            run('video.currentTime = 0.5');
+            consoleWrite('');
+        }
+
+        function seeked()
+        { 
+            testExpected('video.currentTime', 0.5);
+            waitForEventAndFail('seeked');
+            waitForEventAndEnd('play');
+            run('video.play()');
+         }
+    &lt;/script&gt;
+&lt;/head&gt;
+&lt;body onload='runTest()'&gt;
+    &lt;p&gt;Test that seeking twice in the same run loop will cancel the first seek.
+     &lt;/p&gt;
+    &lt;video controls&gt;&lt;/video&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (170335 => 170336)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-06-24 00:03:15 UTC (rev 170335)
+++ trunk/Source/WebCore/ChangeLog        2014-06-24 00:08:25 UTC (rev 170336)
</span><span class="lines">@@ -1,3 +1,38 @@
</span><ins>+2014-06-20  Jer Noble  &lt;jer.noble@apple.com&gt;
+
+        HTMLMediaElement seek algorithm should allow cancelling previous seeks.
+        https://bugs.webkit.org/show_bug.cgi?id=134116
+
+        Reviewed by Eric Carlson.
+
+        Test: media/video-seek-double.html
+
+        Fulfill the requirement of the §4.7.14.9 seeking algorithm to do steps 5+ asynchronously and cancel
+        previous instances of the algorithm.
+
+        For the html/ parts of the algorithm, implement this by adding a seek timer, which when fired will
+        issue steps 5-12. MediaPlayerPrivateAVFoundation will already coalesce multiple seek operations, so nothing
+        additional needs be done there.  However, MediaPlayerPrivateMediaSourceAVFObjC needs to implement the same
+        pending seek logic in case additional seeks were issued after the html/ algorithm reached step 12.
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::HTMLMediaElement): Initialize the new m_seekTimer.
+        (WebCore::HTMLMediaElement::parseAttribute): Clear the seek timer.
+        (WebCore::HTMLMediaElement::seekInternal): Differentiate between DOM seeks and internal seeks.
+        (WebCore::HTMLMediaElement::seekWithTolerance:) Split into the seekTimerFired() method.
+        (WebCore::HTMLMediaElement::seekTimerFired:) Added, split from seekWithTolerance().
+        * html/HTMLMediaElement.h:
+        * html/MediaController.cpp:
+        (MediaController::bringElementUpToSpeed): Call seekInternal().
+        (WebCore::HTMLMediaElement::PendingSeek::PendingSeek): Added convenience struct for storing seek requests.
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h:
+        (WebCore::MediaPlayerPrivateMediaSourceAVFObjC::PendingSeek::PendingSeek): Ditto.
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm:
+        (WebCore::MediaPlayerPrivateMediaSourceAVFObjC::MediaPlayerPrivateMediaSourceAVFObjC): Modify the time jumped
+            handler to not clear the m_seeking flag if another seek request is pending.
+        (WebCore::MediaPlayerPrivateMediaSourceAVFObjC::seekWithTolerance):
+        (WebCore::MediaPlayerPrivateMediaSourceAVFObjC::seekInternal):
+
</ins><span class="cx"> 2014-06-23  Timothy Horton  &lt;timothy_horton@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [WK2] Use the page background color instead of white when swipe snapshots were purged (134218)
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlHTMLMediaElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/HTMLMediaElement.cpp (170335 => 170336)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/HTMLMediaElement.cpp        2014-06-24 00:03:15 UTC (rev 170335)
+++ trunk/Source/WebCore/html/HTMLMediaElement.cpp        2014-06-24 00:08:25 UTC (rev 170336)
</span><span class="lines">@@ -256,6 +256,7 @@
</span><span class="cx">     , m_progressEventTimer(this, &amp;HTMLMediaElement::progressEventTimerFired)
</span><span class="cx">     , m_playbackProgressTimer(this, &amp;HTMLMediaElement::playbackProgressTimerFired)
</span><span class="cx">     , m_scanTimer(this, &amp;HTMLMediaElement::scanTimerFired)
</span><ins>+    , m_seekTimer(this, &amp;HTMLMediaElement::seekTimerFired)
</ins><span class="cx">     , m_playedTimeRanges()
</span><span class="cx">     , m_asyncEventQueue(*this)
</span><span class="cx">     , m_playbackRate(1.0f)
</span><span class="lines">@@ -2316,17 +2317,23 @@
</span><span class="cx">     double negativeTolerance = delta &gt;= 0 ? delta : std::numeric_limits&lt;double&gt;::infinity();
</span><span class="cx">     double positiveTolerance = delta &lt; 0 ? -delta : std::numeric_limits&lt;double&gt;::infinity();
</span><span class="cx"> 
</span><del>-    seekWithTolerance(time, negativeTolerance, positiveTolerance);
</del><ins>+    seekWithTolerance(time, negativeTolerance, positiveTolerance, true);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void HTMLMediaElement::seek(double time)
</span><span class="cx"> {
</span><span class="cx">     LOG(Media, &quot;HTMLMediaElement::seek(%f)&quot;, time);
</span><del>-    seekWithTolerance(time, 0, 0);
</del><ins>+    seekWithTolerance(time, 0, 0, true);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void HTMLMediaElement::seekWithTolerance(double time, double negativeTolerance, double positiveTolerance)
</del><ins>+void HTMLMediaElement::seekInternal(double time)
</ins><span class="cx"> {
</span><ins>+    LOG(Media, &quot;HTMLMediaElement::seekInternal(%f)&quot;, time);
+    seekWithTolerance(time, 0, 0, false);
+}
+
+void HTMLMediaElement::seekWithTolerance(double time, double negativeTolerance, double positiveTolerance, bool fromDOM)
+{
</ins><span class="cx">     // 4.8.10.9 Seeking
</span><span class="cx"> 
</span><span class="cx">     // 1 - Set the media element's show poster flag to false.
</span><span class="lines">@@ -2347,16 +2354,38 @@
</span><span class="cx">     // 3 - If the element's seeking IDL attribute is true, then another instance of this algorithm is
</span><span class="cx">     // already running. Abort that other instance of the algorithm without waiting for the step that
</span><span class="cx">     // it is running to complete.
</span><del>-    // Nothing specific to be done here.
</del><ins>+    if (m_seeking) {
+        m_seekTimer.stop();
+        m_pendingSeek = nullptr;
+    }
</ins><span class="cx"> 
</span><span class="cx">     // 4 - Set the seeking IDL attribute to true.
</span><span class="cx">     // The flag will be cleared when the engine tells us the time has actually changed.
</span><span class="cx">     m_seeking = true;
</span><ins>+    if (m_playing) {
+        if (m_lastSeekTime &lt; now)
+            addPlayedRange(m_lastSeekTime, now);
+    }
+    m_lastSeekTime = time;
</ins><span class="cx"> 
</span><span class="cx">     // 5 - If the seek was in response to a DOM method call or setting of an IDL attribute, then continue
</span><span class="cx">     // the script. The remainder of these steps must be run asynchronously.
</span><del>-    // Nothing to be done here.
</del><ins>+    m_pendingSeek = std::make_unique&lt;PendingSeek&gt;(now, time, negativeTolerance, positiveTolerance);
+    if (fromDOM)
+        m_seekTimer.startOneShot(0);
+    else
+        seekTimerFired(m_seekTimer);
+}
</ins><span class="cx"> 
</span><ins>+void HTMLMediaElement::seekTimerFired(Timer&lt;HTMLMediaElement&gt;&amp;)
+{
+    ASSERT(m_pendingSeek);
+    double now = m_pendingSeek-&gt;now;
+    double time = m_pendingSeek-&gt;targetTime;
+    double negativeTolerance = m_pendingSeek-&gt;negativeTolerance;
+    double positiveTolerance = m_pendingSeek-&gt;positiveTolerance;
+    m_pendingSeek = nullptr;
+
</ins><span class="cx">     // 6 - If the new playback position is later than the end of the media resource, then let it be the end 
</span><span class="cx">     // of the media resource instead.
</span><span class="cx">     time = std::min(time, duration());
</span><span class="lines">@@ -2373,7 +2402,7 @@
</span><span class="cx"> #if !LOG_DISABLED
</span><span class="cx">     double mediaTime = m_player-&gt;mediaTimeForTimeValue(time);
</span><span class="cx">     if (time != mediaTime)
</span><del>-        LOG(Media, &quot;HTMLMediaElement::seek(%f) - media timeline equivalent is %f&quot;, time, mediaTime);
</del><ins>+        LOG(Media, &quot;HTMLMediaElement::seekTimerFired(%f) - media timeline equivalent is %f&quot;, time, mediaTime);
</ins><span class="cx"> #endif
</span><span class="cx">     time = m_player-&gt;mediaTimeForTimeValue(time);
</span><span class="cx"> 
</span><span class="lines">@@ -2406,12 +2435,8 @@
</span><span class="cx">     }
</span><span class="cx">     time = seekableRanges-&gt;nearest(time);
</span><span class="cx"> 
</span><del>-    if (m_playing) {
-        if (m_lastSeekTime &lt; now)
-            addPlayedRange(m_lastSeekTime, now);
-    }
</del><ins>+    m_sentEndEvent = false;
</ins><span class="cx">     m_lastSeekTime = time;
</span><del>-    m_sentEndEvent = false;
</del><span class="cx"> 
</span><span class="cx">     // 10 - Queue a task to fire a simple event named seeking at the element.
</span><span class="cx">     scheduleEvent(eventNames().seekingEvent);
</span><span class="lines">@@ -2562,7 +2587,7 @@
</span><span class="cx">     if (m_mediaController)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    seek(time);
</del><ins>+    seekInternal(time);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void HTMLMediaElement::setCurrentTime(double time, ExceptionCode&amp; ec)
</span><span class="lines">@@ -2728,7 +2753,7 @@
</span><span class="cx">         scheduleDelayedAction(LoadMediaResource);
</span><span class="cx"> 
</span><span class="cx">     if (endedPlayback())
</span><del>-        seek(0);
</del><ins>+        seekInternal(0);
</ins><span class="cx"> 
</span><span class="cx">     if (m_mediaController)
</span><span class="cx">         m_mediaController-&gt;bringElementUpToSpeed(this);
</span><span class="lines">@@ -4075,7 +4100,7 @@
</span><span class="cx">             // then seek to the earliest possible position of the media resource and abort these steps when the direction of
</span><span class="cx">             // playback is forwards,
</span><span class="cx">             if (now &gt;= dur)
</span><del>-                seek(0);
</del><ins>+                seekInternal(0);
</ins><span class="cx">         } else if ((now &lt;= 0 &amp;&amp; playbackRate &lt; 0) || (now &gt;= dur &amp;&amp; playbackRate &gt; 0)) {
</span><span class="cx">             // If the media element does not have a current media controller, and the media element
</span><span class="cx">             // has still ended playback and paused is false,
</span><span class="lines">@@ -4146,7 +4171,7 @@
</span><span class="cx">     double now = currentTime();
</span><span class="cx">     double dur = duration();
</span><span class="cx">     if (now &gt; dur)
</span><del>-        seek(dur);
</del><ins>+        seekInternal(dur);
</ins><span class="cx"> 
</span><span class="cx">     endProcessingMediaPlayerCallback();
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlHTMLMediaElementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/HTMLMediaElement.h (170335 => 170336)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/HTMLMediaElement.h        2014-06-24 00:03:15 UTC (rev 170335)
+++ trunk/Source/WebCore/html/HTMLMediaElement.h        2014-06-24 00:08:25 UTC (rev 170336)
</span><span class="lines">@@ -576,12 +576,14 @@
</span><span class="cx">     void progressEventTimerFired(Timer&lt;HTMLMediaElement&gt;&amp;);
</span><span class="cx">     void playbackProgressTimerFired(Timer&lt;HTMLMediaElement&gt;&amp;);
</span><span class="cx">     void scanTimerFired(Timer&lt;HTMLMediaElement&gt;&amp;);
</span><ins>+    void seekTimerFired(Timer&lt;HTMLMediaElement&gt;&amp;);
</ins><span class="cx">     void startPlaybackProgressTimer();
</span><span class="cx">     void startProgressEventTimer();
</span><span class="cx">     void stopPeriodicTimers();
</span><span class="cx"> 
</span><span class="cx">     void seek(double time);
</span><del>-    void seekWithTolerance(double time, double negativeTolerance, double positiveTolerance);
</del><ins>+    void seekInternal(double time);
+    void seekWithTolerance(double time, double negativeTolerance, double positiveTolerance, bool fromDOM);
</ins><span class="cx">     void finishSeek();
</span><span class="cx">     void checkIfSeekNeeded();
</span><span class="cx">     void addPlayedRange(double start, double end);
</span><span class="lines">@@ -701,6 +703,7 @@
</span><span class="cx">     Timer&lt;HTMLMediaElement&gt; m_progressEventTimer;
</span><span class="cx">     Timer&lt;HTMLMediaElement&gt; m_playbackProgressTimer;
</span><span class="cx">     Timer&lt;HTMLMediaElement&gt; m_scanTimer;
</span><ins>+    Timer&lt;HTMLMediaElement&gt; m_seekTimer;
</ins><span class="cx">     RefPtr&lt;TimeRanges&gt; m_playedTimeRanges;
</span><span class="cx">     GenericEventQueue m_asyncEventQueue;
</span><span class="cx"> 
</span><span class="lines">@@ -714,6 +717,21 @@
</span><span class="cx"> 
</span><span class="cx">     RefPtr&lt;MediaError&gt; m_error;
</span><span class="cx"> 
</span><ins>+    struct PendingSeek {
+        PendingSeek(double now, double targetTime, double negativeTolerance, double positiveTolerance)
+            : now(now)
+            , targetTime(targetTime)
+            , negativeTolerance(negativeTolerance)
+            , positiveTolerance(positiveTolerance)
+        {
+        }
+        double now;
+        double targetTime;
+        double negativeTolerance;
+        double positiveTolerance;
+    };
+    std::unique_ptr&lt;PendingSeek&gt; m_pendingSeek;
+
</ins><span class="cx">     double m_volume;
</span><span class="cx">     bool m_volumeInitialized;
</span><span class="cx">     double m_lastSeekTime;
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlMediaControllercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/MediaController.cpp (170335 => 170336)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/MediaController.cpp        2014-06-24 00:03:15 UTC (rev 170335)
+++ trunk/Source/WebCore/html/MediaController.cpp        2014-06-24 00:08:25 UTC (rev 170336)
</span><span class="lines">@@ -479,7 +479,7 @@
</span><span class="cx">     // When the user agent is to bring a media element up to speed with its new media controller,
</span><span class="cx">     // it must seek that media element to the MediaController's media controller position relative
</span><span class="cx">     // to the media element's timeline.
</span><del>-    element-&gt;seek(currentTime());
</del><ins>+    element-&gt;seekInternal(currentTime());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool MediaController::isBlocked() const
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsavfoundationobjcMediaPlayerPrivateMediaSourceAVFObjCh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h (170335 => 170336)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h        2014-06-24 00:03:15 UTC (rev 170335)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h        2014-06-24 00:08:25 UTC (rev 170336)
</span><span class="lines">@@ -64,7 +64,7 @@
</span><span class="cx">     void setReadyState(MediaPlayer::ReadyState);
</span><span class="cx">     void setNetworkState(MediaPlayer::NetworkState);
</span><span class="cx"> 
</span><del>-    void seekInternal(double, double, double);
</del><ins>+    void seekInternal();
</ins><span class="cx">     void setLoadingProgresssed(bool flag) { m_loadingProgressed = flag; }
</span><span class="cx">     void setHasAvailableVideoFrame(bool flag) { m_hasAvailableVideoFrame = flag; }
</span><span class="cx">     void durationChanged();
</span><span class="lines">@@ -166,6 +166,19 @@
</span><span class="cx"> 
</span><span class="cx">     friend class MediaSourcePrivateAVFObjC;
</span><span class="cx"> 
</span><ins>+    struct PendingSeek {
+        PendingSeek(const MediaTime&amp; targetTime, const MediaTime&amp; negativeThreshold, const MediaTime&amp; positiveThreshold)
+            : targetTime(targetTime)
+            , negativeThreshold(negativeThreshold)
+            , positiveThreshold(positiveThreshold)
+        {
+        }
+        MediaTime targetTime;
+        MediaTime negativeThreshold;
+        MediaTime positiveThreshold;
+    };
+    std::unique_ptr&lt;PendingSeek&gt; m_pendingSeek;
+
</ins><span class="cx">     MediaPlayer* m_player;
</span><span class="cx">     WeakPtrFactory&lt;MediaPlayerPrivateMediaSourceAVFObjC&gt; m_weakPtrFactory;
</span><span class="cx">     RefPtr&lt;MediaSourcePrivateClient&gt; m_mediaSource;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsavfoundationobjcMediaPlayerPrivateMediaSourceAVFObjCmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm (170335 => 170336)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm        2014-06-24 00:03:15 UTC (rev 170335)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm        2014-06-24 00:08:25 UTC (rev 170336)
</span><span class="lines">@@ -153,9 +153,12 @@
</span><span class="cx">         if (!weakThis)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        if (m_seeking)
</del><ins>+        if (m_seeking &amp;&amp; !m_pendingSeek)
</ins><span class="cx">             m_seeking = false;
</span><span class="cx">         m_player-&gt;timeChanged();
</span><ins>+
+        if (m_pendingSeek)
+            seekInternal();
</ins><span class="cx">     }];
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -424,23 +427,31 @@
</span><span class="cx"> {
</span><span class="cx">     m_seeking = true;
</span><span class="cx">     auto weakThis = createWeakPtr();
</span><del>-    callOnMainThread([weakThis, time, negativeThreshold, positiveThreshold]{
</del><ins>+    m_pendingSeek = std::make_unique&lt;PendingSeek&gt;(MediaTime::createWithDouble(time), MediaTime::createWithDouble(negativeThreshold), MediaTime::createWithDouble(positiveThreshold));
+
+    callOnMainThread([weakThis] {
</ins><span class="cx">         if (!weakThis)
</span><span class="cx">             return;
</span><del>-        weakThis.get()-&gt;seekInternal(time, negativeThreshold, positiveThreshold);
</del><ins>+        weakThis.get()-&gt;seekInternal();
</ins><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void MediaPlayerPrivateMediaSourceAVFObjC::seekInternal(double time, double negativeThreshold, double positiveThreshold)
</del><ins>+void MediaPlayerPrivateMediaSourceAVFObjC::seekInternal()
</ins><span class="cx"> {
</span><ins>+    std::unique_ptr&lt;PendingSeek&gt; pendingSeek;
+    pendingSeek.swap(m_pendingSeek);
+
+    if (!pendingSeek)
+        return;
+
</ins><span class="cx">     if (!m_mediaSourcePrivate)
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     MediaTime seekTime;
</span><del>-    if (!negativeThreshold &amp;&amp; !positiveThreshold)
-        seekTime = MediaTime::createWithDouble(time);
</del><ins>+    if (pendingSeek-&gt;negativeThreshold != MediaTime::zeroTime() &amp;&amp; pendingSeek-&gt;positiveThreshold != MediaTime::zeroTime())
+        seekTime = pendingSeek-&gt;targetTime;
</ins><span class="cx">     else
</span><del>-        seekTime = m_mediaSourcePrivate-&gt;fastSeekTimeForMediaTime(MediaTime::createWithDouble(time), MediaTime::createWithDouble(positiveThreshold), MediaTime::createWithDouble(negativeThreshold));
</del><ins>+        seekTime = m_mediaSourcePrivate-&gt;fastSeekTimeForMediaTime(pendingSeek-&gt;targetTime, pendingSeek-&gt;positiveThreshold, pendingSeek-&gt;negativeThreshold);
</ins><span class="cx"> 
</span><span class="cx">     [m_synchronizer setRate:(m_playing ? m_rate : 0) time:toCMTime(seekTime)];
</span><span class="cx">     m_mediaSourcePrivate-&gt;seekToTime(seekTime);
</span></span></pre>
</div>
</div>

</body>
</html>