requestFrameAnimation() callback timestamp should be very close to Performance.now()
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 23 Jun 2016 22:46:28 +0000 (22:46 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 23 Jun 2016 22:46:28 +0000 (22:46 +0000)
https://bugs.webkit.org/show_bug.cgi?id=159038

Patch by Said Abou-Hallawa <sabouhallawa@apple.com> on 2016-06-23
Reviewed by Simon Fraser.

Source/WebCore:

Pass the Performance.now() to requestFrameAnimation() callback. Do not add
the timeUntilOutput which is the difference between outputTime and now since
this addition makes us report a timestamp ahead in the future by almost 33ms.

A new function named "nowTimestamp()" is added to the DOMWindow class. It
calls Performance.now() if WEB_TIMING is enabled, otherwise it calls
monotonicallyIncreasingTime(). The returned timestamp is seconds and it is
relative to the document loading time.

The timestamp passing will be removed all the down till the callers of
ScriptedAnimationController::serviceScriptedAnimations(). The callers will
getting the now timestamp by calling DOMWindow::nowTimestamp().

Tests: animations/animation-callback-timestamp.html
       animations/animation-multiple-callbacks-timestamp.html

* dom/Document.cpp:
(WebCore::Document::monotonicTimestamp):
(WebCore::Document::serviceScriptedAnimations):
* dom/Document.h:
* dom/ScriptedAnimationController.cpp:
(WebCore::ScriptedAnimationController::serviceScriptedAnimations):
(WebCore::ScriptedAnimationController::animationTimerFired):
(WebCore::ScriptedAnimationController::displayRefreshFired):
* dom/ScriptedAnimationController.h:
* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::getVideoPlaybackQuality):
* loader/DocumentLoadTiming.h:
(WebCore::DocumentLoadTiming::referenceWallTime):
* page/DOMWindow.cpp:
(WebCore::DOMWindow::nowTimestamp):
* page/DOMWindow.h:
* page/FrameView.cpp:
(WebCore::FrameView::serviceScriptedAnimations):
* page/FrameView.h:
* platform/graphics/DisplayRefreshMonitor.cpp:
(WebCore::DisplayRefreshMonitor::DisplayRefreshMonitor):
(WebCore::DisplayRefreshMonitor::displayDidRefresh):
* platform/graphics/DisplayRefreshMonitor.h:
(WebCore::DisplayRefreshMonitor::setMonotonicAnimationStartTime): Deleted.
* platform/graphics/DisplayRefreshMonitorClient.cpp:
(WebCore::DisplayRefreshMonitorClient::fireDisplayRefreshIfNeeded):
* platform/graphics/DisplayRefreshMonitorClient.h:
* platform/graphics/GraphicsLayerUpdater.cpp:
(WebCore::GraphicsLayerUpdater::displayRefreshFired):
* platform/graphics/GraphicsLayerUpdater.h:
* platform/graphics/ios/DisplayRefreshMonitorIOS.h:
* platform/graphics/ios/DisplayRefreshMonitorIOS.mm:
(-[WebDisplayLinkHandler handleDisplayLink:]):
(WebCore::DisplayRefreshMonitorIOS::displayLinkFired):
(WebCore::mediaTimeToCurrentTime): Deleted.
* platform/graphics/mac/DisplayRefreshMonitorMac.cpp:
(WebCore::displayLinkCallback):
(WebCore::DisplayRefreshMonitorMac::displayLinkFired):
* platform/graphics/mac/DisplayRefreshMonitorMac.h:
* platform/graphics/texmap/coordinated/CompositingCoordinator.cpp:
(WebCore::CompositingCoordinator::syncDisplayState):
(WebCore::CompositingCoordinator::nextAnimationServiceTime):

Source/WebKit2:

* WebProcess/WebPage/Cocoa/RemoteLayerTreeDisplayRefreshMonitor.mm:
(WebKit::RemoteLayerTreeDisplayRefreshMonitor::didUpdateLayers):

LayoutTests:

* animations/animation-callback-timestamp-expected.txt: Added.
* animations/animation-callback-timestamp.html: Added.
* animations/animation-multiple-callbacks-timestamp-expected.txt: Added.
* animations/animation-multiple-callbacks-timestamp.html: Added.

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

