2011-02-15 James Robinson <jamesr@chromium.org>
authorjamesr@google.com <jamesr@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 16 Feb 2011 00:53:36 +0000 (00:53 +0000)
committerjamesr@google.com <jamesr@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 16 Feb 2011 00:53:36 +0000 (00:53 +0000)
        Reviewed by Alexey Proskuryakov.

        requestAnimationFrame callbacks should not fire within a modal dialog
        https://bugs.webkit.org/show_bug.cgi?id=53188

        Tests that requestAnimationFrame callbacks are suspended while a modal
        dialog is showing.

        * fast/animation/request-animation-frame-during-modal-expected.txt: Added.
        * fast/animation/request-animation-frame-during-modal.html: Added.
2011-02-15  James Robinson  <jamesr@chromium.org>

        Reviewed by Alexey Proskuryakov.

        requestAnimationFrame callbacks should not fire within a modal dialog
        https://bugs.webkit.org/show_bug.cgi?id=53188

        requestAnimationFrame callbacks shouldn't fire while a modal dialog is up (like a window.alert()).
        This matches Firefox and other async APIs.  This patch moves the callback servicing into its own
        controller class which receives notifications on suspend/resume.

        Test: fast/animation/request-animation-frame-during-modal.html

        * WebCore.gypi:
        * bindings/js/ScriptDebugServer.cpp:
        (WebCore::ScriptDebugServer::setJavaScriptPaused):
        * dom/Document.cpp:
        (WebCore::Document::Document):
        (WebCore::Document::suspendScriptedAnimationControllerCallbacks):
        (WebCore::Document::resumeScriptedAnimationControllerCallbacks):
        (WebCore::Document::webkitRequestAnimationFrame):
        (WebCore::Document::webkitCancelRequestAnimationFrame):
        (WebCore::Document::serviceScriptedAnimations):
        * dom/Document.h:
        * dom/ScriptExecutionContext.h:
        (WebCore::ScriptExecutionContext::suspendScriptedAnimationControllerCallbacks):
        (WebCore::ScriptExecutionContext::resumeScriptedAnimationControllerCallbacks):
        * dom/ScriptedAnimationController.cpp: Added.
        (WebCore::ScriptedAnimationController::ScriptedAnimationController):
        (WebCore::ScriptedAnimationController::suspend):
        (WebCore::ScriptedAnimationController::resume):
        (WebCore::ScriptedAnimationController::registerCallback):
        (WebCore::ScriptedAnimationController::cancelCallback):
        (WebCore::ScriptedAnimationController::serviceScriptedAnimations):
        * dom/ScriptedAnimationController.h: Added.
        (WebCore::ScriptedAnimationController::create):
        * history/CachedFrame.cpp:
        (WebCore::CachedFrameBase::restore):
        (WebCore::CachedFrame::CachedFrame):
        * page/PageGroupLoadDeferrer.cpp:
        (WebCore::PageGroupLoadDeferrer::PageGroupLoadDeferrer):
        (WebCore::PageGroupLoadDeferrer::~PageGroupLoadDeferrer):

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

13 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/animation/request-animation-frame-during-modal-expected.txt [new file with mode: 0644]
LayoutTests/fast/animation/request-animation-frame-during-modal.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/WebCore.gypi
Source/WebCore/bindings/js/ScriptDebugServer.cpp
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h
Source/WebCore/dom/ScriptExecutionContext.h
Source/WebCore/dom/ScriptedAnimationController.cpp [new file with mode: 0644]
Source/WebCore/dom/ScriptedAnimationController.h [new file with mode: 0644]
Source/WebCore/history/CachedFrame.cpp
Source/WebCore/page/PageGroupLoadDeferrer.cpp

index 8b13eca..40f8af0 100644 (file)
@@ -1,3 +1,16 @@
+2011-02-15  James Robinson  <jamesr@chromium.org>
+
+        Reviewed by Alexey Proskuryakov.
+
+        requestAnimationFrame callbacks should not fire within a modal dialog
+        https://bugs.webkit.org/show_bug.cgi?id=53188
+
+        Tests that requestAnimationFrame callbacks are suspended while a modal
+        dialog is showing.
+
+        * fast/animation/request-animation-frame-during-modal-expected.txt: Added.
+        * fast/animation/request-animation-frame-during-modal.html: Added.
+
 2011-02-15  Benjamin Kalman  <kalman@chromium.org>
 
         Reviewed by Darin Adler.
