| 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/CustomElementRegistry.h" | 5 #include "core/dom/custom/CustomElementRegistry.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" | 9 #include "bindings/core/v8/ScriptPromise.h" |
| 10 #include "bindings/core/v8/ScriptPromiseResolver.h" | 10 #include "bindings/core/v8/ScriptPromiseResolver.h" |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 83 m_upgradeCandidates(new UpgradeCandidateMap()) {} | 83 m_upgradeCandidates(new UpgradeCandidateMap()) {} |
| 84 | 84 |
| 85 DEFINE_TRACE(CustomElementRegistry) { | 85 DEFINE_TRACE(CustomElementRegistry) { |
| 86 visitor->trace(m_definitions); | 86 visitor->trace(m_definitions); |
| 87 visitor->trace(m_owner); | 87 visitor->trace(m_owner); |
| 88 visitor->trace(m_v0); | 88 visitor->trace(m_v0); |
| 89 visitor->trace(m_upgradeCandidates); | 89 visitor->trace(m_upgradeCandidates); |
| 90 visitor->trace(m_whenDefinedPromiseMap); | 90 visitor->trace(m_whenDefinedPromiseMap); |
| 91 } | 91 } |
| 92 | 92 |
| 93 void CustomElementRegistry::define(ScriptState* scriptState, | 93 CustomElementDefinition* CustomElementRegistry::define( |
| 94 const AtomicString& name, | 94 ScriptState* scriptState, |
| 95 const ScriptValue& constructor, | 95 const AtomicString& name, |
| 96 const ElementDefinitionOptions& options, | 96 const ScriptValue& constructor, |
| 97 ExceptionState& exceptionState) { | 97 const ElementDefinitionOptions& options, |
| 98 ExceptionState& exceptionState) { |
| 98 ScriptCustomElementDefinitionBuilder builder(scriptState, this, constructor, | 99 ScriptCustomElementDefinitionBuilder builder(scriptState, this, constructor, |
| 99 exceptionState); | 100 exceptionState); |
| 100 define(name, builder, options, exceptionState); | 101 return define(name, builder, options, exceptionState); |
| 101 } | 102 } |
| 102 | 103 |
| 103 // http://w3c.github.io/webcomponents/spec/custom/#dfn-element-definition | 104 // http://w3c.github.io/webcomponents/spec/custom/#dfn-element-definition |
| 104 void CustomElementRegistry::define(const AtomicString& name, | 105 CustomElementDefinition* CustomElementRegistry::define( |
| 105 CustomElementDefinitionBuilder& builder, | 106 const AtomicString& name, |
| 106 const ElementDefinitionOptions& options, | 107 CustomElementDefinitionBuilder& builder, |
| 107 ExceptionState& exceptionState) { | 108 const ElementDefinitionOptions& options, |
| 109 ExceptionState& exceptionState) { |
| 108 TRACE_EVENT1("blink", "CustomElementRegistry::define", "name", name.utf8()); | 110 TRACE_EVENT1("blink", "CustomElementRegistry::define", "name", name.utf8()); |
| 109 if (!builder.checkConstructorIntrinsics()) | 111 if (!builder.checkConstructorIntrinsics()) |
| 110 return; | 112 return nullptr; |
| 111 | 113 |
| 112 if (throwIfInvalidName(name, exceptionState)) | 114 if (throwIfInvalidName(name, exceptionState)) |
| 113 return; | 115 return nullptr; |
| 114 | 116 |
| 115 if (nameIsDefined(name) || v0NameIsDefined(name)) { | 117 if (nameIsDefined(name) || v0NameIsDefined(name)) { |
| 116 exceptionState.throwDOMException( | 118 exceptionState.throwDOMException( |
| 117 NotSupportedError, | 119 NotSupportedError, |
| 118 "this name has already been used with this registry"); | 120 "this name has already been used with this registry"); |
| 119 return; | 121 return nullptr; |
| 120 } | 122 } |
| 121 | 123 |
| 122 if (!builder.checkConstructorNotRegistered()) | 124 if (!builder.checkConstructorNotRegistered()) |
| 123 return; | 125 return nullptr; |
| 124 | 126 |
| 125 AtomicString localName = name; | 127 AtomicString localName = name; |
| 126 | 128 |
| 127 // Step 7. customized built-in elements definition | 129 // Step 7. customized built-in elements definition |
| 128 // element interface extends option checks | 130 // element interface extends option checks |
| 129 if (RuntimeEnabledFeatures::customElementsBuiltinEnabled() && | 131 if (RuntimeEnabledFeatures::customElementsBuiltinEnabled() && |
| 130 options.hasExtends()) { | 132 options.hasExtends()) { |
| 131 // 7.1. If element interface is valid custom element name, throw exception | 133 // 7.1. If element interface is valid custom element name, throw exception |
| 132 const AtomicString& extends = AtomicString(options.extends()); | 134 const AtomicString& extends = AtomicString(options.extends()); |
| 133 if (throwIfValidName(AtomicString(options.extends()), exceptionState)) | 135 if (throwIfValidName(AtomicString(options.extends()), exceptionState)) |
| 134 return; | 136 return nullptr; |
| 135 // 7.2. If element interface is undefined element, throw exception | 137 // 7.2. If element interface is undefined element, throw exception |
| 136 if (htmlElementTypeForTag(extends) == | 138 if (htmlElementTypeForTag(extends) == |
| 137 HTMLElementType::kHTMLUnknownElement) { | 139 HTMLElementType::kHTMLUnknownElement) { |
| 138 exceptionState.throwDOMException( | 140 exceptionState.throwDOMException( |
| 139 NotSupportedError, "\"" + extends + "\" is an HTMLUnknownElement"); | 141 NotSupportedError, "\"" + extends + "\" is an HTMLUnknownElement"); |
| 140 return; | 142 return nullptr; |
| 141 } | 143 } |
| 142 // 7.3. Set localName to extends | 144 // 7.3. Set localName to extends |
| 143 localName = extends; | 145 localName = extends; |
| 144 } | 146 } |
| 145 | 147 |
| 146 // TODO(dominicc): Add a test where the prototype getter destroys | 148 // TODO(dominicc): Add a test where the prototype getter destroys |
| 147 // the context. | 149 // the context. |
| 148 | 150 |
| 149 // 8. If this CustomElementRegistry's element definition is | 151 // 8. If this CustomElementRegistry's element definition is |
| 150 // running flag is set, then throw a "NotSupportedError" | 152 // running flag is set, then throw a "NotSupportedError" |
| 151 // DOMException and abort these steps. | 153 // DOMException and abort these steps. |
| 152 if (m_elementDefinitionIsRunning) { | 154 if (m_elementDefinitionIsRunning) { |
| 153 exceptionState.throwDOMException( | 155 exceptionState.throwDOMException( |
| 154 NotSupportedError, "an element definition is already being processed"); | 156 NotSupportedError, "an element definition is already being processed"); |
| 155 return; | 157 return nullptr; |
| 156 } | 158 } |
| 157 | 159 |
| 158 { | 160 { |
| 159 // 9. Set this CustomElementRegistry's element definition is | 161 // 9. Set this CustomElementRegistry's element definition is |
| 160 // running flag. | 162 // running flag. |
| 161 ElementDefinitionIsRunning defining(m_elementDefinitionIsRunning); | 163 ElementDefinitionIsRunning defining(m_elementDefinitionIsRunning); |
| 162 | 164 |
| 163 // 10.1-2 | 165 // 10.1-2 |
| 164 if (!builder.checkPrototype()) | 166 if (!builder.checkPrototype()) |
| 165 return; | 167 return nullptr; |
| 166 | 168 |
| 167 // 10.3-6 | 169 // 10.3-6 |
| 168 if (!builder.rememberOriginalProperties()) | 170 if (!builder.rememberOriginalProperties()) |
| 169 return; | 171 return nullptr; |
| 170 | 172 |
| 171 // "Then, perform the following substep, regardless of whether | 173 // "Then, perform the following substep, regardless of whether |
| 172 // the above steps threw an exception or not: Unset this | 174 // the above steps threw an exception or not: Unset this |
| 173 // CustomElementRegistry's element definition is running | 175 // CustomElementRegistry's element definition is running |
| 174 // flag." | 176 // flag." |
| 175 // (ElementDefinitionIsRunning destructor does this.) | 177 // (ElementDefinitionIsRunning destructor does this.) |
| 176 } | 178 } |
| 177 | 179 |
| 178 CustomElementDescriptor descriptor(name, localName); | 180 CustomElementDescriptor descriptor(name, localName); |
| 179 CustomElementDefinition* definition = builder.build(descriptor); | 181 CustomElementDefinition* definition = builder.build(descriptor); |
| 180 CHECK(!exceptionState.hadException()); | 182 CHECK(!exceptionState.hadException()); |
| 181 CHECK(definition->descriptor() == descriptor); | 183 CHECK(definition->descriptor() == descriptor); |
| 182 DefinitionMap::AddResult result = | 184 DefinitionMap::AddResult result = |
| 183 m_definitions.add(descriptor.name(), definition); | 185 m_definitions.add(descriptor.name(), definition); |
| 184 CHECK(result.isNewEntry); | 186 CHECK(result.isNewEntry); |
| 185 | 187 |
| 186 HeapVector<Member<Element>> candidates; | 188 HeapVector<Member<Element>> candidates; |
| 187 collectCandidates(descriptor, &candidates); | 189 collectCandidates(descriptor, &candidates); |
| 188 for (Element* candidate : candidates) | 190 for (Element* candidate : candidates) |
| 189 definition->enqueueUpgradeReaction(candidate); | 191 definition->enqueueUpgradeReaction(candidate); |
| 190 | 192 |
| 191 // 16: when-defined promise processing | 193 // 16: when-defined promise processing |
| 192 const auto& entry = m_whenDefinedPromiseMap.find(name); | 194 const auto& entry = m_whenDefinedPromiseMap.find(name); |
| 193 if (entry == m_whenDefinedPromiseMap.end()) | 195 if (entry != m_whenDefinedPromiseMap.end()) { |
| 194 return; | 196 entry->value->resolve(); |
| 195 entry->value->resolve(); | 197 m_whenDefinedPromiseMap.remove(entry); |
| 196 m_whenDefinedPromiseMap.remove(entry); | 198 } |
| 199 return definition; |
| 197 } | 200 } |
| 198 | 201 |
| 199 // https://html.spec.whatwg.org/multipage/scripting.html#dom-customelementsregis
try-get | 202 // https://html.spec.whatwg.org/multipage/scripting.html#dom-customelementsregis
try-get |
| 200 ScriptValue CustomElementRegistry::get(const AtomicString& name) { | 203 ScriptValue CustomElementRegistry::get(const AtomicString& name) { |
| 201 CustomElementDefinition* definition = definitionForName(name); | 204 CustomElementDefinition* definition = definitionForName(name); |
| 202 if (!definition) { | 205 if (!definition) { |
| 203 // Binding layer converts |ScriptValue()| to script specific value, | 206 // Binding layer converts |ScriptValue()| to script specific value, |
| 204 // e.g. |undefined| for v8. | 207 // e.g. |undefined| for v8. |
| 205 return ScriptValue(); | 208 return ScriptValue(); |
| 206 } | 209 } |
| 207 return definition->getConstructorForScript(); | 210 return definition->getConstructorForScript(); |
| 208 } | 211 } |
| 209 | 212 |
| 213 // https://html.spec.whatwg.org/multipage/scripting.html#look-up-a-custom-elemen
t-definition |
| 214 // At this point, what the spec calls 'is' is 'name' from desc |
| 210 CustomElementDefinition* CustomElementRegistry::definitionFor( | 215 CustomElementDefinition* CustomElementRegistry::definitionFor( |
| 211 const CustomElementDescriptor& desc) const { | 216 const CustomElementDescriptor& desc) const { |
| 217 // 4&5. If there is a definition in registry with name equal to is/localName |
| 218 // Autonomous elements have the same name and local name |
| 212 CustomElementDefinition* definition = definitionForName(desc.name()); | 219 CustomElementDefinition* definition = definitionForName(desc.name()); |
| 213 if (!definition) | 220 // 4&5. and name equal to localName, return that definition |
| 214 return nullptr; | 221 if (definition and definition->descriptor().localName() == desc.localName()) |
| 215 // The definition for a customized built-in element, such as | 222 return definition; |
| 216 // <button is="my-button"> should not be provided for an | 223 // 6. Return null |
| 217 // autonomous element, such as <my-button>, even though the | 224 return nullptr; |
| 218 // name "my-button" matches. | |
| 219 return definition->descriptor() == desc ? definition : nullptr; | |
| 220 } | 225 } |
| 221 | 226 |
| 222 bool CustomElementRegistry::nameIsDefined(const AtomicString& name) const { | 227 bool CustomElementRegistry::nameIsDefined(const AtomicString& name) const { |
| 223 return m_definitions.contains(name); | 228 return m_definitions.contains(name); |
| 224 } | 229 } |
| 225 | 230 |
| 226 void CustomElementRegistry::entangle(V0CustomElementRegistrationContext* v0) { | 231 void CustomElementRegistry::entangle(V0CustomElementRegistrationContext* v0) { |
| 227 m_v0->add(v0); | 232 m_v0->add(v0); |
| 228 v0->setV1(this); | 233 v0->setV1(this); |
| 229 } | 234 } |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 291 m_upgradeCandidates->remove(it); | 296 m_upgradeCandidates->remove(it); |
| 292 | 297 |
| 293 Document* document = m_owner->document(); | 298 Document* document = m_owner->document(); |
| 294 if (!document) | 299 if (!document) |
| 295 return; | 300 return; |
| 296 | 301 |
| 297 sorter.sorted(elements, document); | 302 sorter.sorted(elements, document); |
| 298 } | 303 } |
| 299 | 304 |
| 300 } // namespace blink | 305 } // namespace blink |
| OLD | NEW |