30 files changed:
LayoutTests/ChangeLog
LayoutTests/animations/animation-callback-timestamp-expected.txt [new file with mode: 0644]
LayoutTests/animations/animation-callback-timestamp.html [new file with mode: 0644]
LayoutTests/animations/animation-multiple-callbacks-timestamp-expected.txt [new file with mode: 0644]
LayoutTests/animations/animation-multiple-callbacks-timestamp.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h
Source/WebCore/dom/ScriptedAnimationController.cpp
Source/WebCore/dom/ScriptedAnimationController.h
Source/WebCore/html/HTMLMediaElement.cpp
Source/WebCore/loader/DocumentLoadTiming.h
Source/WebCore/page/DOMWindow.cpp
Source/WebCore/page/DOMWindow.h
Source/WebCore/page/FrameView.cpp
Source/WebCore/page/FrameView.h
Source/WebCore/platform/graphics/DisplayRefreshMonitor.cpp
Source/WebCore/platform/graphics/DisplayRefreshMonitor.h
Source/WebCore/platform/graphics/DisplayRefreshMonitorClient.cpp
Source/WebCore/platform/graphics/DisplayRefreshMonitorClient.h
Source/WebCore/platform/graphics/GraphicsLayerUpdater.cpp
Source/WebCore/platform/graphics/GraphicsLayerUpdater.h
Source/WebCore/platform/graphics/ios/DisplayRefreshMonitorIOS.h
Source/WebCore/platform/graphics/ios/DisplayRefreshMonitorIOS.mm
Source/WebCore/platform/graphics/mac/DisplayRefreshMonitorMac.cpp
Source/WebCore/platform/graphics/mac/DisplayRefreshMonitorMac.h
Source/WebCore/platform/graphics/texmap/coordinated/CompositingCoordinator.cpp
Source/WebCore/platform/graphics/texmap/coordinated/CompositingCoordinator.h
Source/WebKit2/ChangeLog
Source/WebKit2/WebProcess/WebPage/Cocoa/RemoteLayerTreeDisplayRefreshMonitor.mm

index def0495..f58af4f 100644 (file)
@@ -1,3 +1,15 @@
+2016-06-23  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        requestFrameAnimation() callback timestamp should be very close to Performance.now() 
+        https://bugs.webkit.org/show_bug.cgi?id=159038
+
+        Reviewed by Simon Fraser.
+
+        * animations/animation-callback-timestamp-expected.txt: Added.
+        * animations/animation-callback-timestamp.html: Added.
+        * animations/animation-multiple-callbacks-timestamp-expected.txt: Added.
+        * animations/animation-multiple-callbacks-timestamp.html: Added.
+
 2016-06-23  Ryan Haddad  <ryanhaddad@apple.com>
 
         Land test expectations for rdar://problem/26952627.