diff --git a/LayoutTests/fast/animation/request-animation-frame-during-modal-expected.txt b/LayoutTests/fast/animation/request-animation-frame-during-modal-expected.txt
new file mode 100644 (file)
index 0000000..6278775
--- /dev/null
@@ -0,0 +1,13 @@
+Tests that requestAnimationFrame callbacks are not invoked while modal dialogs are displayed.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+Setting callback
+Showing modal dialog
+Returned from modal dialog
+Callback fired
+
diff --git a/LayoutTests/fast/animation/request-animation-frame-during-modal.html b/LayoutTests/fast/animation/request-animation-frame-during-modal.html
new file mode 100644 (file)
index 0000000..e903d73
--- /dev/null
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+<link rel="stylesheet" href="../js/resources/js-test-style.css">
+<script src="../js/resources/js-test-pre.js"></script>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+
+<script type="text/javascript">
+description('Tests that requestAnimationFrame callbacks are not invoked while modal dialogs are displayed.');
+
+onload = function()
+{
+    debug('Setting callback');
+    window.webkitRequestAnimationFrame(function() { debug('Callback fired'); }, document.body);
+    debug('Showing modal dialog');
+    var src = 'if (window.layoutTestController) {' +
+              '    layoutTestController.display();' +
+              '    window.close();' +
+              '} else {'+
+              '    window.setTimeout(window.close, 10);'+
+              '}';
+    showModalDialog('data:text/html,<script>' + src + '</' + 'script>');
+    debug('Returned from modal dialog');
+    if (window.layoutTestController) {;
+        layoutTestController.display();
+    }
+}
+
+var successfullyParsed = true;
+</script>
+<script src="../js/resources/js-test-post.js"></script>
+</body>
+</html>
+
index 93a6c03..96a7b14 100644 (file)
@@ -1,3 +1,46 @@
+2011-02-15  James Robinson  <jamesr@chromium.org>
+
+        Reviewed by Alexey Proskuryakov.
+
+        requestAnimationFrame callbacks should not fire within a modal dialog
+        https://bugs.webkit.org/show_bug.cgi?id=53188
+
+        requestAnimationFrame callbacks shouldn't fire while a modal dialog is up (like a window.alert()).
+        This matches Firefox and other async APIs.  This patch moves the callback servicing into its own
+        controller class which receives notifications on suspend/resume.
+
+        Test: fast/animation/request-animation-frame-during-modal.html
+
+        * WebCore.gypi:
+        * bindings/js/ScriptDebugServer.cpp:
+        (WebCore::ScriptDebugServer::setJavaScriptPaused):
+        * dom/Document.cpp:
+        (WebCore::Document::Document):
+        (WebCore::Document::suspendScriptedAnimationControllerCallbacks):
+        (WebCore::Document::resumeScriptedAnimationControllerCallbacks):
+        (WebCore::Document::webkitRequestAnimationFrame):
+        (WebCore::Document::webkitCancelRequestAnimationFrame):
+        (WebCore::Document::serviceScriptedAnimations):
+        * dom/Document.h:
+        * dom/ScriptExecutionContext.h:
+        (WebCore::ScriptExecutionContext::suspendScriptedAnimationControllerCallbacks):
+        (WebCore::ScriptExecutionContext::resumeScriptedAnimationControllerCallbacks):
+        * dom/ScriptedAnimationController.cpp: Added.
+        (WebCore::ScriptedAnimationController::ScriptedAnimationController):
+        (WebCore::ScriptedAnimationController::suspend):
+        (WebCore::ScriptedAnimationController::resume):
+        (WebCore::ScriptedAnimationController::registerCallback):
+        (WebCore::ScriptedAnimationController::cancelCallback):
+        (WebCore::ScriptedAnimationController::serviceScriptedAnimations):
+        * dom/ScriptedAnimationController.h: Added.
+        (WebCore::ScriptedAnimationController::create):
+        * history/CachedFrame.cpp:
+        (WebCore::CachedFrameBase::restore):
+        (WebCore::CachedFrame::CachedFrame):
+        * page/PageGroupLoadDeferrer.cpp:
+        (WebCore::PageGroupLoadDeferrer::PageGroupLoadDeferrer):
+        (WebCore::PageGroupLoadDeferrer::~PageGroupLoadDeferrer):
+
 2011-02-14  Jeremy Orlow  <jorlow@chromium.org>
 
         Reviewed by Darin Fisher.
