Sync requestAnimationFrame callback to CVDisplayLink on Mac
authorcmarrin@apple.com <cmarrin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 13 Oct 2011 21:59:25 +0000 (21:59 +0000)
committercmarrin@apple.com <cmarrin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 13 Oct 2011 21:59:25 +0000 (21:59 +0000)
https://bugs.webkit.org/show_bug.cgi?id=68911

Reviewed by Simon Fraser.

Source/JavaScriptCore:

Add REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR for implementations
that use the DisplayRefreshMonitor logic.

* wtf/Platform.h:

Source/WebCore:

Test: fast/animation/request-animation-frame-iframe.html

Implement CVDisplayLink which checks to see if any scheduleAnimation requests
have come in. If so, remember the timestamp and do a callOnMainThread to fire
the callbacks. A DisplayRefreshMonitorManager is a singleton which has a list
of DisplayRefreshMonitors, one for each display. Each monitor has one or more
DisplayRefreshMonitorClients, which is a abstract virtual class implemented
by ScriptAnimationController. When an animation is scheduled, the
displayRefreshFired method is called on the client, which in turn calls the
requestAnimationFrame callbacks.

DisplayRefreshMonitor and therefore the CVDisplayLink it owns is discarded
when it no longer has any clients. This minimizes the number of concurrent
CVDisplayLink threads.

* WebCore.exp.in:
* WebCore.xcodeproj/project.pbxproj:
* dom/Document.cpp:
(WebCore::Document::windowScreenDidChange):
(WebCore::Document::webkitRequestAnimationFrame):
* dom/Document.h:
* dom/ScriptedAnimationController.cpp:
(WebCore::ScriptedAnimationController::ScriptedAnimationController):
(WebCore::ScriptedAnimationController::windowScreenDidChange):
(WebCore::ScriptedAnimationController::scheduleAnimation):
* dom/ScriptedAnimationController.h:
(WebCore::ScriptedAnimationController::displayRefreshFired):
* page/Page.cpp:
(WebCore::Page::Page):
(WebCore::Page::windowScreenDidChange):
* page/Page.h:
(WebCore::Page::displayID):
* platform/PlatformScreen.h:
* platform/graphics/DisplayRefreshMonitor.cpp: Added.
(WebCore::DisplayRefreshMonitorClient::DisplayRefreshMonitorClient):
(WebCore::DisplayRefreshMonitorClient::~DisplayRefreshMonitorClient):
(WebCore::DisplayRefreshMonitorClient::fireDisplayRefreshIfNeeded):
(WebCore::DisplayRefreshMonitor::DisplayRefreshMonitor):
(WebCore::DisplayRefreshMonitor::refreshDisplayOnMainThread):
(WebCore::DisplayRefreshMonitorManager::sharedManager):
(WebCore::DisplayRefreshMonitorManager::findMonitor):
(WebCore::DisplayRefreshMonitorManager::registerClient):
(WebCore::DisplayRefreshMonitorManager::unregisterClient):
(WebCore::DisplayRefreshMonitorManager::scheduleAnimation):
(WebCore::DisplayRefreshMonitorManager::windowScreenDidChange):
* platform/graphics/DisplayRefreshMonitor.h: Added.
(WebCore::DisplayRefreshMonitorClient::scheduleAnimation):
(WebCore::DisplayRefreshMonitor::hasClients):
(WebCore::DisplayRefreshMonitor::addClient):
(WebCore::DisplayRefreshMonitor::removeClient):
(WebCore::DisplayRefreshMonitor::displayID):
(WebCore::DisplayRefreshMonitorManager::DisplayRefreshMonitorManager):
* platform/graphics/mac/DisplayRefreshMonitorMac.cpp: Added.
(WebCore::DisplayRefreshMonitor::displayLinkCallback):
(WebCore::DisplayRefreshMonitor::~DisplayRefreshMonitor):
(WebCore::DisplayRefreshMonitor::scheduleAnimation):

Source/WebKit/mac:

Add windowDidChangeScreen function which listens for the window changing
screens and passes the new displayID along to WebCore::Page. It also sends
one on windowWillOrderOnScreen, so the Page has a fresh displayID after it's
created.

* WebView/WebView.mm:
(-[WebView addWindowObserversForWindow:]):
(-[WebView removeWindowObservers]):
(-[WebView _windowDidChangeScreen:]):
(-[WebView _windowWillOrderOnScreen:]):

Source/WebKit2:

Add windowDidChangeScreen function which listens for the window changing
screens and passes the new displayID along to WebCore::Page. It also sends
one on windowDidBecomeKey, so the Page has a fresh displayID after it's
created. Event is generated in the UIProcess and then sent over to the
WebProcess, which actually sends it to WebCore::Page.

* UIProcess/API/mac/WKView.mm:
(-[WKView addWindowObserversForWindow:]):
(-[WKView removeWindowObservers]):
(-[WKView _windowDidChangeScreen:]):
(-[WKView _windowDidBecomeKey:]):
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::windowScreenDidChange):
* UIProcess/WebPageProxy.h:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::windowScreenDidChange):
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:

LayoutTests:

Test to make sure requestAnimationFrame events fire inside iframe

* fast/animation/request-animation-frame-iframe-expected.txt: Added.
* fast/animation/request-animation-frame-iframe.html: Added.
* fast/animation/script-tests/request-animation-frame-subframe.html: Added.

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

