Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(26)

Side by Side Diff: third_party/WebKit/Source/core/dom/custom/CustomElementsRegistry.cpp

Issue 2277713002: Rename CustomElementsRegistry to CustomElementRegistry (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "core/dom/custom/CustomElementsRegistry.h"
6
7 #include "bindings/core/v8/ExceptionState.h"
8 #include "bindings/core/v8/ScriptCustomElementDefinitionBuilder.h"
9 #include "bindings/core/v8/ScriptPromise.h"
10 #include "bindings/core/v8/ScriptPromiseResolver.h"
11 #include "core/dom/Document.h"
12 #include "core/dom/Element.h"
13 #include "core/dom/ElementRegistrationOptions.h"
14 #include "core/dom/ExceptionCode.h"
15 #include "core/dom/custom/CEReactionsScope.h"
16 #include "core/dom/custom/CustomElement.h"
17 #include "core/dom/custom/CustomElementDefinition.h"
18 #include "core/dom/custom/CustomElementDefinitionBuilder.h"
19 #include "core/dom/custom/CustomElementDescriptor.h"
20 #include "core/dom/custom/CustomElementUpgradeReaction.h"
21 #include "core/dom/custom/CustomElementUpgradeSorter.h"
22 #include "core/dom/custom/V0CustomElementRegistrationContext.h"
23 #include "core/frame/LocalDOMWindow.h"
24 #include "wtf/Allocator.h"
25
26 namespace blink {
27
28 // Returns true if |name| is invalid.
29 static bool throwIfInvalidName(
30 const AtomicString& name,
31 ExceptionState& exceptionState)
32 {
33 if (CustomElement::isValidName(name))
34 return false;
35 exceptionState.throwDOMException(
36 SyntaxError,
37 "\"" + name + "\" is not a valid custom element name");
38 return true;
39 }
40
41
42 class CustomElementsRegistry::NameIsBeingDefined final {
43 STACK_ALLOCATED();
44 DISALLOW_IMPLICIT_CONSTRUCTORS(NameIsBeingDefined);
45 public:
46 NameIsBeingDefined(
47 CustomElementsRegistry* registry,
48 const AtomicString& name)
49 : m_registry(registry)
50 , m_name(name)
51 {
52 DCHECK(!m_registry->m_namesBeingDefined.contains(name));
53 m_registry->m_namesBeingDefined.add(name);
54 }
55
56 ~NameIsBeingDefined()
57 {
58 m_registry->m_namesBeingDefined.remove(m_name);
59 }
60
61 private:
62 Member<CustomElementsRegistry> m_registry;
63 const AtomicString& m_name;
64 };
65
66 CustomElementsRegistry* CustomElementsRegistry::create(
67 const LocalDOMWindow* owner)
68 {
69 CustomElementsRegistry* registry = new CustomElementsRegistry(owner);
70 Document* document = owner->document();
71 if (V0CustomElementRegistrationContext* v0 =
72 document ? document->registrationContext() : nullptr)
73 registry->entangle(v0);
74 return registry;
75 }
76
77 CustomElementsRegistry::CustomElementsRegistry(const LocalDOMWindow* owner)
78 : m_owner(owner)
79 , m_v0 (new V0RegistrySet())
80 , m_upgradeCandidates(new UpgradeCandidateMap())
81 {
82 }
83
84 DEFINE_TRACE(CustomElementsRegistry)
85 {
86 visitor->trace(m_definitions);
87 visitor->trace(m_owner);
88 visitor->trace(m_v0);
89 visitor->trace(m_upgradeCandidates);
90 visitor->trace(m_whenDefinedPromiseMap);
91 }
92
93 void CustomElementsRegistry::define(
94 ScriptState* scriptState,
95 const AtomicString& name,
96 const ScriptValue& constructor,
97 const ElementRegistrationOptions& options,
98 ExceptionState& exceptionState)
99 {
100 ScriptCustomElementDefinitionBuilder builder(
101 scriptState,
102 this,
103 constructor,
104 exceptionState);
105 define(name, builder, options, exceptionState);
106 }
107
108 // http://w3c.github.io/webcomponents/spec/custom/#dfn-element-definition
109 void CustomElementsRegistry::define(
110 const AtomicString& name,
111 CustomElementDefinitionBuilder& builder,
112 const ElementRegistrationOptions& options,
113 ExceptionState& exceptionState)
114 {
115 if (!builder.checkConstructorIntrinsics())
116 return;
117
118 if (throwIfInvalidName(name, exceptionState))
119 return;
120
121 if (m_namesBeingDefined.contains(name)) {
122 exceptionState.throwDOMException(
123 NotSupportedError,
124 "this name is already being defined in this registry");
125 return;
126 }
127 NameIsBeingDefined defining(this, name);
128
129 if (nameIsDefined(name) || v0NameIsDefined(name)) {
130 exceptionState.throwDOMException(
131 NotSupportedError,
132 "this name has already been used with this registry");
133 return;
134 }
135
136 if (!builder.checkConstructorNotRegistered())
137 return;
138
139 // TODO(dominicc): Implement steps:
140 // 5: localName
141 // 6-7: extends processing
142
143 // 8-9: observed attributes caching is done below, together with callbacks.
144 // TODO(kojii): https://github.com/whatwg/html/issues/1373 for the ordering.
145 // When it's resolved, revisit if this code needs changes.
146
147 // TODO(dominicc): Add a test where the prototype getter destroys
148 // the context.
149
150 if (!builder.checkPrototype())
151 return;
152
153 // 8-9: observed attributes caching
154 // 12-13: connected callback
155 // 14-15: disconnected callback
156 // 16-17: attribute changed callback
157
158 if (!builder.rememberOriginalProperties())
159 return;
160
161 // TODO(dominicc): Add a test where retrieving the prototype
162 // recursively calls define with the same name.
163
164 CustomElementDescriptor descriptor(name, name);
165 CustomElementDefinition* definition = builder.build(descriptor);
166 CHECK(!exceptionState.hadException());
167 CHECK(definition->descriptor() == descriptor);
168 DefinitionMap::AddResult result =
169 m_definitions.add(descriptor.name(), definition);
170 CHECK(result.isNewEntry);
171
172 HeapVector<Member<Element>> candidates;
173 collectCandidates(descriptor, &candidates);
174 for (Element* candidate : candidates)
175 definition->enqueueUpgradeReaction(candidate);
176
177 // 19: when-defined promise processing
178 const auto& entry = m_whenDefinedPromiseMap.find(name);
179 if (entry == m_whenDefinedPromiseMap.end())
180 return;
181 entry->value->resolve();
182 m_whenDefinedPromiseMap.remove(entry);
183 }
184
185 // https://html.spec.whatwg.org/multipage/scripting.html#dom-customelementsregis try-get
186 ScriptValue CustomElementsRegistry::get(const AtomicString& name)
187 {
188 CustomElementDefinition* definition = definitionForName(name);
189 if (!definition) {
190 // Binding layer converts |ScriptValue()| to script specific value,
191 // e.g. |undefined| for v8.
192 return ScriptValue();
193 }
194 return definition->getConstructorForScript();
195 }
196
197 CustomElementDefinition* CustomElementsRegistry::definitionFor(const CustomEleme ntDescriptor& desc) const
198 {
199 CustomElementDefinition* definition = definitionForName(desc.name());
200 if (!definition)
201 return nullptr;
202 // The definition for a customized built-in element, such as
203 // <button is="my-button"> should not be provided for an
204 // autonomous element, such as <my-button>, even though the
205 // name "my-button" matches.
206 return definition->descriptor() == desc ? definition : nullptr;
207 }
208
209 bool CustomElementsRegistry::nameIsDefined(const AtomicString& name) const
210 {
211 return m_definitions.contains(name);
212 }
213
214 void CustomElementsRegistry::entangle(V0CustomElementRegistrationContext* v0)
215 {
216 m_v0->add(v0);
217 v0->setV1(this);
218 }
219
220 bool CustomElementsRegistry::v0NameIsDefined(const AtomicString& name)
221 {
222 for (const auto& v0 : *m_v0) {
223 if (v0->nameIsDefined(name))
224 return true;
225 }
226 return false;
227 }
228
229 CustomElementDefinition* CustomElementsRegistry::definitionForName(
230 const AtomicString& name) const
231 {
232 return m_definitions.get(name);
233 }
234
235 void CustomElementsRegistry::addCandidate(Element* candidate)
236 {
237 const AtomicString& name = candidate->localName();
238 if (nameIsDefined(name) || v0NameIsDefined(name))
239 return;
240 UpgradeCandidateMap::iterator it = m_upgradeCandidates->find(name);
241 UpgradeCandidateSet* set;
242 if (it != m_upgradeCandidates->end()) {
243 set = it->value;
244 } else {
245 set = m_upgradeCandidates->add(name, new UpgradeCandidateSet())
246 .storedValue
247 ->value;
248 }
249 set->add(candidate);
250 }
251
252 // https://html.spec.whatwg.org/multipage/scripting.html#dom-customelementsregis try-whendefined
253 ScriptPromise CustomElementsRegistry::whenDefined(
254 ScriptState* scriptState,
255 const AtomicString& name,
256 ExceptionState& exceptionState)
257 {
258 if (throwIfInvalidName(name, exceptionState))
259 return ScriptPromise();
260 CustomElementDefinition* definition = definitionForName(name);
261 if (definition)
262 return ScriptPromise::castUndefined(scriptState);
263 ScriptPromiseResolver* resolver = m_whenDefinedPromiseMap.get(name);
264 if (resolver)
265 return resolver->promise();
266 ScriptPromiseResolver* newResolver =
267 ScriptPromiseResolver::create(scriptState);
268 m_whenDefinedPromiseMap.add(name, newResolver);
269 return newResolver->promise();
270 }
271
272 void CustomElementsRegistry::collectCandidates(
273 const CustomElementDescriptor& desc,
274 HeapVector<Member<Element>>* elements)
275 {
276 UpgradeCandidateMap::iterator it = m_upgradeCandidates->find(desc.name());
277 if (it == m_upgradeCandidates->end())
278 return;
279 CustomElementUpgradeSorter sorter;
280 for (Element* element : *it.get()->value) {
281 if (!element || !desc.matches(*element))
282 continue;
283 sorter.add(element);
284 }
285
286 m_upgradeCandidates->remove(it);
287
288 Document* document = m_owner->document();
289 if (!document)
290 return;
291
292 sorter.sorted(elements, document);
293 }
294
295 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698