index 7a868f0..106be5c 100644 (file)
             'dom/RangeBoundaryPoint.h',
             'dom/RangeException.h',
             'dom/RequestAnimationFrameCallback.h',
+            'dom/ScriptedAnimationController.cpp',
+            'dom/ScriptedAnimationController.h',
             'dom/RawDataDocumentParser.h',
             'dom/RegisteredEventListener.cpp',
             'dom/RegisteredEventListener.h',
index 5c52dd7..32a3b2d 100644 (file)
@@ -408,10 +408,13 @@ void ScriptDebugServer::setJavaScriptPaused(Frame* frame, bool paused)
     frame->script()->setPaused(paused);
 
     Document* document = frame->document();
-    if (paused)
+    if (paused) {
+        document->suspendScriptedAnimationControllerCallbacks();
         document->suspendActiveDOMObjects(ActiveDOMObject::JavaScriptDebuggerPaused);
-    else
+    } else {
         document->resumeActiveDOMObjects();
+        document->resumeScriptedAnimationControllerCallbacks();
+    }
 
     setJavaScriptPaused(frame->view(), paused);
 }
index faa77bb..a7bb85a 100644 (file)
 
 #if ENABLE(REQUEST_ANIMATION_FRAME)
 #include "RequestAnimationFrameCallback.h"
+#include "ScriptedAnimationController.h"
 #endif
 
 using namespace std;
@@ -429,9 +430,6 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML)
     , m_writingModeSetOnDocumentElement(false)
     , m_writeRecursionIsTooDeep(false)
     , m_writeRecursionDepth(0)
-#if ENABLE(REQUEST_ANIMATION_FRAME)
-    , m_nextRequestAnimationFrameCallbackId(0)
-#endif
 {
     m_document = this;
 
@@ -4672,6 +4670,22 @@ void Document::postTask(PassOwnPtr<Task> task)
     callOnMainThread(performTask, new PerformTaskContext(m_weakReference, task));
 }
 
+void Document::suspendScriptedAnimationControllerCallbacks()
+{
+#if ENABLE(REQUEST_ANIMATION_FRAME)
+    if (m_scriptedAnimationController)
+        m_scriptedAnimationController->suspend();
+#endif
+}
+
+void Document::resumeScriptedAnimationControllerCallbacks()
+{
+#if ENABLE(REQUEST_ANIMATION_FRAME)
+    if (m_scriptedAnimationController)
+        m_scriptedAnimationController->resume();
+#endif
+}
+
 Element* Document::findAnchor(const String& name)
 {
     if (name.isEmpty())
@@ -4902,82 +4916,26 @@ void Document::loadEventDelayTimerFired(Timer<Document>*)
 }
 
 #if ENABLE(REQUEST_ANIMATION_FRAME)
