1 /* 2 * Copyright (C) 2011 Google Inc. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY 17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 * 24 */ 25 26 #include "config.h" 27 #include "ScriptedAnimationController.h" 28 29 #if ENABLE(REQUEST_ANIMATION_FRAME) 30 31 #include "Document.h" 32 #include "Element.h" 33 #include "FrameView.h" 34 #include "RequestAnimationFrameCallback.h" 35 36 namespace WebCore { 37 38 ScriptedAnimationController::ScriptedAnimationController(Document* document) 39 : m_document(document) 40 , m_nextCallbackId(0) 41 , m_suspendCount(0) 42 { 43 } 44 45 void ScriptedAnimationController::suspend() 46 { 47 ++m_suspendCount; 48 } 49 50 void ScriptedAnimationController::resume() 51 { 52 --m_suspendCount; 53 if (!m_suspendCount && m_callbacks.size()) 54 if (FrameView* fv = m_document->view()) 55 fv->scheduleAnimation(); 56 } 57 58 ScriptedAnimationController::CallbackId ScriptedAnimationController::registerCallback(PassRefPtr<RequestAnimationFrameCallback> callback, Element* animationElement) 59 { 60 ScriptedAnimationController::CallbackId id = m_nextCallbackId++; 61 callback->m_firedOrCancelled = false; 62 callback->m_id = id; 63 callback->m_element = animationElement; 64 m_callbacks.append(callback); 65 if (!m_suspendCount) 66 if (FrameView* view = m_document->view()) 67 view->scheduleAnimation(); 68 return id; 69 } 70 71 void ScriptedAnimationController::cancelCallback(CallbackId id) 72 { 73 for (size_t i = 0; i < m_callbacks.size(); ++i) { 74 if (m_callbacks[i]->m_id == id) { 75 m_callbacks[i]->m_firedOrCancelled = true; 76 m_callbacks.remove(i); 77 return; 78 } 79 } 80 } 81 82 void ScriptedAnimationController::serviceScriptedAnimations(DOMTimeStamp time) 83 { 84 if (!m_callbacks.size() || m_suspendCount) 85 return; 86 // We want to run the callback for all elements in the document that have registered 87 // for a callback and that are visible. Running the callbacks can cause new callbacks 88 // to be registered, existing callbacks to be cancelled, and elements to gain or lose 89 // visibility so this code has to iterate carefully. 90 91 // FIXME: Currently, this code doesn't do any visibility tests beyond checking display: 92 93 // First, generate a list of callbacks to consider. Callbacks registered from this point 94 // on are considered only for the "next" frame, not this one. 95 CallbackList callbacks(m_callbacks); 96 97 // Firing the callback may cause the visibility of other elements to change. To avoid 98 // missing any callbacks, we keep iterating through the list of candiate callbacks and firing 99 // them until nothing new becomes visible. 100 bool firedCallback; 101 do { 102 firedCallback = false; 103 // A previous iteration may have invalidated style (or layout). Update styles for each iteration 104 // for now since all we check is the existence of a renderer. 105 m_document->updateStyleIfNeeded(); 106 for (size_t i = 0; i < callbacks.size(); ++i) { 107 RequestAnimationFrameCallback* callback = callbacks[i].get(); 108 if (!callback->m_firedOrCancelled && (!callback->m_element || callback->m_element->renderer())) { 109 callback->m_firedOrCancelled = true; 110 callback->handleEvent(time); 111 firedCallback = true; 112 callbacks.remove(i); 113 break; 114 } 115 } 116 } while (firedCallback); 117 118 // Remove any callbacks we fired from the list of pending callbacks. 119 for (size_t i = 0; i < m_callbacks.size();) { 120 if (m_callbacks[i]->m_firedOrCancelled) 121 m_callbacks.remove(i); 122 else 123 ++i; 124 } 125 126 if (m_callbacks.size()) 127 if (FrameView* view = m_document->view()) 128 view->scheduleAnimation(); 129 } 130 131 } 132 133 #endif 134 135