diff --git a/LayoutTests/animations/animation-callback-timestamp-expected.txt b/LayoutTests/animations/animation-callback-timestamp-expected.txt
new file mode 100644 (file)
index 0000000..39c0f42
--- /dev/null
@@ -0,0 +1,5 @@
+PASS All the differences between requestAnimationFrame() callback timestamps and Performance.now() were within 3ms.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/animations/animation-callback-timestamp.html b/LayoutTests/animations/animation-callback-timestamp.html
new file mode 100644 (file)
index 0000000..6d45632
--- /dev/null
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+    <script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+    <script>
+        var currentFrame = 0;
+        var failed = false;
+
+        function finishTest()
+        {
+            if (failed)
+                testFailed("Some of the requestAnimationFrame() callback timestamps were larger than Performance.now() by more than 3ms.");
+            else
+                testPassed("All the differences between requestAnimationFrame() callback timestamps and Performance.now() were within 3ms.")
+            finishJSTest();
+        }
+        
+        function doAnimation(timestamp)
+        {
+            const Tolerance = 3;
+            const WarmupFrames = 5;
+
+            var performanceNow = window.performance.now();
+            if (++currentFrame > WarmupFrames && Math.abs(timestamp - performanceNow) >= Tolerance) {
+                debug("requestAnimationFrame() timestamp = " + timestamp + ", window.performance.now() = " + performanceNow);
+                failed = true;
+            }
+
+            const MaxFrames = 25;
+            if (currentFrame == MaxFrames)
+                finishTest();
+            else
+                requestAnimationFrame(doAnimation);
+        }
+        
+        window.jsTestIsAsync = true;
+        requestAnimationFrame(doAnimation);
+    </script>
+    <script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/animations/animation-multiple-callbacks-timestamp-expected.txt b/LayoutTests/animations/animation-multiple-callbacks-timestamp-expected.txt
new file mode 100644 (file)
index 0000000..1b2df23
--- /dev/null
@@ -0,0 +1,5 @@
+PASS All the multiple requestAnimationFrame() callbacks, which were fired at the same time, received the same timestamp.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/animations/animation-multiple-callbacks-timestamp.html b/LayoutTests/animations/animation-multiple-callbacks-timestamp.html
new file mode 100644 (file)
index 0000000..5ddd9bf
--- /dev/null
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+    <script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+    <script>
+        var currentFrame = 0;
+        var timestamp1 = 0;
+        var failed = false;
+
+        function finishTest()
+        {
+            if (failed)
+                testFailed("Some of the multiple requestAnimationFrame() callbacks, which were fired at the same time, received different timestamps.");
+            else
+                testPassed("All the multiple requestAnimationFrame() callbacks, which were fired at the same time, received the same timestamp.");
+            finishJSTest();
+        }
+
+        function doAnimation1(timestamp)
+        {
+            timestamp1 = timestamp;
+            
+            const MaxFrames = 25;
+            if (currentFrame == MaxFrames)
+                finishTest();
+            else {
+                requestAnimationFrame(doAnimation1);
+                requestAnimationFrame(doAnimation2);
+            }
+        }
+
+        function doAnimation2(timestamp)
+        {
+            const WarmupFrames = 5;
+            if (++currentFrame > WarmupFrames && timestamp != timestamp1) {
+                testFailed("timestamp1 = " + timestamp1 + ", timestamp2 = " + timestamp2  + ", window.performance.now() = " + window.performance.now());
+                failed = true;
+            }
+        }
+        
+        window.jsTestIsAsync = true;
+        requestAnimationFrame(doAnimation1);
+    </script>
+    <script src="../resources/js-test-post.js"></script>
+</body>
+</html>
index 6a0661d..031faa0 100644 (file)
@@ -1,3 +1,69 @@
+2016-06-23  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        requestFrameAnimation() callback timestamp should be very close to Performance.now() 
+        https://bugs.webkit.org/show_bug.cgi?id=159038
+
+        Reviewed by Simon Fraser.
+
+        Pass the Performance.now() to requestFrameAnimation() callback. Do not add
+        the timeUntilOutput which is the difference between outputTime and now since
+        this addition makes us report a timestamp ahead in the future by almost 33ms.
+
+        A new function named "nowTimestamp()" is added to the DOMWindow class. It
+        calls Performance.now() if WEB_TIMING is enabled, otherwise it calls
+        monotonicallyIncreasingTime(). The returned timestamp is seconds and it is
+        relative to the document loading time.
+
+        The timestamp passing will be removed all the down till the callers of
+        ScriptedAnimationController::serviceScriptedAnimations(). The callers will
+        getting the now timestamp by calling DOMWindow::nowTimestamp().
+
+        Tests: animations/animation-callback-timestamp.html
+               animations/animation-multiple-callbacks-timestamp.html
+
+        * dom/Document.cpp:
+        (WebCore::Document::monotonicTimestamp):
+        (WebCore::Document::serviceScriptedAnimations):
+        * dom/Document.h:
+        * dom/ScriptedAnimationController.cpp:
+        (WebCore::ScriptedAnimationController::serviceScriptedAnimations):
+        (WebCore::ScriptedAnimationController::animationTimerFired):
+        (WebCore::ScriptedAnimationController::displayRefreshFired):
+        * dom/ScriptedAnimationController.h:
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::getVideoPlaybackQuality):
+        * loader/DocumentLoadTiming.h:
+        (WebCore::DocumentLoadTiming::referenceWallTime):
+        * page/DOMWindow.cpp:
+        (WebCore::DOMWindow::nowTimestamp):
+        * page/DOMWindow.h:
+        * page/FrameView.cpp:
+        (WebCore::FrameView::serviceScriptedAnimations):
+        * page/FrameView.h:
+        * platform/graphics/DisplayRefreshMonitor.cpp:
+        (WebCore::DisplayRefreshMonitor::DisplayRefreshMonitor):
+        (WebCore::DisplayRefreshMonitor::displayDidRefresh):
+        * platform/graphics/DisplayRefreshMonitor.h:
+        (WebCore::DisplayRefreshMonitor::setMonotonicAnimationStartTime): Deleted.
+        * platform/graphics/DisplayRefreshMonitorClient.cpp:
+        (WebCore::DisplayRefreshMonitorClient::fireDisplayRefreshIfNeeded):
+        * platform/graphics/DisplayRefreshMonitorClient.h:
+        * platform/graphics/GraphicsLayerUpdater.cpp:
+        (WebCore::GraphicsLayerUpdater::displayRefreshFired):
+        * platform/graphics/GraphicsLayerUpdater.h:
+        * platform/graphics/ios/DisplayRefreshMonitorIOS.h:
+        * platform/graphics/ios/DisplayRefreshMonitorIOS.mm:
+        (-[WebDisplayLinkHandler handleDisplayLink:]):
+        (WebCore::DisplayRefreshMonitorIOS::displayLinkFired):
+        (WebCore::mediaTimeToCurrentTime): Deleted.
+        * platform/graphics/mac/DisplayRefreshMonitorMac.cpp:
+        (WebCore::displayLinkCallback):
+        (WebCore::DisplayRefreshMonitorMac::displayLinkFired):
+        * platform/graphics/mac/DisplayRefreshMonitorMac.h:
+        * platform/graphics/texmap/coordinated/CompositingCoordinator.cpp:
+        (WebCore::CompositingCoordinator::syncDisplayState):
+        (WebCore::CompositingCoordinator::nextAnimationServiceTime):
+
 2016-06-23  David Kilzer  <ddkilzer@apple.com>
 
         Remove unused HarfBuzzFaceCoreText.cpp