-int Document::webkitRequestAnimationFrame(PassRefPtr<RequestAnimationFrameCallback> callback, Element* e)
+int Document::webkitRequestAnimationFrame(PassRefPtr<RequestAnimationFrameCallback> callback, Element* animationElement)
 {
-    if (!m_requestAnimationFrameCallbacks)
-        m_requestAnimationFrameCallbacks = new RequestAnimationFrameCallbackList;
-    int id = m_nextRequestAnimationFrameCallbackId++;
-    callback->m_firedOrCancelled = false;
-    callback->m_id = id;
-    callback->m_element = e;
-    m_requestAnimationFrameCallbacks->append(callback);
-    if (FrameView* v = view())
-        v->scheduleAnimation();
-    return id;
+    if (!m_scriptedAnimationController)
+        m_scriptedAnimationController = ScriptedAnimationController::create(this);
+
+    return m_scriptedAnimationController->registerCallback(callback, animationElement);
 }
 
 void Document::webkitCancelRequestAnimationFrame(int id)
 {
-    if (!m_requestAnimationFrameCallbacks)
+    if (!m_scriptedAnimationController)
         return;
-    for (size_t i = 0; i < m_requestAnimationFrameCallbacks->size(); ++i) {
-        if (m_requestAnimationFrameCallbacks->at(i)->m_id == id) {
-            m_requestAnimationFrameCallbacks->at(i)->m_firedOrCancelled = true;
-            m_requestAnimationFrameCallbacks->remove(i);
-            return;
-        }
-    }
+    m_scriptedAnimationController->cancelCallback(id);
 }
 
 void Document::serviceScriptedAnimations(DOMTimeStamp time)
 {
-    if (!m_requestAnimationFrameCallbacks)
+    if (!m_scriptedAnimationController)
         return;
-    // We want to run the callback for all elements in the document that have registered
-    // for a callback and that are visible.  Running the callbacks can cause new callbacks
-    // to be registered, existing callbacks to be cancelled, and elements to gain or lose
-    // visibility so this code has to iterate carefully.
-
-    // FIXME: Currently, this code doesn't do any visibility tests beyond checking display:
-
-    // First, generate a list of callbacks to consider.  Callbacks registered from this point
-    // on are considered only for the "next" frame, not this one.
-    RequestAnimationFrameCallbackList callbacks(*m_requestAnimationFrameCallbacks);
-
-    // Firing the callback may cause the visibility of other elements to change.  To avoid
-    // missing any callbacks, we keep iterating through the list of candiate callbacks and firing
-    // them until nothing new becomes visible.
-    bool firedCallback;
-    do {
-        firedCallback = false;
-        // A previous iteration may have invalidated style (or layout).  Update styles for each iteration
-        // for now since all we check is the existence of a renderer.
-        updateStyleIfNeeded();
-        for (size_t i = 0; i < callbacks.size(); ++i) {
-            RequestAnimationFrameCallback* callback = callbacks[i].get();
-            if (!callback->m_firedOrCancelled && (!callback->m_element || callback->m_element->renderer())) {
-                callback->m_firedOrCancelled = true;
-                callback->handleEvent(time);
-                firedCallback = true;
-                callbacks.remove(i);
-                break;
-            }
-        }
-    } while (firedCallback);
-
-    // Remove any callbacks we fired from the list of pending callbacks.
-    for (size_t i = 0; i < m_requestAnimationFrameCallbacks->size();) {
-        if (m_requestAnimationFrameCallbacks->at(i)->m_firedOrCancelled)
-            m_requestAnimationFrameCallbacks->remove(i);
-        else
-            ++i;
-    }
-
-    // In most cases we expect this list to be empty, so no need to keep around the vector's inline buffer.
-    if (!m_requestAnimationFrameCallbacks->size())
-        m_requestAnimationFrameCallbacks.clear();
-    else if (FrameView* v = view())
-        v->scheduleAnimation();
+    m_scriptedAnimationController->serviceScriptedAnimations(time);
 }
 #endif
 
index 92e8aa2..9e15ac7 100644 (file)
@@ -152,6 +152,7 @@ class TouchList;
 
 #if ENABLE(REQUEST_ANIMATION_FRAME)
 class RequestAnimationFrameCallback;
+class ScriptedAnimationController;
 #endif
 
 typedef int ExceptionCode;
@@ -953,6 +954,9 @@ public:
     virtual void addMessage(MessageSource, MessageType, MessageLevel, const String& message, unsigned lineNumber, const String& sourceURL, PassRefPtr<ScriptCallStack>);
     virtual void postTask(PassOwnPtr<Task>); // Executes the task on context's thread asynchronously.
 
+    virtual void suspendScriptedAnimationControllerCallbacks();
+    virtual void resumeScriptedAnimationControllerCallbacks();
+
 #if USE(JSC)
     typedef JSC::WeakGCMap<WebCore::Node*, JSNode> JSWrapperCache;
     typedef HashMap<DOMWrapperWorld*, JSWrapperCache*> JSWrapperCacheMap;
@@ -1406,9 +1410,7 @@ private:
     unsigned m_writeRecursionDepth;
 
 #if ENABLE(REQUEST_ANIMATION_FRAME)
-    typedef Vector<RefPtr<RequestAnimationFrameCallback> > RequestAnimationFrameCallbackList;
-    OwnPtr<RequestAnimationFrameCallbackList> m_requestAnimationFrameCallbacks;
-    int m_nextRequestAnimationFrameCallbackId;
+    OwnPtr<ScriptedAnimationController> m_scriptedAnimationController;
 #endif
 
     ContentSecurityPolicy m_contentSecurityPolicy;