28 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/animation/request-animation-frame-iframe-expected.txt [new file with mode: 0644]
LayoutTests/fast/animation/request-animation-frame-iframe.html [new file with mode: 0644]
LayoutTests/fast/animation/script-tests/request-animation-frame-subframe.html [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/wtf/Platform.h
Source/WebCore/ChangeLog
Source/WebCore/WebCore.exp.in
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h
Source/WebCore/dom/ScriptedAnimationController.cpp
Source/WebCore/dom/ScriptedAnimationController.h
Source/WebCore/page/Page.cpp
Source/WebCore/page/Page.h
Source/WebCore/platform/PlatformScreen.h
Source/WebCore/platform/graphics/DisplayRefreshMonitor.cpp [new file with mode: 0644]
Source/WebCore/platform/graphics/DisplayRefreshMonitor.h [new file with mode: 0644]
Source/WebCore/platform/graphics/mac/DisplayRefreshMonitorMac.cpp [new file with mode: 0644]
Source/WebKit/mac/ChangeLog
Source/WebKit/mac/WebView/WebView.mm
Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/mac/WKView.mm
Source/WebKit2/UIProcess/WebPageProxy.cpp
Source/WebKit2/UIProcess/WebPageProxy.h
Source/WebKit2/WebProcess/WebPage/WebPage.cpp
Source/WebKit2/WebProcess/WebPage/WebPage.h
Source/WebKit2/WebProcess/WebPage/WebPage.messages.in

index 70979c1..618e61f 100644 (file)
@@ -1,3 +1,16 @@
+2011-10-12  Chris Marrin  <cmarrin@apple.com>
+
+        Sync requestAnimationFrame callback to CVDisplayLink on Mac
+        https://bugs.webkit.org/show_bug.cgi?id=68911
+
+        Reviewed by Simon Fraser.
+
+        Test to make sure requestAnimationFrame events fire inside iframe
+
+        * fast/animation/request-animation-frame-iframe-expected.txt: Added.
+        * fast/animation/request-animation-frame-iframe.html: Added.
+        * fast/animation/script-tests/request-animation-frame-subframe.html: Added.
+
 2011-10-12  Abhishek Arya  <inferno@chromium.org>
 
         Register custom fonts at their creation time,
diff --git a/LayoutTests/fast/animation/request-animation-frame-iframe-expected.txt b/LayoutTests/fast/animation/request-animation-frame-iframe-expected.txt
new file mode 100644 (file)
index 0000000..72b438d
--- /dev/null
@@ -0,0 +1,10 @@
+Tests requestAnimationFrame in an iframe
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS callbackInvoked is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/fast/animation/request-animation-frame-iframe.html b/LayoutTests/fast/animation/request-animation-frame-iframe.html
new file mode 100644 (file)
index 0000000..9a2336d
--- /dev/null
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link rel="stylesheet" href="../js/resources/js-test-style.css">
+<script src="../js/resources/js-test-pre.js"></script>
+</head>
+<body>
+    <p id="description"></p>
+    <div id="console"></div>
+    <iframe src="script-tests/request-animation-frame-subframe.html" width="700" height="500"></iframe>
+    <script type="text/javascript" charset="utf-8">
+        description("Tests requestAnimationFrame in an iframe");
+
+        var callbackInvoked = false;
+    
+        if (window.layoutTestController) {
+            layoutTestController.dumpAsText();
+            layoutTestController.waitUntilDone();
+        }
+
+        // Called from subframe.
+        function doDisplay()
+        {
+            if (window.layoutTestController)
+                layoutTestController.display();
+        }
+    
+        function doCheckResult()
+        {
+            shouldBeTrue("callbackInvoked");
+        }
+    
+        function doTestDone()
+        {
+            isSuccessfullyParsed();
+            if (window.layoutTestController)
+                layoutTestController.notifyDone();
+        }
+
+        var successfullyParsed = true;
+    </script>
+
+    <script src="../js/resources/js-test-post-function.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/animation/script-tests/request-animation-frame-subframe.html b/LayoutTests/fast/animation/script-tests/request-animation-frame-subframe.html
new file mode 100644 (file)
index 0000000..7a6d9c2
--- /dev/null
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link rel="stylesheet" href="../../js/resources/js-test-style.css">
+<script src="../../js/resources/js-test-pre.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<span id="e"></span>
+<span id="f"></span>
+<script>
+    var e = document.getElementById("e");
+    window.webkitRequestAnimationFrame(function() {
+        parent.callbackInvoked = true;
+    }, e);
+
+    parent.doDisplay();
+    
+    setTimeout(function() {
+        parent.doCheckResult();
+    }, 100);
+
+    setTimeout(function() {
+        parent.doTestDone();
+    }, 200);    
+</script>
+</body>
+</html>
index 2e308dc..ef9b60a 100644 (file)
@@ -1,3 +1,15 @@
+2011-10-13  Chris Marrin  <cmarrin@apple.com>
+
+        Sync requestAnimationFrame callback to CVDisplayLink on Mac
+        https://bugs.webkit.org/show_bug.cgi?id=68911
+
+        Reviewed by Simon Fraser.
+
+        Add REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR for implementations
+        that use the DisplayRefreshMonitor logic.
+
+        * wtf/Platform.h:
+
 2011-10-13  Gavin Barraclough  <baraclough@apple.com>
 
         terminateSpeculativeExecution for fillSpeculateDouble with DataFormatCell
index 0cdfcfd..1fe2352 100644 (file)
 
 #if PLATFORM(MAC) || PLATFORM(GTK) || (PLATFORM(WIN) && !OS(WINCE) && !PLATFORM(WIN_CAIRO))
 #define WTF_USE_REQUEST_ANIMATION_FRAME_TIMER 1
-#define WTF_USE_REQUEST_ANIMATION_FRAME_TIMER 1
+#endif
+
+#if PLATFORM(MAC)
+#define WTF_USE_REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR 1
 #endif
 
 #if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
index 07f3c0d..723cdf9 100644 (file)
@@ -1,3 +1,67 @@
+2011-10-12  Chris Marrin  <cmarrin@apple.com>
+
+        Sync requestAnimationFrame callback to CVDisplayLink on Mac
+        https://bugs.webkit.org/show_bug.cgi?id=68911
+
+        Reviewed by Simon Fraser.
+
+        Test: fast/animation/request-animation-frame-iframe.html
+
+        Implement CVDisplayLink which checks to see if any scheduleAnimation requests
+        have come in. If so, remember the timestamp and do a callOnMainThread to fire
+        the callbacks. A DisplayRefreshMonitorManager is a singleton which has a list
+        of DisplayRefreshMonitors, one for each display. Each monitor has one or more
+        DisplayRefreshMonitorClients, which is a abstract virtual class implemented
+        by ScriptAnimationController. When an animation is scheduled, the
+        displayRefreshFired method is called on the client, which in turn calls the
+        requestAnimationFrame callbacks. 
+
+        DisplayRefreshMonitor and therefore the CVDisplayLink it owns is discarded
+        when it no longer has any clients. This minimizes the number of concurrent
+        CVDisplayLink threads.
+
+        * WebCore.exp.in:
+        * WebCore.xcodeproj/project.pbxproj:
+        * dom/Document.cpp:
+        (WebCore::Document::windowScreenDidChange):
+        (WebCore::Document::webkitRequestAnimationFrame):
+        * dom/Document.h:
+        * dom/ScriptedAnimationController.cpp:
+        (WebCore::ScriptedAnimationController::ScriptedAnimationController):
+        (WebCore::ScriptedAnimationController::windowScreenDidChange):
+        (WebCore::ScriptedAnimationController::scheduleAnimation):
+        * dom/ScriptedAnimationController.h:
+        (WebCore::ScriptedAnimationController::displayRefreshFired):
+        * page/Page.cpp:
+        (WebCore::Page::Page):
+        (WebCore::Page::windowScreenDidChange):
+        * page/Page.h:
+        (WebCore::Page::displayID):
+        * platform/PlatformScreen.h:
+        * platform/graphics/DisplayRefreshMonitor.cpp: Added.
+        (WebCore::DisplayRefreshMonitorClient::DisplayRefreshMonitorClient):
+        (WebCore::DisplayRefreshMonitorClient::~DisplayRefreshMonitorClient):
+        (WebCore::DisplayRefreshMonitorClient::fireDisplayRefreshIfNeeded):
+        (WebCore::DisplayRefreshMonitor::DisplayRefreshMonitor):
+        (WebCore::DisplayRefreshMonitor::refreshDisplayOnMainThread):
+        (WebCore::DisplayRefreshMonitorManager::sharedManager):
+        (WebCore::DisplayRefreshMonitorManager::findMonitor):
+        (WebCore::DisplayRefreshMonitorManager::registerClient):
+        (WebCore::DisplayRefreshMonitorManager::unregisterClient):
+        (WebCore::DisplayRefreshMonitorManager::scheduleAnimation):
+        (WebCore::DisplayRefreshMonitorManager::windowScreenDidChange):
+        * platform/graphics/DisplayRefreshMonitor.h: Added.
+        (WebCore::DisplayRefreshMonitorClient::scheduleAnimation):
+        (WebCore::DisplayRefreshMonitor::hasClients):
+        (WebCore::DisplayRefreshMonitor::addClient):
+        (WebCore::DisplayRefreshMonitor::removeClient):
+        (WebCore::DisplayRefreshMonitor::displayID):
+        (WebCore::DisplayRefreshMonitorManager::DisplayRefreshMonitorManager):
+        * platform/graphics/mac/DisplayRefreshMonitorMac.cpp: Added.
+        (WebCore::DisplayRefreshMonitor::displayLinkCallback):
+        (WebCore::DisplayRefreshMonitor::~DisplayRefreshMonitor):
+        (WebCore::DisplayRefreshMonitor::scheduleAnimation):
+
 2011-10-13  Abhishek Arya  <inferno@chromium.org>
 
         Unreviewed. Qt compile fix.
index 203c7a6..e473ba9 100644 (file)
@@ -732,6 +732,7 @@ __ZN7WebCore4Page20removeScrollableAreaEPNS_14ScrollableAreaE
 __ZN7WebCore4Page20setDeviceScaleFactorEf
 __ZN7WebCore4Page20unmarkAllTextMatchesEv
 __ZN7WebCore4Page21markAllMatchesForTextERKN3WTF6StringEjbj
+__ZN7WebCore4Page21windowScreenDidChangeEj
 __ZN7WebCore4Page22allVisitedStateChangedEPNS_9PageGroupE
 __ZN7WebCore4Page23clearUndoRedoOperationsEv
 __ZN7WebCore4Page27setJavaScriptURLsAreAllowedEb
index 4090491..024a8f1 100644 (file)
                49A5A4FE13E2F01E00CFDAE0 /* PeerConnection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49A5A4F813E2F01E00CFDAE0 /* PeerConnection.cpp */; };
                49A5A4FF13E2F01E00CFDAE0 /* PeerConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 49A5A4F913E2F01E00CFDAE0 /* PeerConnection.h */; };
                49A5A50113E2F01E00CFDAE0 /* SignalingCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = 49A5A4FB13E2F01E00CFDAE0 /* SignalingCallback.h */; };