index 5bc4387..d0424ce 100644 (file)
@@ -6164,6 +6164,12 @@ void Document::loadEventDelayTimerFired()
         frame()->loader().checkCompleted();
 }
 
+double Document::monotonicTimestamp() const
+{
+    auto* loader = this->loader();
+    return loader ? loader->timing().monotonicTimeToZeroBasedDocumentTime(monotonicallyIncreasingTime()) : 0;
+}
+
 #if ENABLE(REQUEST_ANIMATION_FRAME)
 int Document::requestAnimationFrame(PassRefPtr<RequestAnimationFrameCallback> callback)
 {
@@ -6190,11 +6196,11 @@ void Document::cancelAnimationFrame(int id)
     m_scriptedAnimationController->cancelCallback(id);
 }
 
-void Document::serviceScriptedAnimations(double monotonicAnimationStartTime)
+void Document::serviceScriptedAnimations(double timestamp)
 {
     if (!m_scriptedAnimationController)
         return;
-    m_scriptedAnimationController->serviceScriptedAnimations(monotonicAnimationStartTime);
+    m_scriptedAnimationController->serviceScriptedAnimations(timestamp);
 }
 
 void Document::clearScriptedAnimationController()
index 57276be..6e2f52e 100644 (file)
@@ -1166,10 +1166,12 @@ public:
     const DocumentTiming& timing() const { return m_documentTiming; }
 #endif
 
+    double monotonicTimestamp() const;
+
 #if ENABLE(REQUEST_ANIMATION_FRAME)
     int requestAnimationFrame(PassRefPtr<RequestAnimationFrameCallback>);
     void cancelAnimationFrame(int id);
-    void serviceScriptedAnimations(double monotonicAnimationStartTime);
+    void serviceScriptedAnimations(double timestamp);
 #endif
 
     void sendWillRevealEdgeEventsIfNeeded(const IntPoint& oldPosition, const IntPoint& newPosition, const IntRect& visibleRect, const IntSize& contentsSize, Element* target = nullptr);
index ecd1942..71782f2 100644 (file)
@@ -28,6 +28,7 @@
 
 #if ENABLE(REQUEST_ANIMATION_FRAME)
 
+#include "DOMWindow.h"
 #include "DisplayRefreshMonitor.h"
 #include "DisplayRefreshMonitorManager.h"
 #include "Document.h"
@@ -140,15 +141,15 @@ void ScriptedAnimationController::cancelCallback(CallbackId id)
     }
 }
 