index 37ad3f3..3b37f0c 100644 (file)
@@ -107,6 +107,9 @@ namespace WebCore {
         typedef const HashMap<ActiveDOMObject*, void*> ActiveDOMObjectsMap;
         ActiveDOMObjectsMap& activeDOMObjects() const { return m_activeDOMObjects; }
 
+        virtual void suspendScriptedAnimationControllerCallbacks() { }
+        virtual void resumeScriptedAnimationControllerCallbacks() { }
+
         // MessagePort is conceptually a kind of ActiveDOMObject, but it needs to be tracked separately for message dispatch.
         void processMessagePortMessagesSoon();
         void dispatchMessagePortEvents();
diff --git a/Source/WebCore/dom/ScriptedAnimationController.cpp b/Source/WebCore/dom/ScriptedAnimationController.cpp
new file mode 100644 (file)
index 0000000..0c70359
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2011 Google 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. AND ITS CONTRIBUTORS ``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 INC. OR ITS 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"
+#include "ScriptedAnimationController.h"
+
+#if ENABLE(REQUEST_ANIMATION_FRAME)
+
+#include "Document.h"
+#include "Element.h"
+#include "FrameView.h"
+#include "RequestAnimationFrameCallback.h"
+
+namespace WebCore {
+
+ScriptedAnimationController::ScriptedAnimationController(Document* document)
+    : m_document(document)
+    , m_nextCallbackId(0)
+    , m_suspendCount(0)
+{
+}
+
+void ScriptedAnimationController::suspend()
+{
+    ++m_suspendCount;
+}
+
+void ScriptedAnimationController::resume()
+{
+    --m_suspendCount;
+    if (!m_suspendCount && m_callbacks.size())
+        if (FrameView* fv = m_document->view())
+            fv->scheduleAnimation();
+}
+
+ScriptedAnimationController::CallbackId ScriptedAnimationController::registerCallback(PassRefPtr<RequestAnimationFrameCallback> callback, Element* animationElement)
+{
+    ScriptedAnimationController::CallbackId id = m_nextCallbackId++;
+    callback->m_firedOrCancelled = false;
+    callback->m_id = id;
+    callback->m_element = animationElement;
+    m_callbacks.append(callback);
+    if (!m_suspendCount)
+        if (FrameView* view = m_document->view())
+            view->scheduleAnimation();
+    return id;
+}
+
+void ScriptedAnimationController::cancelCallback(CallbackId id)
+{
+    for (size_t i = 0; i < m_callbacks.size(); ++i) {
+        if (m_callbacks[i]->m_id == id) {
+            m_callbacks[i]->m_firedOrCancelled = true;
+            m_callbacks.remove(i);
+            return;
+        }
+    }
+}
+
+void ScriptedAnimationController::serviceScriptedAnimations(DOMTimeStamp time)
+{
+    if (!m_callbacks.size() || m_suspendCount)
+        return;
+    // We want to run the callback for all elements in the document that have registered
+    // for a callback and that are visible.  Running the callbacks can cause new callbacks
+    // to be registered, existing callbacks to be cancelled, and elements to gain or lose
+    // visibility so this code has to iterate carefully.
+
+    // FIXME: Currently, this code doesn't do any visibility tests beyond checking display:
+
+    // First, generate a list of callbacks to consider.  Callbacks registered from this point
+    // on are considered only for the "next" frame, not this one.
+    CallbackList callbacks(m_callbacks);
+
+    // Firing the callback may cause the visibility of other elements to change.  To avoid
+    // missing any callbacks, we keep iterating through the list of candiate callbacks and firing
+    // them until nothing new becomes visible.
+    bool firedCallback;
+    do {
+        firedCallback = false;
+        // A previous iteration may have invalidated style (or layout).  Update styles for each iteration
+        // for now since all we check is the existence of a renderer.
+        m_document->updateStyleIfNeeded();
+        for (size_t i = 0; i < callbacks.size(); ++i) {
+            RequestAnimationFrameCallback* callback = callbacks[i].get();
+            if (!callback->m_firedOrCancelled && (!callback->m_element || callback->m_element->renderer())) {
+                callback->m_firedOrCancelled = true;
+                callback->handleEvent(time);
+                firedCallback = true;
+                callbacks.remove(i);
+                break;
+            }
+        }
+    } while (firedCallback);
+
+    // Remove any callbacks we fired from the list of pending callbacks.
+    for (size_t i = 0; i < m_callbacks.size();) {
+        if (m_callbacks[i]->m_firedOrCancelled)
+            m_callbacks.remove(i);
+        else
+            ++i;
+    }
+
+    if (m_callbacks.size())
+        if (FrameView* view = m_document->view())
+            view->scheduleAnimation();
+}
+
+}
+
+#endif
+
diff --git a/Source/WebCore/dom/ScriptedAnimationController.h b/Source/WebCore/dom/ScriptedAnimationController.h
new file mode 100644 (file)
index 0000000..e8d8d03
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2011 Google 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. AND ITS CONTRIBUTORS ``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 INC. OR ITS 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 ScriptedAnimationController_h
+#define ScriptedAnimationController_h
+
+#include "DOMTimeStamp.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class Document;
+class Element;
+class RequestAnimationFrameCallback;
+
+class ScriptedAnimationController {
+WTF_MAKE_NONCOPYABLE(ScriptedAnimationController);
+public:
+    static PassOwnPtr<ScriptedAnimationController> create(Document* document)
+    {
+        return adoptPtr(new ScriptedAnimationController(document));
+    }
+
+    typedef int CallbackId;
+
+    CallbackId registerCallback(PassRefPtr<RequestAnimationFrameCallback>, Element*);
+    void cancelCallback(CallbackId);
+    void serviceScriptedAnimations(DOMTimeStamp);
+
+    void suspend();
+    void resume();
+
+private:
+    explicit ScriptedAnimationController(Document*);
+    typedef Vector<RefPtr<RequestAnimationFrameCallback> > CallbackList;
+    CallbackList m_callbacks;
+
+    Document* m_document;
+    CallbackId m_nextCallbackId;
+    int m_suspendCount;
+};
+
+}
+
+#endif // ScriptedAnimationController_h
+
index 0059691..92557b7 100644 (file)
@@ -94,6 +94,7 @@ void CachedFrameBase::restore()
     frame->animation()->resumeAnimationsForDocument(m_document.get());
     frame->eventHandler()->setMousePressNode(m_mousePressNode.get());
     m_document->resumeActiveDOMObjects();
