OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/dom/custom/CustomElementsRegistry.h" | 5 #include "core/dom/custom/CustomElementsRegistry.h" |
6 | 6 |
7 #include "bindings/core/v8/ExceptionState.h" | 7 #include "bindings/core/v8/ExceptionState.h" |
8 #include "bindings/core/v8/ScriptCustomElementDefinitionBuilder.h" | 8 #include "bindings/core/v8/ScriptCustomElementDefinitionBuilder.h" |
| 9 #include "bindings/core/v8/ScriptPromise.h" |
| 10 #include "bindings/core/v8/ScriptPromiseResolver.h" |
9 #include "core/dom/Document.h" | 11 #include "core/dom/Document.h" |
10 #include "core/dom/Element.h" | 12 #include "core/dom/Element.h" |
11 #include "core/dom/ElementRegistrationOptions.h" | 13 #include "core/dom/ElementRegistrationOptions.h" |
12 #include "core/dom/ExceptionCode.h" | 14 #include "core/dom/ExceptionCode.h" |
13 #include "core/dom/custom/CEReactionsScope.h" | 15 #include "core/dom/custom/CEReactionsScope.h" |
14 #include "core/dom/custom/CustomElement.h" | 16 #include "core/dom/custom/CustomElement.h" |
15 #include "core/dom/custom/CustomElementDefinition.h" | 17 #include "core/dom/custom/CustomElementDefinition.h" |
16 #include "core/dom/custom/CustomElementDefinitionBuilder.h" | 18 #include "core/dom/custom/CustomElementDefinitionBuilder.h" |
17 #include "core/dom/custom/CustomElementDescriptor.h" | 19 #include "core/dom/custom/CustomElementDescriptor.h" |
18 #include "core/dom/custom/CustomElementUpgradeReaction.h" | 20 #include "core/dom/custom/CustomElementUpgradeReaction.h" |
19 #include "core/dom/custom/CustomElementUpgradeSorter.h" | 21 #include "core/dom/custom/CustomElementUpgradeSorter.h" |
20 #include "core/dom/custom/V0CustomElementRegistrationContext.h" | 22 #include "core/dom/custom/V0CustomElementRegistrationContext.h" |
21 #include "wtf/Allocator.h" | 23 #include "wtf/Allocator.h" |
22 | 24 |
23 namespace blink { | 25 namespace blink { |
24 | 26 |
| 27 // Returns true if |name| is invalid. |
| 28 static bool throwIfInvalidName( |
| 29 const AtomicString& name, |
| 30 ExceptionState& exceptionState) |
| 31 { |
| 32 if (CustomElement::isValidName(name)) |
| 33 return false; |
| 34 exceptionState.throwDOMException( |
| 35 SyntaxError, |
| 36 "\"" + name + "\" is not a valid custom element name"); |
| 37 return true; |
| 38 } |
| 39 |
| 40 |
25 class CustomElementsRegistry::NameIsBeingDefined final { | 41 class CustomElementsRegistry::NameIsBeingDefined final { |
26 STACK_ALLOCATED(); | 42 STACK_ALLOCATED(); |
27 DISALLOW_IMPLICIT_CONSTRUCTORS(NameIsBeingDefined); | 43 DISALLOW_IMPLICIT_CONSTRUCTORS(NameIsBeingDefined); |
28 public: | 44 public: |
29 NameIsBeingDefined( | 45 NameIsBeingDefined( |
30 CustomElementsRegistry* registry, | 46 CustomElementsRegistry* registry, |
31 const AtomicString& name) | 47 const AtomicString& name) |
32 : m_registry(registry) | 48 : m_registry(registry) |
33 , m_name(name) | 49 , m_name(name) |
34 { | 50 { |
(...skipping 24 matching lines...) Expand all Loading... |
59 : m_document(document) | 75 : m_document(document) |
60 , m_upgradeCandidates(new UpgradeCandidateMap()) | 76 , m_upgradeCandidates(new UpgradeCandidateMap()) |
61 { | 77 { |
62 } | 78 } |
63 | 79 |
64 DEFINE_TRACE(CustomElementsRegistry) | 80 DEFINE_TRACE(CustomElementsRegistry) |
65 { | 81 { |
66 visitor->trace(m_definitions); | 82 visitor->trace(m_definitions); |
67 visitor->trace(m_document); | 83 visitor->trace(m_document); |
68 visitor->trace(m_upgradeCandidates); | 84 visitor->trace(m_upgradeCandidates); |
| 85 visitor->trace(m_whenDefinedPromiseMap); |
69 } | 86 } |
70 | 87 |
71 void CustomElementsRegistry::define( | 88 void CustomElementsRegistry::define( |
72 ScriptState* scriptState, | 89 ScriptState* scriptState, |
73 const AtomicString& name, | 90 const AtomicString& name, |
74 const ScriptValue& constructor, | 91 const ScriptValue& constructor, |
75 const ElementRegistrationOptions& options, | 92 const ElementRegistrationOptions& options, |
76 ExceptionState& exceptionState) | 93 ExceptionState& exceptionState) |
77 { | 94 { |
78 ScriptCustomElementDefinitionBuilder builder( | 95 ScriptCustomElementDefinitionBuilder builder( |
79 scriptState, | 96 scriptState, |
80 this, | 97 this, |
81 constructor, | 98 constructor, |
82 exceptionState); | 99 exceptionState); |
83 define(name, builder, options, exceptionState); | 100 define(name, builder, options, exceptionState); |
84 } | 101 } |
85 | 102 |
86 // http://w3c.github.io/webcomponents/spec/custom/#dfn-element-definition | 103 // http://w3c.github.io/webcomponents/spec/custom/#dfn-element-definition |
87 void CustomElementsRegistry::define( | 104 void CustomElementsRegistry::define( |
88 const AtomicString& name, | 105 const AtomicString& name, |
89 CustomElementDefinitionBuilder& builder, | 106 CustomElementDefinitionBuilder& builder, |
90 const ElementRegistrationOptions& options, | 107 const ElementRegistrationOptions& options, |
91 ExceptionState& exceptionState) | 108 ExceptionState& exceptionState) |
92 { | 109 { |
93 if (!builder.checkConstructorIntrinsics()) | 110 if (!builder.checkConstructorIntrinsics()) |
94 return; | 111 return; |
95 | 112 |
96 if (!CustomElement::isValidName(name)) { | 113 if (throwIfInvalidName(name, exceptionState)) |
97 exceptionState.throwDOMException( | |
98 SyntaxError, | |
99 "\"" + name + "\" is not a valid custom element name"); | |
100 return; | 114 return; |
101 } | |
102 | 115 |
103 if (m_namesBeingDefined.contains(name)) { | 116 if (m_namesBeingDefined.contains(name)) { |
104 exceptionState.throwDOMException( | 117 exceptionState.throwDOMException( |
105 NotSupportedError, | 118 NotSupportedError, |
106 "this name is already being defined in this registry"); | 119 "this name is already being defined in this registry"); |
107 return; | 120 return; |
108 } | 121 } |
109 NameIsBeingDefined defining(this, name); | 122 NameIsBeingDefined defining(this, name); |
110 | 123 |
111 if (nameIsDefined(name) || v0NameIsDefined(name)) { | 124 if (nameIsDefined(name) || v0NameIsDefined(name)) { |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
149 CHECK(definition->descriptor() == descriptor); | 162 CHECK(definition->descriptor() == descriptor); |
150 DefinitionMap::AddResult result = | 163 DefinitionMap::AddResult result = |
151 m_definitions.add(descriptor.name(), definition); | 164 m_definitions.add(descriptor.name(), definition); |
152 CHECK(result.isNewEntry); | 165 CHECK(result.isNewEntry); |
153 | 166 |
154 HeapVector<Member<Element>> candidates; | 167 HeapVector<Member<Element>> candidates; |
155 collectCandidates(descriptor, &candidates); | 168 collectCandidates(descriptor, &candidates); |
156 for (Element* candidate : candidates) | 169 for (Element* candidate : candidates) |
157 CustomElement::enqueueUpgradeReaction(candidate, definition); | 170 CustomElement::enqueueUpgradeReaction(candidate, definition); |
158 | 171 |
159 // TODO(dominicc): Implement steps: | 172 // 19: when-defined promise processing |
160 // 20: when-defined promise processing | 173 const auto& entry = m_whenDefinedPromiseMap.find(name); |
| 174 if (entry == m_whenDefinedPromiseMap.end()) |
| 175 return; |
| 176 entry->value->resolve(); |
| 177 m_whenDefinedPromiseMap.remove(entry); |
161 } | 178 } |
162 | 179 |
163 // https://html.spec.whatwg.org/multipage/scripting.html#dom-customelementsregis
try-get | 180 // https://html.spec.whatwg.org/multipage/scripting.html#dom-customelementsregis
try-get |
164 ScriptValue CustomElementsRegistry::get(const AtomicString& name) | 181 ScriptValue CustomElementsRegistry::get(const AtomicString& name) |
165 { | 182 { |
166 CustomElementDefinition* definition = definitionForName(name); | 183 CustomElementDefinition* definition = definitionForName(name); |
167 if (!definition) { | 184 if (!definition) { |
168 // Binding layer converts |ScriptValue()| to script specific value, | 185 // Binding layer converts |ScriptValue()| to script specific value, |
169 // e.g. |undefined| for v8. | 186 // e.g. |undefined| for v8. |
170 return ScriptValue(); | 187 return ScriptValue(); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
205 if (it != m_upgradeCandidates->end()) { | 222 if (it != m_upgradeCandidates->end()) { |
206 set = it->value; | 223 set = it->value; |
207 } else { | 224 } else { |
208 set = m_upgradeCandidates->add(name, new UpgradeCandidateSet()) | 225 set = m_upgradeCandidates->add(name, new UpgradeCandidateSet()) |
209 .storedValue | 226 .storedValue |
210 ->value; | 227 ->value; |
211 } | 228 } |
212 set->add(candidate); | 229 set->add(candidate); |
213 } | 230 } |
214 | 231 |
| 232 // https://html.spec.whatwg.org/multipage/scripting.html#dom-customelementsregis
try-whendefined |
| 233 ScriptPromise CustomElementsRegistry::whenDefined( |
| 234 ScriptState* scriptState, |
| 235 const AtomicString& name, |
| 236 ExceptionState& exceptionState) |
| 237 { |
| 238 if (throwIfInvalidName(name, exceptionState)) |
| 239 return ScriptPromise(); |
| 240 CustomElementDefinition* definition = definitionForName(name); |
| 241 if (definition) |
| 242 return ScriptPromise::castUndefined(scriptState); |
| 243 ScriptPromiseResolver* resolver = m_whenDefinedPromiseMap.get(name); |
| 244 if (resolver) |
| 245 return resolver->promise(); |
| 246 ScriptPromiseResolver* newResolver = |
| 247 ScriptPromiseResolver::create(scriptState); |
| 248 m_whenDefinedPromiseMap.add(name, newResolver); |
| 249 return newResolver->promise(); |
| 250 } |
| 251 |
215 void CustomElementsRegistry::collectCandidates( | 252 void CustomElementsRegistry::collectCandidates( |
216 const CustomElementDescriptor& desc, | 253 const CustomElementDescriptor& desc, |
217 HeapVector<Member<Element>>* elements) | 254 HeapVector<Member<Element>>* elements) |
218 { | 255 { |
219 UpgradeCandidateMap::iterator it = m_upgradeCandidates->find(desc.name()); | 256 UpgradeCandidateMap::iterator it = m_upgradeCandidates->find(desc.name()); |
220 if (it == m_upgradeCandidates->end()) | 257 if (it == m_upgradeCandidates->end()) |
221 return; | 258 return; |
222 CustomElementUpgradeSorter sorter; | 259 CustomElementUpgradeSorter sorter; |
223 for (Element* element : *it.get()->value) { | 260 for (Element* element : *it.get()->value) { |
224 if (!element || !desc.matches(*element)) | 261 if (!element || !desc.matches(*element)) |
225 continue; | 262 continue; |
226 sorter.add(element); | 263 sorter.add(element); |
227 } | 264 } |
228 | 265 |
229 m_upgradeCandidates->remove(it); | 266 m_upgradeCandidates->remove(it); |
230 sorter.sorted(elements, m_document.get()); | 267 sorter.sorted(elements, m_document.get()); |
231 } | 268 } |
232 | 269 |
233 } // namespace blink | 270 } // namespace blink |
OLD | NEW |