+               49AF2D6914435D050016A784 /* DisplayRefreshMonitor.h in Headers */ = {isa = PBXBuildFile; fileRef = 49AF2D6814435D050016A784 /* DisplayRefreshMonitor.h */; };
+               49AF2D6C14435D210016A784 /* DisplayRefreshMonitorMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49AF2D6B14435D210016A784 /* DisplayRefreshMonitorMac.cpp */; };
                49BE30D213D9747B003808A9 /* JSPeerConnectionCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49BE30D113D9747B003808A9 /* JSPeerConnectionCustom.cpp */; };
                49BE30F313D97646003808A9 /* JSPeerConnection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49BE30EF13D97646003808A9 /* JSPeerConnection.cpp */; };
                49BE30F413D97646003808A9 /* JSPeerConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 49BE30F013D97646003808A9 /* JSPeerConnection.h */; };
                49EED14E1051971A00099FAB /* JSCanvasRenderingContext2DCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49EED14B1051971900099FAB /* JSCanvasRenderingContext2DCustom.cpp */; };
                49EED14F1051971A00099FAB /* JSWebGLRenderingContextCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49EED14C1051971A00099FAB /* JSWebGLRenderingContextCustom.cpp */; };
                49EED1501051971A00099FAB /* JSCanvasRenderingContextCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49EED14D1051971A00099FAB /* JSCanvasRenderingContextCustom.cpp */; };