+    m_document->resumeScriptedAnimationControllerCallbacks();
 
     // It is necessary to update any platform script objects after restoring the
     // cached page.
@@ -152,6 +153,7 @@ CachedFrame::CachedFrame(Frame* frame)
     // Suspending must also happen after we've recursed over child frames, in case
     // those create more objects.
     // FIXME: It's still possible to have objects created after suspending in some cases, see http://webkit.org/b/53733 for more details.
+    m_document->suspendScriptedAnimationControllerCallbacks();
     m_document->suspendActiveDOMObjects(ActiveDOMObject::DocumentWillBecomeInactive);
     m_cachedFrameScriptData = adoptPtr(new ScriptCachedFrameData(frame));
 
index 781bc34..dea2cd7 100644 (file)
@@ -48,6 +48,7 @@ PageGroupLoadDeferrer::PageGroupLoadDeferrer(Page* page, bool deferSelf)
                 // NOTE: if PageGroupLoadDeferrer is ever used for tasks other than showing a modal window or sheet,
                 // the constructor will need to take a ActiveDOMObject::ReasonForSuspension.
                 for (Frame* frame = otherPage->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
+                    frame->document()->suspendScriptedAnimationControllerCallbacks();
                     frame->document()->suspendActiveDOMObjects(ActiveDOMObject::WillShowDialog);
                     frame->document()->asyncScriptRunner()->suspend();
                     if (DocumentParser* parser = frame->document()->parser())
@@ -71,6 +72,7 @@ PageGroupLoadDeferrer::~PageGroupLoadDeferrer()
 
             for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
                 frame->document()->resumeActiveDOMObjects();
+                frame->document()->resumeScriptedAnimationControllerCallbacks();
                 frame->document()->asyncScriptRunner()->resume();
                 if (DocumentParser* parser = frame->document()->parser())
                     parser->resumeScheduledTasks();