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
scheduleAttributeChangedCallback(PassRefPtr<CustomElementLifecycleCallbacks> callbacks,PassRefPtr<Element> element,const AtomicString & name,const AtomicString & oldValue,const AtomicString & newValue)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
scheduleCreatedCallback(PassRefPtr<CustomElementLifecycleCallbacks> callbacks,PassRefPtr<Element> element)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
scheduleAttachedCallback(PassRefPtr<CustomElementLifecycleCallbacks> callbacks,PassRefPtr<Element> element)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
scheduleDetachedCallback(PassRefPtr<CustomElementLifecycleCallbacks> callbacks,PassRefPtr<Element> element)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
instance()76 CustomElementCallbackScheduler& CustomElementCallbackScheduler::instance()
77 {
78 DEFINE_STATIC_LOCAL(CustomElementCallbackScheduler, instance, ());
79 return instance;
80 }
81
ensureCallbackQueue(PassRefPtr<Element> element)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
clearElementCallbackQueueMap()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.
schedule(PassRefPtr<Element> element)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.
scheduleInCurrentElementQueue(PassRefPtr<Element> element)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