-void ScriptedAnimationController::serviceScriptedAnimations(double monotonicTimeNow)
+void ScriptedAnimationController::serviceScriptedAnimations(double timestamp)
 {
     if (!m_callbacks.size() || m_suspendCount || !requestAnimationFrameEnabled())
         return;
 
     TraceScope tracingScope(RAFCallbackStart, RAFCallbackEnd);
-    
-    double highResNowMs = 1000.0 * m_document->loader()->timing().monotonicTimeToZeroBasedDocumentTime(monotonicTimeNow);
-    double legacyHighResNowMs = 1000.0 * m_document->loader()->timing().monotonicTimeToPseudoWallTime(monotonicTimeNow);
+
+    double highResNowMs = 1000 * timestamp;
+    double legacyHighResNowMs = 1000 * (timestamp + m_document->loader()->timing().referenceWallTime());
 
     // First, generate a list of callbacks to consider.  Callbacks registered from this point
     // on are considered only for the "next" frame, not this one.
@@ -216,7 +217,7 @@ void ScriptedAnimationController::scheduleAnimation()
         animationInterval = MinimumThrottledAnimationInterval;
 #endif
 
-    double scheduleDelay = std::max<double>(animationInterval - (monotonicallyIncreasingTime() - m_lastAnimationFrameTimeMonotonic), 0);
+    double scheduleDelay = std::max<double>(animationInterval - (m_document->domWindow()->nowTimestamp() - m_lastAnimationFrameTimestamp), 0);
     m_animationTimer.startOneShot(scheduleDelay);
 #else
     if (FrameView* frameView = m_document->view())
@@ -227,13 +228,13 @@ void ScriptedAnimationController::scheduleAnimation()
 #if USE(REQUEST_ANIMATION_FRAME_TIMER)
 void ScriptedAnimationController::animationTimerFired()
 {
-    m_lastAnimationFrameTimeMonotonic = monotonicallyIncreasingTime();
-    serviceScriptedAnimations(m_lastAnimationFrameTimeMonotonic);
+    m_lastAnimationFrameTimestamp = m_document->domWindow()->nowTimestamp();
+    serviceScriptedAnimations(m_lastAnimationFrameTimestamp);
 }
 #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
-void ScriptedAnimationController::displayRefreshFired(double monotonicTimeNow)
+void ScriptedAnimationController::displayRefreshFired()
 {
-    serviceScriptedAnimations(monotonicTimeNow);
+    serviceScriptedAnimations(m_document->domWindow()->nowTimestamp());
 }
 #endif
 #endif
index ce93b6c..08fd7b8 100644 (file)
@@ -64,7 +64,7 @@ public:
 
     CallbackId registerCallback(PassRefPtr<RequestAnimationFrameCallback>);
     void cancelCallback(CallbackId);
-    void serviceScriptedAnimations(double monotonicTimeNow);
+    void serviceScriptedAnimations(double timestamp);
 
     void suspend();
     void resume();
@@ -88,11 +88,11 @@ private:
 #if USE(REQUEST_ANIMATION_FRAME_TIMER)
     void animationTimerFired();
     Timer m_animationTimer;
-    double m_lastAnimationFrameTimeMonotonic { 0 };
+    double m_lastAnimationFrameTimestamp { 0 };
 
 #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
     // Override for DisplayRefreshMonitorClient
-    void displayRefreshFired(double timestamp) override;
+    void displayRefreshFired() override;
     RefPtr<DisplayRefreshMonitor> createDisplayRefreshMonitor(PlatformDisplayID) const override;
 
     bool m_isUsingTimer { false };
index 31444e0..fc85056 100644 (file)
@@ -6424,19 +6424,13 @@ void HTMLMediaElement::removeBehaviorsRestrictionsAfterFirstUserGesture(MediaEle
 #if ENABLE(MEDIA_SOURCE)
 RefPtr<VideoPlaybackQuality> HTMLMediaElement::getVideoPlaybackQuality()
 {
-#if ENABLE(WEB_TIMING)
     DOMWindow* domWindow = document().domWindow();
-    Performance* performance = domWindow ? domWindow->performance() : nullptr;
-    double now = performance ? performance->now() : 0;
-#else
-    DocumentLoader* loader = document().loader();
-    double now = loader ? 1000.0 * loader->timing().monotonicTimeToZeroBasedDocumentTime(monotonicallyIncreasingTime()) : 0;
-#endif
+    double timestamp = domWindow ? 1000 * domWindow->nowTimestamp() : 0;
 
     if (!m_player)
-        return VideoPlaybackQuality::create(now, 0, 0, 0, 0);
+        return VideoPlaybackQuality::create(timestamp, 0, 0, 0, 0);
 
-    return VideoPlaybackQuality::create(now,
+    return VideoPlaybackQuality::create(timestamp,
         m_droppedVideoFrames + m_player->totalVideoFrames(),
         m_droppedVideoFrames + m_player->droppedVideoFrames(),
         m_player->corruptedVideoFrames(),
index 1904a7a..6f7d9d7 100644 (file)
@@ -68,6 +68,7 @@ public:
     bool hasSameOriginAsPreviousDocument() const { return m_hasSameOriginAsPreviousDocument; }
 
     double referenceMonotonicTime() const { return m_referenceMonotonicTime; }
+    double referenceWallTime() const { return m_referenceWallTime; }
 
 private:
     double m_referenceMonotonicTime;
index f1ae742..4006726 100644 (file)
@@ -745,6 +745,15 @@ Performance* DOMWindow::performance() const
 }
 #endif
 
+double DOMWindow::nowTimestamp() const
+{
+#if ENABLE(WEB_TIMING)
+    return performance() ? performance()->now() / 1000 : 0;
+#else
+    return document() ? document()->monotonicTimestamp() : 0;
+#endif
+}
+
 Location* DOMWindow::location() const
 {
     if (!isCurrentlyDisplayedInFrame())
index 62a8928..77c8113 100644 (file)
@@ -316,6 +316,7 @@ namespace WebCore {
 #if ENABLE(WEB_TIMING)
         Performance* performance() const;
 #endif
+        double nowTimestamp() const;
 
 #if PLATFORM(IOS)
         void incrementScrollEventListenersCount();
index a311db0..e6ec707 100644 (file)
@@ -2829,19 +2829,23 @@ void FrameView::unscheduleRelayout()
 }
 
 #if ENABLE(REQUEST_ANIMATION_FRAME)
-void FrameView::serviceScriptedAnimations(double monotonicAnimationStartTime)
+void FrameView::serviceScriptedAnimations()
 {
     for (auto* frame = m_frame.ptr(); frame; frame = frame->tree().traverseNext()) {
         frame->view()->serviceScrollAnimations();
         frame->animation().serviceAnimations();
     }
 
+    if (!frame().document() || !frame().document()->domWindow())
+        return;
+
     Vector<RefPtr<Document>> documents;
     for (auto* frame = m_frame.ptr(); frame; frame = frame->tree().traverseNext())
         documents.append(frame->document());
 
+    double timestamp = frame().document()->domWindow()->nowTimestamp();
     for (auto& document : documents)
-        document->serviceScriptedAnimations(monotonicAnimationStartTime);
+        document->serviceScriptedAnimations(timestamp);
 }
 #endif
 
index f4449e5..9ad8a51 100644 (file)
@@ -149,7 +149,7 @@ public:
 #endif
 
 #if ENABLE(REQUEST_ANIMATION_FRAME)
-    WEBCORE_EXPORT void serviceScriptedAnimations(double monotonicAnimationStartTime);
+    WEBCORE_EXPORT void serviceScriptedAnimations();
 #endif
 
     void willRecalcStyle();
index d9a6226..2cbefcc 100644 (file)
@@ -56,8 +56,7 @@ RefPtr<DisplayRefreshMonitor> DisplayRefreshMonitor::create(DisplayRefreshMonito
 }
 
 DisplayRefreshMonitor::DisplayRefreshMonitor(PlatformDisplayID displayID)
-    : m_monotonicAnimationStartTime(0)
-    , m_active(true)
+    : m_active(true)
     , m_scheduled(false)
     , m_previousFrameDone(true)
     , m_unscheduledFireCount(0)
@@ -90,8 +89,6 @@ bool DisplayRefreshMonitor::removeClient(DisplayRefreshMonitorClient& client)
 
 void DisplayRefreshMonitor::displayDidRefresh()
 {
-    double monotonicAnimationStartTime;
-
     {
         LockHolder lock(m_mutex);
         if (!m_scheduled)
@@ -100,7 +97,6 @@ void DisplayRefreshMonitor::displayDidRefresh()
             m_unscheduledFireCount = 0;
 
         m_scheduled = false;
-        monotonicAnimationStartTime = m_monotonicAnimationStartTime;
     }
 
     // The call back can cause all our clients to be unregistered, so we need to protect
@@ -113,7 +109,7 @@ void DisplayRefreshMonitor::displayDidRefresh()
     m_clientsToBeNotified = &clientsToBeNotified;
     while (!clientsToBeNotified.isEmpty()) {
         DisplayRefreshMonitorClient* client = clientsToBeNotified.takeAny();
-        client->fireDisplayRefreshIfNeeded(monotonicAnimationStartTime);
+        client->fireDisplayRefreshIfNeeded();
 
         // This checks if this function was reentered. In that case, stop iterating
         // since it's not safe to use the set any more.
index ee09e7d..1218326 100644 (file)
@@ -70,8 +70,6 @@ public:
     bool isPreviousFrameDone() const { return m_previousFrameDone; }
     void setIsPreviousFrameDone(bool done) { m_previousFrameDone = done; }
 
-    void setMonotonicAnimationStartTime(double startTime) { m_monotonicAnimationStartTime = startTime; }
-
     Lock& mutex() { return m_mutex; }
 
     static RefPtr<DisplayRefreshMonitor> createDefaultDisplayRefreshMonitor(PlatformDisplayID);
@@ -83,7 +81,6 @@ protected:
 private:
     void displayDidRefresh();
 
-    double m_monotonicAnimationStartTime;
     bool m_active;
     bool m_scheduled;
     bool m_previousFrameDone;
index b51d68a..b08a3a8 100644 (file)
@@ -42,13 +42,13 @@ DisplayRefreshMonitorClient::~DisplayRefreshMonitorClient()
     DisplayRefreshMonitorManager::sharedManager().unregisterClient(*this);
 }
 
-void DisplayRefreshMonitorClient::fireDisplayRefreshIfNeeded(double timestamp)
+void DisplayRefreshMonitorClient::fireDisplayRefreshIfNeeded()
 {
     if (!m_scheduled)
         return;
 
     m_scheduled = false;
-    displayRefreshFired(timestamp);
+    displayRefreshFired();
 }
 
 }
index 2993d1d..c669dcb 100644 (file)
@@ -41,7 +41,7 @@ public:
     virtual ~DisplayRefreshMonitorClient();
 
     // Always called on the main thread.
-    virtual void displayRefreshFired(double timestamp) = 0;
+    virtual void displayRefreshFired() = 0;
 
     virtual RefPtr<DisplayRefreshMonitor> createDisplayRefreshMonitor(PlatformDisplayID) const = 0;
 
@@ -52,7 +52,7 @@ public:
     void setIsScheduled(bool isScheduled) { m_scheduled = isScheduled; }
     bool isScheduled() const { return m_scheduled; }
 
-    void fireDisplayRefreshIfNeeded(double timestamp);
+    void fireDisplayRefreshIfNeeded();
 
 private:
     bool m_scheduled { false };
index 0503305..a911bdd 100644 (file)
@@ -71,11 +71,9 @@ void GraphicsLayerUpdater::screenDidChange(PlatformDisplayID displayID)
 }
 
 #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
-void GraphicsLayerUpdater::displayRefreshFired(double timestamp)
+void GraphicsLayerUpdater::displayRefreshFired()
 {
-    UNUSED_PARAM(timestamp);
     m_scheduled = false;
-    
     m_client.flushLayersSoon(*this);
 }
 #endif
index 5d7e51f..472f2d3 100644 (file)
@@ -60,7 +60,7 @@ public:
 
 private:
 #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
-    void displayRefreshFired(double timestamp) override;
+    void displayRefreshFired() override;
     GraphicsLayerUpdaterClient& m_client;
 #endif
     bool m_scheduled { false };
index 0e07408..3f85cfc 100644 (file)
@@ -44,7 +44,7 @@ public:
     
     virtual ~DisplayRefreshMonitorIOS();
 
-    void displayLinkFired(double nowSeconds);
+    void displayLinkFired();
     bool requestRefreshCallback() override;
 
 private:
index 3a5e1ee..cd14864 100644 (file)
@@ -69,8 +69,9 @@ using namespace WebCore;
 
 - (void)handleDisplayLink:(CADisplayLink *)sender
 {
+    UNUSED_PARAM(sender);
     ASSERT(isMainThread());
-    m_monitor->displayLinkFired(sender.timestamp);
+    m_monitor->displayLinkFired();
 }
 
 - (void)invalidate
@@ -109,20 +110,12 @@ bool DisplayRefreshMonitorIOS::requestRefreshCallback()
     return true;
 }
 
-static double mediaTimeToCurrentTime(CFTimeInterval t)
-{
-    // FIXME: This may be a no-op if CACurrentMediaTime is *guaranteed* to be mach_absolute_time.
-    return monotonicallyIncreasingTime() + t - CACurrentMediaTime();
-}
-
-void DisplayRefreshMonitorIOS::displayLinkFired(double nowSeconds)
+void DisplayRefreshMonitorIOS::displayLinkFired()
 {
     if (!isPreviousFrameDone())
         return;
 
     setIsPreviousFrameDone(false);
-    setMonotonicAnimationStartTime(mediaTimeToCurrentTime(nowSeconds));
-
     handleDisplayRefreshedNotificationOnMainThread(this);
     
     TracePoint(RAFDisplayLinkFired);
index 5a8d66a..e31a1a9 100644 (file)
@@ -50,14 +50,10 @@ DisplayRefreshMonitorMac::~DisplayRefreshMonitorMac()
     }
 }
 
-static CVReturn displayLinkCallback(CVDisplayLinkRef, const CVTimeStamp* now, const CVTimeStamp* outputTime, CVOptionFlags, CVOptionFlags*, void* data)
+static CVReturn displayLinkCallback(CVDisplayLinkRef, const CVTimeStamp*, const CVTimeStamp*, CVOptionFlags, CVOptionFlags*, void* data)
 {
     DisplayRefreshMonitorMac* monitor = static_cast<DisplayRefreshMonitorMac*>(data);
-
-    double nowSeconds = static_cast<double>(now->videoTime) / static_cast<double>(now->videoTimeScale);
-    double outputTimeSeconds = static_cast<double>(outputTime->videoTime) / static_cast<double>(outputTime->videoTimeScale);
-    monitor->displayLinkFired(nowSeconds, outputTimeSeconds);
-
+    monitor->displayLinkFired();
     return kCVReturnSuccess;
 }
 
@@ -88,7 +84,7 @@ bool DisplayRefreshMonitorMac::requestRefreshCallback()
     return true;
 }
 
-void DisplayRefreshMonitorMac::displayLinkFired(double nowSeconds, double outputTimeSeconds)
+void DisplayRefreshMonitorMac::displayLinkFired()
 {
     LockHolder lock(mutex());
     if (!isPreviousFrameDone())
@@ -96,12 +92,6 @@ void DisplayRefreshMonitorMac::displayLinkFired(double nowSeconds, double output
 
     setIsPreviousFrameDone(false);
 
-    double webKitMonotonicNow = monotonicallyIncreasingTime();
-    double timeUntilOutput = outputTimeSeconds - nowSeconds;
-    // FIXME: Should this be using webKitMonotonicNow?
-    setMonotonicAnimationStartTime(webKitMonotonicNow + timeUntilOutput);
-
-
     // FIXME: Is it really okay to create a weakPtr on a background thread and then use it on the main thread?
     RunLoop::main().dispatch([weakPtr = m_weakFactory.createWeakPtr()] {
         if (auto* monitor = weakPtr.get())
index 115c4b2..df83b7e 100644 (file)
@@ -44,7 +44,7 @@ public:
     
     virtual ~DisplayRefreshMonitorMac();
 
-    void displayLinkFired(double nowSeconds, double outputTimeSeconds);
+    void displayLinkFired();
     bool requestRefreshCallback() override;
 
 private:
index ddeb0c3..c419339 100644 (file)
@@ -141,12 +141,20 @@ bool CompositingCoordinator::flushPendingLayerChanges()
     return didSync;
 }
 
+double CompositingCoordinator::timestamp() const
+{
+    auto* document = m_page->mainFrame().document();
+    if (!document)
+        return 0;
+    return document->domWindow() ? document->domWindow()->nowTimestamp() : document->monotonicTimestamp();
+}
+
 void CompositingCoordinator::syncDisplayState()
 {
 #if ENABLE(REQUEST_ANIMATION_FRAME) && !USE(REQUEST_ANIMATION_FRAME_TIMER) && !USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
     // Make sure that any previously registered animation callbacks are being executed before we flush the layers.
-    m_lastAnimationServiceTime = WTF::monotonicallyIncreasingTime();
-    m_page->mainFrame().view()->serviceScriptedAnimations(m_lastAnimationServiceTime);
+    m_lastAnimationServiceTime = timestamp();
+    m_page->mainFrame().view()->serviceScriptedAnimations();
 #endif
     m_page->mainFrame().view()->updateLayoutAndStyleIfNeededRecursive();
 }
@@ -156,7 +164,7 @@ double CompositingCoordinator::nextAnimationServiceTime() const
 {
     // According to the requestAnimationFrame spec, rAF callbacks should not be faster than 60FPS.
     static const double MinimalTimeoutForAnimations = 1. / 60.;
-    return std::max<double>(0., MinimalTimeoutForAnimations - WTF::monotonicallyIncreasingTime() + m_lastAnimationServiceTime);
+    return std::max<double>(0., MinimalTimeoutForAnimations - timestamp() + m_lastAnimationServiceTime);
 }
 #endif
 
index 3aa866e..984af2f 100644 (file)
@@ -125,6 +125,8 @@ private:
 
     void releaseInactiveAtlasesTimerFired();
 
+    double timestamp() const;
+
     Page* m_page;
     CompositingCoordinator::Client* m_client;
 
index 22e0e36..be637c3 100644 (file)
@@ -1,3 +1,13 @@
+2016-06-23  Said Abou-Hallawa  <sabouhallawa@apple.com>
+
+        requestFrameAnimation() callback timestamp should be very close to Performance.now() 
+        https://bugs.webkit.org/show_bug.cgi?id=159038
+
+        Reviewed by Simon Fraser.
+
+        * WebProcess/WebPage/Cocoa/RemoteLayerTreeDisplayRefreshMonitor.mm:
+        (WebKit::RemoteLayerTreeDisplayRefreshMonitor::didUpdateLayers):
+
 2016-06-23  Chris Dumez  <cdumez@apple.com>
 
         [iOS] A WebPageProxy in closed state should not be allowed to hold a process assertion
index bf2f724..892d657 100644 (file)
@@ -67,8 +67,6 @@ void RemoteLayerTreeDisplayRefreshMonitor::didUpdateLayers()
         return;
 
     setIsPreviousFrameDone(false);
-    setMonotonicAnimationStartTime(monotonicallyIncreasingTime());
-
     handleDisplayRefreshedNotificationOnMainThread(this);
 }