1 /* 2 * Copyright (C) 2013 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 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * 3. Neither the name of Google Inc. nor the names of its contributors 15 * may be used to endorse or promote products derived from this 16 * software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "core/dom/custom/CustomElementCallbackScheduler.h" 33 34 #include "core/dom/Element.h" 35 #include "core/dom/custom/CustomElementCallbackDispatcher.h" 36 #include "core/dom/custom/CustomElementLifecycleCallbacks.h" 37 38 namespace WebCore { 39 40 void CustomElementCallbackScheduler::scheduleAttributeChangedCallback(PassRefPtr<CustomElementLifecycleCallbacks> callbacks, PassRefPtr<Element> element, const AtomicString& name, const AtomicString& oldValue, const AtomicString& newValue) 41 { 42 if (!callbacks->hasAttributeChangedCallback()) 43 return; 44 45 CustomElementCallbackQueue* queue = instance().schedule(element); 46 queue->append(CustomElementCallbackInvocation::createAttributeChangedInvocation(callbacks, name, oldValue, newValue)); 47 } 48 49 void CustomElementCallbackScheduler::scheduleCreatedCallback(PassRefPtr<CustomElementLifecycleCallbacks> callbacks, PassRefPtr<Element> element) 50 { 51 if (!callbacks->hasCreatedCallback()) 52 return; 53 54 CustomElementCallbackQueue* queue = instance().scheduleInCurrentElementQueue(element); 55 queue->append(CustomElementCallbackInvocation::createInvocation(callbacks, CustomElementLifecycleCallbacks::Created)); 56 } 57 58 void CustomElementCallbackScheduler::scheduleAttachedCallback(PassRefPtr<CustomElementLifecycleCallbacks> callbacks, PassRefPtr<Element> element) 59 { 60 if (!callbacks->hasAttachedCallback()) 61 return; 62 63 CustomElementCallbackQueue* queue = instance().schedule(element); 64 queue->append(CustomElementCallbackInvocation::createInvocation(callbacks, CustomElementLifecycleCallbacks::Attached)); 65 } 66 67 void CustomElementCallbackScheduler::scheduleDetachedCallback(PassRefPtr<CustomElementLifecycleCallbacks> callbacks, PassRefPtr<Element> element) 68 { 69 if (!callbacks->hasDetachedCallback()) 70 return; 71 72 CustomElementCallbackQueue* queue = instance().schedule(element); 73 queue->append(CustomElementCallbackInvocation::createInvocation(callbacks, CustomElementLifecycleCallbacks::Detached)); 74 } 75 76 CustomElementCallbackScheduler& CustomElementCallbackScheduler::instance() 77 { 78 DEFINE_STATIC_LOCAL(CustomElementCallbackScheduler, instance, ()); 79 return instance; 80 } 81 82 CustomElementCallbackQueue* CustomElementCallbackScheduler::ensureCallbackQueue(PassRefPtr<Element> element) 83 { 84 Element* key = element.get(); 85 ElementCallbackQueueMap::iterator it = m_elementCallbackQueueMap.find(key); 86 if (it == m_elementCallbackQueueMap.end()) 87 it = m_elementCallbackQueueMap.add(key, CustomElementCallbackQueue::create(element)).iterator; 88 return it->value.get(); 89 } 90 91 void CustomElementCallbackScheduler::clearElementCallbackQueueMap() 92 { 93 ElementCallbackQueueMap emptyMap; 94 instance().m_elementCallbackQueueMap.swap(emptyMap); 95 } 96 97 // Finds or creates the callback queue for element. If the 98 // createdCallback has not finished running, the callback queue is not 99 // moved to the top-of-stack. Otherwise like 100 // scheduleInCurrentElementQueue. 101 CustomElementCallbackQueue* CustomElementCallbackScheduler::schedule(PassRefPtr<Element> element) 102 { 103 CustomElementCallbackQueue* callbackQueue = ensureCallbackQueue(element); 104 if (!callbackQueue->inCreatedCallback()) 105 CustomElementCallbackDispatcher::instance().enqueue(callbackQueue); 106 return callbackQueue; 107 } 108 109 // Finds or creates the callback queue for element. If the element's 110 // callback queue is scheduled in an earlier processing stack frame, 111 // its owner is set to the element queue on the top of the processing 112 // stack. Because callback queues are processed exhaustively, this 113 // effectively moves the callback queue to the top of the stack. 114 CustomElementCallbackQueue* CustomElementCallbackScheduler::scheduleInCurrentElementQueue(PassRefPtr<Element> element) 115 { 116 CustomElementCallbackQueue* callbackQueue = ensureCallbackQueue(element); 117 CustomElementCallbackDispatcher::instance().enqueue(callbackQueue); 118 return callbackQueue; 119 } 120 121 } // namespace WebCore 122