+               49FC7A501444AF5F00A5D864 /* DisplayRefreshMonitor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49FC7A4F1444AF5F00A5D864 /* DisplayRefreshMonitor.cpp */; };
                49FFBF1D11C8550E006A7118 /* GraphicsContext3DMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 49FFBF1C11C8550E006A7118 /* GraphicsContext3DMac.mm */; };
                49FFBF3F11C93EE3006A7118 /* WebGLLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 49FFBF3D11C93EE3006A7118 /* WebGLLayer.h */; };
                49FFBF4011C93EE3006A7118 /* WebGLLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 49FFBF3E11C93EE3006A7118 /* WebGLLayer.mm */; };
                49A5A4FA13E2F01E00CFDAE0 /* PeerConnection.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = PeerConnection.idl; path = p2p/PeerConnection.idl; sourceTree = "<group>"; };
                49A5A4FB13E2F01E00CFDAE0 /* SignalingCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SignalingCallback.h; path = p2p/SignalingCallback.h; sourceTree = "<group>"; };
                49A5A4FC13E2F01E00CFDAE0 /* SignalingCallback.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = SignalingCallback.idl; path = p2p/SignalingCallback.idl; sourceTree = "<group>"; };
+               49AF2D6814435D050016A784 /* DisplayRefreshMonitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DisplayRefreshMonitor.h; sourceTree = "<group>"; };
+               49AF2D6B14435D210016A784 /* DisplayRefreshMonitorMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DisplayRefreshMonitorMac.cpp; sourceTree = "<group>"; };
                49BE30D113D9747B003808A9 /* JSPeerConnectionCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPeerConnectionCustom.cpp; sourceTree = "<group>"; };
                49BE30EF13D97646003808A9 /* JSPeerConnection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPeerConnection.cpp; sourceTree = "<group>"; };
                49BE30F013D97646003808A9 /* JSPeerConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPeerConnection.h; sourceTree = "<group>"; };
                49EED14B1051971900099FAB /* JSCanvasRenderingContext2DCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCanvasRenderingContext2DCustom.cpp; sourceTree = "<group>"; };
                49EED14C1051971A00099FAB /* JSWebGLRenderingContextCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWebGLRenderingContextCustom.cpp; sourceTree = "<group>"; };
                49EED14D1051971A00099FAB /* JSCanvasRenderingContextCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCanvasRenderingContextCustom.cpp; sourceTree = "<group>"; };
+               49FC7A4F1444AF5F00A5D864 /* DisplayRefreshMonitor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DisplayRefreshMonitor.cpp; sourceTree = "<group>"; };
                49FFBF1C11C8550E006A7118 /* GraphicsContext3DMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GraphicsContext3DMac.mm; sourceTree = "<group>"; };
                49FFBF3D11C93EE3006A7118 /* WebGLLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebGLLayer.h; sourceTree = "<group>"; };
                49FFBF3E11C93EE3006A7118 /* WebGLLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebGLLayer.mm; sourceTree = "<group>"; };
                                37C2360F1097EE7700EF9F72 /* ComplexTextController.h */,
                                37C2381F1098C84200EF9F72 /* ComplexTextControllerATSUI.cpp */,
                                37C238201098C84200EF9F72 /* ComplexTextControllerCoreText.mm */,
+                               49AF2D6B14435D210016A784 /* DisplayRefreshMonitorMac.cpp */,
                                B275354B0B053814002CE64F /* FloatPointMac.mm */,
                                B275354C0B053814002CE64F /* FloatRectMac.mm */,
                                B275354D0B053814002CE64F /* FloatSizeMac.mm */,
                                B27535390B053814002CE64F /* Color.h */,
                                9382DF5710A8D5C900925652 /* ColorSpace.h */,
                                A8CB41020E85B8A50032C4F0 /* DashArray.h */,
+                               49FC7A4F1444AF5F00A5D864 /* DisplayRefreshMonitor.cpp */,
+                               49AF2D6814435D050016A784 /* DisplayRefreshMonitor.h */,
                                6E67D2A81280E8BD008758F7 /* Extensions3D.h */,
                                B275353A0B053814002CE64F /* FloatPoint.cpp */,
                                B275353B0B053814002CE64F /* FloatPoint.h */,
                                31060379143281CD00ABF4BA /* DOMWebKitCSSFilterValue.h in Headers */,
                                3106037B143281CD00ABF4BA /* DOMWebKitCSSFilterValueInternal.h in Headers */,
                                29ACB212143E7128006BCA5F /* AccessibilityMockObject.h in Headers */,
+                               49AF2D6914435D050016A784 /* DisplayRefreshMonitor.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                3106037A143281CD00ABF4BA /* DOMWebKitCSSFilterValue.mm in Sources */,
                                29ACB214143E7498006BCA5F /* AccessibilityMockObject.cpp in Sources */,
                                0F09087F1444FDB200028917 /* ScrollbarTheme.cpp in Sources */,
