1/*
2 * Copyright (C) 2015, 2016 Apple 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. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include "GCReachableRef.h"
29#include <wtf/Forward.h>
30#include <wtf/Noncopyable.h>
31#include <wtf/Vector.h>
32
33namespace JSC {
34
35class ExecState;
36
37}
38
39namespace WebCore {
40
41class CustomElementReactionQueueItem;
42class Document;
43class Element;
44class JSCustomElementInterface;
45class QualifiedName;
46
47class CustomElementReactionQueue {
48 WTF_MAKE_FAST_ALLOCATED;
49 WTF_MAKE_NONCOPYABLE(CustomElementReactionQueue);
50public:
51 CustomElementReactionQueue(JSCustomElementInterface&);
52 ~CustomElementReactionQueue();
53
54 static void enqueueElementUpgrade(Element&, bool alreadyScheduledToUpgrade);
55 static void enqueueElementUpgradeIfDefined(Element&);
56 static void enqueueConnectedCallbackIfNeeded(Element&);
57 static void enqueueDisconnectedCallbackIfNeeded(Element&);
58 static void enqueueAdoptedCallbackIfNeeded(Element&, Document& oldDocument, Document& newDocument);
59 static void enqueueAttributeChangedCallbackIfNeeded(Element&, const QualifiedName&, const AtomString& oldValue, const AtomString& newValue);
60 static void enqueuePostUpgradeReactions(Element&);
61
62 bool observesStyleAttribute() const;
63 void invokeAll(Element&);
64 void clear();
65
66 static void processBackupQueue();
67
68 class ElementQueue {
69 public:
70 void add(Element&);
71 void processQueue(JSC::ExecState*);
72
73 private:
74 void invokeAll();
75
76 Vector<GCReachableRef<Element>> m_elements;
77 bool m_invoking { false };
78 };
79
80private:
81 static void enqueueElementOnAppropriateElementQueue(Element&);
82 static ElementQueue& ensureBackupQueue();
83 static ElementQueue& backupElementQueue();
84
85 Ref<JSCustomElementInterface> m_interface;
86 Vector<CustomElementReactionQueueItem> m_items;
87};
88
89class CustomElementReactionDisallowedScope {
90public:
91 CustomElementReactionDisallowedScope()
92 {
93#if !ASSERT_DISABLED
94 s_customElementReactionDisallowedCount++;
95#endif
96 }
97
98 ~CustomElementReactionDisallowedScope()
99 {
100#if !ASSERT_DISABLED
101 ASSERT(s_customElementReactionDisallowedCount);
102 s_customElementReactionDisallowedCount--;
103#endif
104 }
105
106#if !ASSERT_DISABLED
107 static bool isReactionAllowed() { return !s_customElementReactionDisallowedCount; }
108#endif
109
110 class AllowedScope {
111#if !ASSERT_DISABLED
112 public:
113 AllowedScope()
114 : m_originalCount(s_customElementReactionDisallowedCount)
115 {
116 s_customElementReactionDisallowedCount = 0;
117 }
118
119 ~AllowedScope()
120 {
121 s_customElementReactionDisallowedCount = m_originalCount;
122 }
123
124 private:
125 unsigned m_originalCount;
126#endif
127 };
128
129private:
130#if !ASSERT_DISABLED
131 WEBCORE_EXPORT static unsigned s_customElementReactionDisallowedCount;
132
133 friend class AllowedScope;
134#endif
135};
136
137class CustomElementReactionStack : public CustomElementReactionDisallowedScope::AllowedScope {
138public:
139 ALWAYS_INLINE CustomElementReactionStack(JSC::ExecState* state)
140 : m_previousProcessingStack(s_currentProcessingStack)
141 , m_state(state)
142 {
143 s_currentProcessingStack = this;
144 }
145
146 ALWAYS_INLINE CustomElementReactionStack(JSC::ExecState& state)
147 : CustomElementReactionStack(&state)
148 { }
149
150 ALWAYS_INLINE ~CustomElementReactionStack()
151 {
152 if (UNLIKELY(m_queue))
153 processQueue(m_state);
154 s_currentProcessingStack = m_previousProcessingStack;
155 }
156
157private:
158 WEBCORE_EXPORT void processQueue(JSC::ExecState*);
159
160 CustomElementReactionQueue::ElementQueue* m_queue { nullptr }; // Use raw pointer to avoid generating delete in the destructor.
161 CustomElementReactionStack* m_previousProcessingStack;
162 JSC::ExecState* m_state;
163
164 WEBCORE_EXPORT static CustomElementReactionStack* s_currentProcessingStack;
165
166 friend CustomElementReactionQueue;
167};
168
169}
170