+                               49AF2D6C14435D210016A784 /* DisplayRefreshMonitorMac.cpp in Sources */,
+                               49FC7A501444AF5F00A5D864 /* DisplayRefreshMonitor.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index bcacfda..1699b56 100644 (file)
@@ -4758,6 +4758,15 @@ void Document::resumeScriptedAnimationControllerCallbacks()
 #endif
 }
 
+void Document::windowScreenDidChange(PlatformDisplayID displayID)
+{
+#if ENABLE(REQUEST_ANIMATION_FRAME)
+    if (m_scriptedAnimationController)
+        m_scriptedAnimationController->windowScreenDidChange(displayID);
+#endif
+}
+
+
 String Document::displayStringModifiedByEncoding(const String& str) const
 {
     if (m_decoder)
@@ -5087,7 +5096,7 @@ void Document::loadEventDelayTimerFired(Timer<Document>*)
 int Document::webkitRequestAnimationFrame(PassRefPtr<RequestAnimationFrameCallback> callback, Element* animationElement)
 {
     if (!m_scriptedAnimationController)
-        m_scriptedAnimationController = ScriptedAnimationController::create(this);
+        m_scriptedAnimationController = ScriptedAnimationController::create(this, page()->displayID());
 
     return m_scriptedAnimationController->registerCallback(callback, animationElement);
 }
index b565b26..e93cb51 100644 (file)
@@ -38,6 +38,7 @@
 #include "IntRect.h"
 #include "LayoutTypes.h"
 #include "PageVisibilityState.h"
+#include "PlatformScreen.h"
 #include "QualifiedName.h"
 #include "ScriptExecutionContext.h"
 #include "StringWithDirection.h"
@@ -939,6 +940,8 @@ public:
 
     virtual void suspendScriptedAnimationControllerCallbacks();
     virtual void resumeScriptedAnimationControllerCallbacks();
+    
+    void windowScreenDidChange(PlatformDisplayID);
 
     virtual void finishedParsing();
 
index 6ecf47b..3e50a88 100644 (file)
@@ -46,15 +46,19 @@ using namespace std;
 
 namespace WebCore {
 
-ScriptedAnimationController::ScriptedAnimationController(Document* document)
+ScriptedAnimationController::ScriptedAnimationController(Document* document, PlatformDisplayID displayID)
     : m_document(document)
     , m_nextCallbackId(0)
     , m_suspendCount(0)
 #if USE(REQUEST_ANIMATION_FRAME_TIMER)
     , m_animationTimer(this, &ScriptedAnimationController::animationTimerFired)
     , m_lastAnimationFrameTime(0)
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+    , m_useTimer(false)
+#endif
 #endif
 {
+    windowScreenDidChange(displayID);
 }
 
 void ScriptedAnimationController::suspend()
@@ -146,9 +150,29 @@ void ScriptedAnimationController::serviceScriptedAnimations(DOMTimeStamp time)
         scheduleAnimation();
 }
     
+void ScriptedAnimationController::windowScreenDidChange(PlatformDisplayID displayID)
+{
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+    DisplayRefreshMonitorManager::sharedManager()->windowScreenDidChange(displayID, this);
+#else
+    UNUSED_PARAM(displayID);
+#endif    
+}
+
 void ScriptedAnimationController::scheduleAnimation()
 {
 #if USE(REQUEST_ANIMATION_FRAME_TIMER)
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+    if (!m_useTimer) {
+        if (DisplayRefreshMonitorManager::sharedManager()->scheduleAnimation(this))
+            return;
+            
+        m_useTimer = true;
+    }
+#endif
+    if (m_animationTimer.isActive())
+        return;
+        
     double scheduleDelay = max<double>(MinimumAnimationInterval - (currentTime() - m_lastAnimationFrameTime), 0);
     m_animationTimer.startOneShot(scheduleDelay);
 #else
index ec24fb3..dfdd503 100644 (file)
 #if ENABLE(REQUEST_ANIMATION_FRAME)
 #include "DOMTimeStamp.h"
 #if USE(REQUEST_ANIMATION_FRAME_TIMER)
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+#include "DisplayRefreshMonitor.h"
+#endif
 #include "Timer.h"
 #endif
+#include "PlatformScreen.h"
 #include <wtf/Noncopyable.h>
 #include <wtf/PassOwnPtr.h>
 #include <wtf/RefPtr.h>
@@ -42,12 +46,16 @@ class Document;
 class Element;
 class RequestAnimationFrameCallback;
 
-class ScriptedAnimationController {
+class ScriptedAnimationController
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+    : public DisplayRefreshMonitorClient
+#endif
+{
 WTF_MAKE_NONCOPYABLE(ScriptedAnimationController);
 public:
-    static PassOwnPtr<ScriptedAnimationController> create(Document* document)
+    static PassOwnPtr<ScriptedAnimationController> create(Document* document, PlatformDisplayID displayID)
     {
-        return adoptPtr(new ScriptedAnimationController(document));
+        return adoptPtr(new ScriptedAnimationController(document, displayID));
     }
 
     typedef int CallbackId;
@@ -59,8 +67,10 @@ public:
     void suspend();
     void resume();
 
+    void windowScreenDidChange(PlatformDisplayID);
+
 private:
-    explicit ScriptedAnimationController(Document*);
+    explicit ScriptedAnimationController(Document*, PlatformDisplayID);
     
     typedef Vector<RefPtr<RequestAnimationFrameCallback> > CallbackList;
     CallbackList m_callbacks;
@@ -75,6 +85,13 @@ private:
     void animationTimerFired(Timer<ScriptedAnimationController>*);
     Timer<ScriptedAnimationController> m_animationTimer;
     double m_lastAnimationFrameTime;
+
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+    // Override for DisplayRefreshMonitorClient
+    virtual void displayRefreshFired(double timestamp) { serviceScriptedAnimations(convertSecondsToDOMTimeStamp(timestamp)); }
+
+    bool m_useTimer;
+#endif
 #endif
 };
 
index 34fa40a..bfbe70a 100644 (file)
@@ -172,6 +172,7 @@ Page::Page(PageClients& pageClients)
 #if ENABLE(PAGE_VISIBILITY_API)
     , m_visibilityState(PageVisibilityStateVisible)
 #endif
+    , m_displayID(0)
 {
     if (!allPages) {
         allPages = new HashSet<Page*>;
@@ -680,6 +681,16 @@ void Page::willMoveOffscreen()
     }
 }
 
+void Page::windowScreenDidChange(PlatformDisplayID displayID)
+{
+    m_displayID = displayID;
+    
+    for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
+        if (frame->document())
+            frame->document()->windowScreenDidChange(displayID);
+    }
+}
+
 void Page::userStyleSheetLocationChanged()
 {
     // FIXME: Eventually we will move to a model of just being handed the sheet
index 1390c98..e70fdbd 100644 (file)
@@ -25,6 +25,7 @@
 #include "FindOptions.h"
 #include "LayoutTypes.h"
 #include "PageVisibilityState.h"
+#include "PlatformScreen.h"
 #include "PlatformString.h"
 #include "ViewportArguments.h"
 #include <wtf/Forward.h>
@@ -256,6 +257,8 @@ namespace WebCore {
         void didMoveOnscreen();
         void willMoveOffscreen();
 
+        void windowScreenDidChange(PlatformDisplayID);
+        
         void userStyleSheetLocationChanged();
         const String& userStyleSheet() const;
 
@@ -310,6 +313,8 @@ namespace WebCore {
         void setVisibilityState(PageVisibilityState, bool);
 #endif
 
+        PlatformDisplayID displayID() const { return m_displayID; }
+        
     private:
         void initGroup();
 
@@ -416,6 +421,7 @@ namespace WebCore {
 #if ENABLE(PAGE_VISIBILITY_API)
         PageVisibilityState m_visibilityState;
 #endif
+        PlatformDisplayID m_displayID;
     };
 
 } // namespace WebCore
index 764fe02..84f7cc6 100644 (file)
@@ -31,6 +31,8 @@
 #include <wtf/RefPtr.h>
 
 #if PLATFORM(MAC)
+#include <QuartzCore/QuartzCore.h>
+
 #ifdef __OBJC__
     @class NSScreen;
     @class NSWindow;
@@ -38,6 +40,9 @@
     class NSScreen;
     class NSWindow;
 #endif
+typedef CGDirectDisplayID PlatformDisplayID;
+#else
+typedef uint64_t PlatformDisplayID;
 #endif
 
 namespace WebCore {
diff --git a/Source/WebCore/platform/graphics/DisplayRefreshMonitor.cpp b/Source/WebCore/platform/graphics/DisplayRefreshMonitor.cpp
new file mode 100644 (file)
index 0000000..1f7b37a
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+
+#include "DisplayRefreshMonitor.h"
+
+#include <wtf/CurrentTime.h>
+
+namespace WebCore {
+
+DisplayRefreshMonitorClient::DisplayRefreshMonitorClient()
+    : m_scheduled(false)
+    , m_displayIDIsSet(false)
+{
+}
+
+DisplayRefreshMonitorClient::~DisplayRefreshMonitorClient()
+{
+    DisplayRefreshMonitorManager::sharedManager()->unregisterClient(this);
+}
+
+void DisplayRefreshMonitorClient::fireDisplayRefreshIfNeeded(double timestamp)
+{
+    if (m_scheduled) {
+        m_scheduled = false;
+        displayRefreshFired(timestamp);
+    }
+}
+
+DisplayRefreshMonitor::DisplayRefreshMonitor(PlatformDisplayID displayID)
+    : m_timestamp(0)
+    , m_active(true)
+    , m_scheduled(false)
+    , m_displayID(displayID)
+#if PLATFORM(MAC)
+    , m_displayLink(0)
+#endif
+{
+}
+
+void DisplayRefreshMonitor::refreshDisplayOnMainThread(void* data)
+{
+    DisplayRefreshMonitor* monitor = static_cast<DisplayRefreshMonitor*>(data);
+
+    double timestamp;
+    {
+        MutexLocker lock(monitor->m_mutex);
+        monitor->m_scheduled = false;
+        timestamp = monitor->m_timestamp;
+    }
+
+    for (size_t i = 0; i < monitor->m_clients.size(); ++i)
+        monitor->m_clients[i]->fireDisplayRefreshIfNeeded(timestamp);
+}
+DisplayRefreshMonitorManager* DisplayRefreshMonitorManager::sharedManager()
+{
+    DEFINE_STATIC_LOCAL(DisplayRefreshMonitorManager, manager, ());
+    return &manager;
+}
+
+size_t DisplayRefreshMonitorManager::findMonitor(PlatformDisplayID displayID) const
+{
+    for (size_t i = 0; i < m_monitors.size(); ++i)
+        if (m_monitors[i]->displayID() == displayID)
+            return i;
+            
+    return notFound;
+}
+
+void DisplayRefreshMonitorManager::registerClient(DisplayRefreshMonitorClient* client)
+{
+    if (!client->m_displayIDIsSet)
+        return;
+        
+    size_t index = findMonitor(client->m_displayID);
+    DisplayRefreshMonitor* monitor;
+    
+    if (index == notFound) {
+        monitor = new DisplayRefreshMonitor(client->m_displayID);
+        m_monitors.append(monitor);
+    } else
+        monitor = m_monitors[index];
+        
+    monitor->addClient(client);
+}
+
+void DisplayRefreshMonitorManager::unregisterClient(DisplayRefreshMonitorClient* client)
+{
+    if (!client->m_displayIDIsSet)
+        return;
+        
+    size_t index = findMonitor(client->m_displayID);
+    if (index == notFound)
+        return;
+    
+    DisplayRefreshMonitor* monitor = m_monitors[index];
+    if (monitor->removeClient(client)) {
+        if (!monitor->hasClients()) {
+            m_monitors.remove(index);
+            delete monitor;
+        }
+    }
+}
+
+bool DisplayRefreshMonitorManager::scheduleAnimation(DisplayRefreshMonitorClient* client)
+{
+    if (!client->m_displayIDIsSet)
+        return false;
+        
+    size_t i = findMonitor(client->m_displayID);
+    ASSERT(i != notFound);
+
+    client->m_scheduled = true;
+    return m_monitors[i]->requestRefreshCallback();
+}
+
+void DisplayRefreshMonitorManager::windowScreenDidChange(PlatformDisplayID displayID, DisplayRefreshMonitorClient* client)
+{
+    if (client->m_displayIDIsSet && client->m_displayID == displayID)
+        return;
+    
+    unregisterClient(client);
+    client->setDisplayID(displayID);
+    registerClient(client);
+    if (client->m_scheduled)
+        scheduleAnimation(client);
+}
+
+}
+
+#endif // USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
diff --git a/Source/WebCore/platform/graphics/DisplayRefreshMonitor.h b/Source/WebCore/platform/graphics/DisplayRefreshMonitor.h
new file mode 100644 (file)
index 0000000..6d87592
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef DisplayRefreshMonitor_h
+#define DisplayRefreshMonitor_h
+
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+
+#include "PlatformScreen.h"
+#include <wtf/Threading.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class DisplayRefreshMonitor;
+class DisplayRefreshMonitorManager;
+
+//
+// Abstract virtual client which receives refresh fired messages on the main thread
+//
+class DisplayRefreshMonitorClient {
+    friend DisplayRefreshMonitor;
+    friend DisplayRefreshMonitorManager;
+    
+public:
+    DisplayRefreshMonitorClient();
+    virtual ~DisplayRefreshMonitorClient();
+    
+    virtual void displayRefreshFired(double timestamp) = 0;
+
+private:
+    void fireDisplayRefreshIfNeeded(double timestamp);
+    
+    void setDisplayID(PlatformDisplayID displayID)
+    {
+        m_displayID = displayID;
+        m_displayIDIsSet = true;
+    }
+    
+    bool m_scheduled;
+    bool m_displayIDIsSet;
+    PlatformDisplayID m_displayID;
+};
+
+//
+// Monitor for display refresh messages for a given screen
+//
+
+class DisplayRefreshMonitor {
+public:
+    DisplayRefreshMonitor(PlatformDisplayID);
+    ~DisplayRefreshMonitor();
+    
+    // Return true if callback request was scheduled, false if it couldn't be
+    // (e.g., hardware refresh is not available)
+    bool requestRefreshCallback();
+    void windowScreenDidChange(PlatformDisplayID);
+    
+    bool hasClients() const { return m_clients.size(); }
+    void addClient(DisplayRefreshMonitorClient* client) { m_clients.append(client); }
+    bool removeClient(DisplayRefreshMonitorClient* client)
+    {
+        size_t i = m_clients.find(client);
+        if (i == notFound)
+            return false;
+        m_clients.remove(i);
+        return true;
+    }
+    
+    PlatformDisplayID displayID() const { return m_displayID; }
+
+private:
+    double m_timestamp;
+    bool m_active;
+    bool m_scheduled;
+    PlatformDisplayID m_displayID;
+    DisplayRefreshMonitorManager* m_manager;
+    Mutex m_mutex;
+    Vector<DisplayRefreshMonitorClient*> m_clients;
+    
+#if PLATFORM(MAC)
+    static void refreshDisplayOnMainThread(void* data);
+    static CVReturn displayLinkCallback(CVDisplayLinkRef, const CVTimeStamp* now, const CVTimeStamp* outputTime, CVOptionFlags, CVOptionFlags*, void* data);
+
+    CVDisplayLinkRef m_displayLink;
+#endif
+};
+
+//
+// Singleton manager for all the DisplayRefreshMonitors. This is the interface to the 
+// outside world. It distributes requests to the appropriate monitor. When the display
+// refresh event fires, the passed DisplayRefreshMonitorClient is called directly on
+// the main thread.
+//
+class DisplayRefreshMonitorManager {
+public:
+    static DisplayRefreshMonitorManager* sharedManager();
+    
+    void registerClient(DisplayRefreshMonitorClient*);
+    void unregisterClient(DisplayRefreshMonitorClient*);
+
+    bool scheduleAnimation(DisplayRefreshMonitorClient*);
+    void windowScreenDidChange(PlatformDisplayID, DisplayRefreshMonitorClient*);
+
+private:
+    DisplayRefreshMonitorManager() { }
+
+    size_t findMonitor(PlatformDisplayID) const;
+    
+    Vector<DisplayRefreshMonitor*> m_monitors;
+};
+
+}
+
+#endif // USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+
+#endif
diff --git a/Source/WebCore/platform/graphics/mac/DisplayRefreshMonitorMac.cpp b/Source/WebCore/platform/graphics/mac/DisplayRefreshMonitorMac.cpp
new file mode 100644 (file)
index 0000000..776a2ef
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+
+#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
+
+#include "DisplayRefreshMonitor.h"
+
+#include <QuartzCore/QuartzCore.h>
+#include <wtf/CurrentTime.h>
+#include <wtf/MainThread.h>
+
+namespace WebCore {
+
+CVReturn DisplayRefreshMonitor::displayLinkCallback(CVDisplayLinkRef, const CVTimeStamp* now, const CVTimeStamp* outputTime, CVOptionFlags, CVOptionFlags*, void* data)
+{
+    DisplayRefreshMonitor* monitor = static_cast<DisplayRefreshMonitor*>(data);
+    
+    MutexLocker lock(monitor->m_mutex);
+    if (!monitor->m_scheduled)
+        return kCVReturnSuccess;
+
+    double nowSeconds = static_cast<double>(now->videoTime) / static_cast<double>(now->videoTimeScale);
+    double outputTimeSeconds = static_cast<double>(outputTime->videoTime) / static_cast<double>(outputTime->videoTimeScale);
+    double webKitNow = currentTime();
+    monitor->m_timestamp = webKitNow - nowSeconds + outputTimeSeconds;
+    
+    callOnMainThread(DisplayRefreshMonitor::refreshDisplayOnMainThread, monitor);
+    return kCVReturnSuccess;
+}
+DisplayRefreshMonitor::~DisplayRefreshMonitor()
+{
+    cancelCallOnMainThread(DisplayRefreshMonitor::refreshDisplayOnMainThread, this);
+    
+    if (m_displayLink) {
+        CVDisplayLinkStop(m_displayLink);
+        CVDisplayLinkRelease(m_displayLink);
+        m_displayLink = 0;
+    }
+}
+
+bool DisplayRefreshMonitor::requestRefreshCallback()
+{
+    if (!m_active)
+        return false;
+        
+    if (!m_displayLink) {
+        m_active = false;
+        CVReturn error = CVDisplayLinkCreateWithCGDisplay(m_displayID, &m_displayLink);
+        if (error)
+            return false;
+
+        error = CVDisplayLinkSetOutputCallback(m_displayLink, DisplayRefreshMonitor::displayLinkCallback, this);
+        if (error)
+            return false;
+
+        error = CVDisplayLinkStart(m_displayLink);
+        if (error)
+            return false;
+
+        m_active = true;
+    }
+    
+    MutexLocker lock(m_mutex);
+    m_scheduled = true;
+    return true;
+}
+
+}
+
+#endif // USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
index bd8d5aa..fa12c41 100644 (file)
@@ -1,3 +1,21 @@
+2011-10-12  Chris Marrin  <cmarrin@apple.com>
+
+        Sync requestAnimationFrame callback to CVDisplayLink on Mac
+        https://bugs.webkit.org/show_bug.cgi?id=68911
+
+        Reviewed by Simon Fraser.
+
+        Add windowDidChangeScreen function which listens for the window changing
+        screens and passes the new displayID along to WebCore::Page. It also sends
+        one on windowWillOrderOnScreen, so the Page has a fresh displayID after it's
+        created.
+
+        * WebView/WebView.mm:
+        (-[WebView addWindowObserversForWindow:]):
+        (-[WebView removeWindowObservers]):
+        (-[WebView _windowDidChangeScreen:]):
+        (-[WebView _windowWillOrderOnScreen:]):
+
 2011-10-12  Adam Barth  <abarth@webkit.org>
 
         Remove ENABLE(XHTMLMP) and associated code
index 997462c..4a5ab66 100644 (file)
@@ -3218,6 +3218,8 @@ static NSString * const windowDidChangeResolutionNotification = @"NSWindowDidCha
             name:WKWindowWillOrderOffScreenNotification() object:window];
         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidChangeResolution:)
             name:windowDidChangeResolutionNotification object:window];
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidChangeScreen:)
+            name:NSWindowDidChangeScreenNotification object:window];
     }
 }
 
@@ -3235,6 +3237,8 @@ static NSString * const windowDidChangeResolutionNotification = @"NSWindowDidCha
             name:WKWindowWillOrderOffScreenNotification() object:window];
         [[NSNotificationCenter defaultCenter] removeObserver:self
             name:windowDidChangeResolutionNotification object:window];
+        [[NSNotificationCenter defaultCenter] removeObserver:self
+            name:NSWindowDidChangeScreenNotification object:window];
     }
 }
 
@@ -3287,6 +3291,12 @@ static NSString * const windowDidChangeResolutionNotification = @"NSWindowDidCha
     [self _updateActiveState];
 }
 
+- (void)doWindowDidChangeScreen
+{
+    if (_private && _private->page)
+        _private->page->windowScreenDidChange((PlatformDisplayID)[[[[[self window] screen] deviceDescription] objectForKey:@"NSScreenNumber"] intValue]);
+}
+
 - (void)_windowDidBecomeKey:(NSNotification *)notification
 {
     NSWindow *keyWindow = [notification object];
@@ -3310,6 +3320,14 @@ static NSString * const windowDidChangeResolutionNotification = @"NSWindowDidCha
 
     if (![self shouldUpdateWhileOffscreen])
         [self setNeedsDisplay:YES];
+
+    // Send a change screen to make sure the initial displayID is set
+    [self doWindowDidChangeScreen];
+}
+
+- (void)_windowDidChangeScreen:(NSNotification *)notification
+{
+    [self doWindowDidChangeScreen];
 }
 
 - (void)_windowWillOrderOffScreen:(NSNotification *)notification
index c98bcea..2289012 100644 (file)
@@ -1,3 +1,29 @@
+2011-10-12  Chris Marrin  <cmarrin@apple.com>
+
+        Sync requestAnimationFrame callback to CVDisplayLink on Mac
+        https://bugs.webkit.org/show_bug.cgi?id=68911
+
+        Reviewed by Simon Fraser.
+
+        Add windowDidChangeScreen function which listens for the window changing
+        screens and passes the new displayID along to WebCore::Page. It also sends
+        one on windowDidBecomeKey, so the Page has a fresh displayID after it's
+        created. Event is generated in the UIProcess and then sent over to the
+        WebProcess, which actually sends it to WebCore::Page.
+
+        * UIProcess/API/mac/WKView.mm:
+        (-[WKView addWindowObserversForWindow:]):
+        (-[WKView removeWindowObservers]):
+        (-[WKView _windowDidChangeScreen:]):
+        (-[WKView _windowDidBecomeKey:]):
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::windowScreenDidChange):
+        * UIProcess/WebPageProxy.h:
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::windowScreenDidChange):
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in:
+
 2011-10-13  Jesus Sanchez-Palencia  <jesus.palencia@openbossa.org>
 
         [Qt][WK2] WebErrorsQt.cpp duplicates code from WKError.h and WebError.h
index 0fbb076..ffff175 100644 (file)
@@ -1797,7 +1797,8 @@ static NSString * const windowDidChangeResolutionNotification = @"NSWindowDidCha
                                                      name:@"_NSWindowDidBecomeVisible" object:window];
         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidChangeResolution:)
                                                      name:windowDidChangeResolutionNotification object:window];
-
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidChangeScreen:)
+                                                     name:NSWindowDidChangeScreenNotification object:window];
     }
 }
 
@@ -1816,7 +1817,7 @@ static NSString * const windowDidChangeResolutionNotification = @"NSWindowDidCha
     [[NSNotificationCenter defaultCenter] removeObserver:self name:@"NSWindowDidOrderOffScreenNotification" object:window];
     [[NSNotificationCenter defaultCenter] removeObserver:self name:@"_NSWindowDidBecomeVisible" object:window];
     [[NSNotificationCenter defaultCenter] removeObserver:self name:windowDidChangeResolutionNotification object:window];
-
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidChangeScreenNotification object:window];
 }
 
 - (void)viewWillMoveToWindow:(NSWindow *)window
@@ -1868,6 +1869,11 @@ static NSString * const windowDidChangeResolutionNotification = @"NSWindowDidCha
     _data->_page->setIntrinsicDeviceScaleFactor([self _intrinsicDeviceScaleFactor]);
 }
 
+- (void)doWindowDidChangeScreen
+{
+    _data->_page->windowScreenDidChange((PlatformDisplayID)[[[[[self window] screen] deviceDescription] objectForKey:@"NSScreenNumber"] intValue]);
+}
+
 - (void)_windowDidBecomeKey:(NSNotification *)notification
 {
     NSWindow *keyWindow = [notification object];
@@ -1875,6 +1881,14 @@ static NSString * const windowDidChangeResolutionNotification = @"NSWindowDidCha
         [self _updateSecureInputState];
         _data->_page->viewStateDidChange(WebPageProxy::ViewWindowIsActive);
     }
+
+    // Send a change screen to make sure the initial displayID is set
+    [self doWindowDidChangeScreen];
+}
+
+- (void)_windowDidChangeScreen:(NSNotification *)notification
+{
+    [self doWindowDidChangeScreen];
 }
 
 - (void)_windowDidResignKey:(NSNotification *)notification
index 20c56d7..e519fa1 100644 (file)
@@ -1158,6 +1158,14 @@ void WebPageProxy::setIntrinsicDeviceScaleFactor(float scaleFactor)
     m_drawingArea->deviceScaleFactorDidChange();
 }
 
+void WebPageProxy::windowScreenDidChange(PlatformDisplayID displayID)
+{
+    if (!isValid())
+        return;
+
+    process()->send(Messages::WebPage::WindowScreenDidChange(displayID), m_pageID);
+}
+
 float WebPageProxy::deviceScaleFactor() const
 {
     if (m_customDeviceScaleFactor)
index adbb29b..3a1b2f6 100644 (file)
@@ -55,6 +55,7 @@
 #include "WebUIClient.h"
 #include <WebCore/DragActions.h>
 #include <WebCore/HitTestResult.h>
+#include <WebCore/PlatformScreen.h>
 #include <WebCore/ScrollTypes.h>
 #include <WebCore/TextChecking.h>
 #include <wtf/HashMap.h>
@@ -392,7 +393,8 @@ public:
     float deviceScaleFactor() const;
     void setIntrinsicDeviceScaleFactor(float);
     void setCustomDeviceScaleFactor(float);
-
+    void windowScreenDidChange(PlatformDisplayID);
+    
     void setUseFixedLayout(bool);
     void setFixedLayoutSize(const WebCore::IntSize&);
     bool useFixedLayout() const { return m_useFixedLayout; };
index 81e3f8c..35e4c8a 100644 (file)
@@ -816,6 +816,11 @@ void WebPage::setPageAndTextZoomFactors(double pageZoomFactor, double textZoomFa
     return frame->setPageAndTextZoomFactors(static_cast<float>(pageZoomFactor), static_cast<float>(textZoomFactor));
 }
 
+void WebPage::windowScreenDidChange(uint64_t displayID)
+{
+    m_page->windowScreenDidChange(static_cast<PlatformDisplayID>(displayID));
+}
+
 void WebPage::scalePage(double scale, const IntPoint& origin)
 {
     m_page->setPageScaleFactor(scale, origin);
index 2ec2a65..8a7f835 100644 (file)
@@ -49,6 +49,7 @@
 #include <WebCore/Editor.h>
 #include <WebCore/FrameLoaderTypes.h>
 #include <WebCore/IntRect.h>
+#include <WebCore/PlatformScreen.h>
 #include <WebCore/ScrollTypes.h>
 #include <WebCore/WebCoreKeyboardUIMode.h>
 #include <wtf/HashMap.h>
@@ -256,6 +257,7 @@ public:
     double pageZoomFactor() const;
     void setPageZoomFactor(double);
     void setPageAndTextZoomFactors(double pageZoomFactor, double textZoomFactor);
+    void windowScreenDidChange(uint64_t);
 
     void scalePage(double scale, const WebCore::IntPoint& origin);
     double pageScaleFactor() const;
index c2241eb..a5853c2 100644 (file)
@@ -113,6 +113,7 @@ messages -> WebPage {
     SetPageAndTextZoomFactors(double pageZoomFactor, double textZoomFactor)
     SetPageZoomFactor(double zoomFactor)
     SetTextZoomFactor(double zoomFactor)
+    WindowScreenDidChange(uint64_t displayID)
 
     ScalePage(double scale, WebCore::IntPoint origin)