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

Side by Side Diff: third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp

Issue 2054433002: Implement "create an element" when sync for Custom Element V1 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@async-ce
Patch Set: Fix building tests Created 4 years, 6 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
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 "bindings/core/v8/ScriptCustomElementDefinition.h" 5 #include "bindings/core/v8/ScriptCustomElementDefinition.h"
6 6
7 #include "bindings/core/v8/ScriptState.h" 7 #include "bindings/core/v8/ScriptState.h"
8 #include "bindings/core/v8/V8Binding.h" 8 #include "bindings/core/v8/V8Binding.h"
9 #include "bindings/core/v8/V8BindingMacros.h" 9 #include "bindings/core/v8/V8BindingMacros.h"
10 #include "bindings/core/v8/V8CustomElementsRegistry.h" 10 #include "bindings/core/v8/V8CustomElementsRegistry.h"
11 #include "bindings/core/v8/V8Element.h" 11 #include "bindings/core/v8/V8Element.h"
12 #include "bindings/core/v8/V8HiddenValue.h" 12 #include "bindings/core/v8/V8HiddenValue.h"
13 #include "bindings/core/v8/V8ScriptRunner.h" 13 #include "bindings/core/v8/V8ScriptRunner.h"
14 #include "bindings/core/v8/V8ThrowException.h" 14 #include "bindings/core/v8/V8ThrowException.h"
15 #include "core/dom/ExceptionCode.h" 15 #include "core/dom/ExceptionCode.h"
16 #include "core/html/HTMLElement.h"
17 #include "core/html/HTMLUnknownElement.h"
16 #include "v8.h" 18 #include "v8.h"
17 #include "wtf/Allocator.h" 19 #include "wtf/Allocator.h"
18 20
19 namespace blink { 21 namespace blink {
20 22
21 // Retrieves the custom elements constructor -> name map, creating it 23 // Retrieves the custom elements constructor -> name map, creating it
22 // if necessary. The same map is used to keep prototypes alive. 24 // if necessary. The same map is used to keep prototypes alive.
23 static v8::Local<v8::Map> ensureCustomElementsRegistryMap( 25 static v8::Local<v8::Map> ensureCustomElementsRegistryMap(
24 ScriptState* scriptState, 26 ScriptState* scriptState,
25 CustomElementsRegistry* registry) 27 CustomElementsRegistry* registry)
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after
145 const v8::Local<v8::Object>& disconnectedCallback, 147 const v8::Local<v8::Object>& disconnectedCallback,
146 const v8::Local<v8::Object>& attributeChangedCallback, 148 const v8::Local<v8::Object>& attributeChangedCallback,
147 const HashSet<AtomicString>& observedAttributes) 149 const HashSet<AtomicString>& observedAttributes)
148 : CustomElementDefinition(descriptor) 150 : CustomElementDefinition(descriptor)
149 , m_scriptState(scriptState) 151 , m_scriptState(scriptState)
150 , m_constructor(scriptState->isolate(), constructor) 152 , m_constructor(scriptState->isolate(), constructor)
151 , m_observedAttributes(observedAttributes) 153 , m_observedAttributes(observedAttributes)
152 { 154 {
153 } 155 }
154 156
157 static String errorForConstructorResult(Element* element,
158 Document& document, const QualifiedName& tagName)
159 {
160 // https://dom.spec.whatwg.org/#concept-create-element
161 // 6.1.4. If result's attribute list is not empty, then throw a NotSupported Error.
162 if (element->hasAttributes())
163 return "The result must not have attributes";
164 // 6.1.5. If result has children, then throw a NotSupportedError.
165 if (element->hasChildren())
166 return "The result must not have children";
167 // 6.1.6. If result's parent is not null, then throw a NotSupportedError.
168 if (element->parentNode())
169 return "The result must not have a parent";
170 // 6.1.7. If result's node document is not document, then throw a NotSupport edError.
171 if (&element->document() != &document)
172 return "The result must be in the same document";
173 // 6.1.8. If result's namespace is not the HTML namespace, then throw a NotS upportedError.
174 if (element->namespaceURI() != HTMLNames::xhtmlNamespaceURI)
175 return "The result must have HTML namespace";
176 // 6.1.9. If result's local name is not equal to localName, then throw a Not SupportedError.
177 if (element->localName() != tagName.localName())
178 return "The result must have the same localName";
179 return String();
180 }
181
182 HTMLElement* ScriptCustomElementDefinition::createCustomElement(
183 Document& document, const QualifiedName& tagName)
184 {
185 // Create an element
186 // https://dom.spec.whatwg.org/#concept-create-element
187 // 6. If definition is non-null
188 // 6.1. If the synchronous custom elements flag is set:
189 // 6.1.2. Set result to Construct(C). Rethrow any exceptions.
190 Element* element;
191 {
192 v8::TryCatch tryCatch(m_scriptState->isolate());
193 element = runConstructor();
194 if (tryCatch.HasCaught()) {
195 tryCatch.ReThrow();
196 return nullptr;
197 }
198 }
199
200 // 6.1.3. If result does not implement the HTMLElement interface, throw a Ty peError.
dominicc (has gone to gerrit) 2016/06/09 06:39:22 This might be a helpful reference: https://cs.chr
kojii 2016/06/09 16:54:21 Ah, thanks for the pointer, this looks good. It l
201 // TODO(kojii): how to check interface? Is this correct way to do this? This
202 // can check HTMLXxxElement classes, but not duck-typing.
203 // https://github.com/whatwg/html/issues/1402
204 if (!element || !element->isHTMLElement()) {
205 throwTypeError("The result must implement HTMLElement interface");
dominicc (has gone to gerrit) 2016/06/09 06:39:22 Might not be worth adding a helper for one line? B
kojii 2016/06/09 16:54:21 Removed helpers as we switched to ExceptionState.
206 return nullptr;
207 }
208
209 // 6.1.4. through 6.1.9.
dominicc (has gone to gerrit) 2016/06/09 06:39:23 Could we make this a "template method pattern" (no
kojii 2016/06/09 16:54:21 Done.
210 const String message = errorForConstructorResult(element, document, tagName) ;
211 if (!message.isEmpty()) {
212 throwDOMException(NotSupportedError, message);
213 return nullptr;
214 }
215
216 DCHECK_EQ(element->getCustomElementState(), CustomElementState::Custom);
217 return toHTMLElement(element);
218 }
219
220 HTMLElement* ScriptCustomElementDefinition::createCustomElementIgnoringErrors(
221 Document& document, const QualifiedName& tagName)
222 {
223 // When invoked from "create an element for a token":
224 // https://html.spec.whatwg.org/multipage/syntax.html#create-an-element-for- the-token
225 // 7. If this step throws an exception, then report the exception, and
226 // let element be instead a new element that implements HTMLUnknownElement,
227 // with no attributes, namespace set to given namespace, namespace prefix
228 // set to null, custom element state "undefined", and node document set to
229 // document.
230 v8::TryCatch tryCatch(m_scriptState->isolate());
231 tryCatch.SetVerbose(true);
232
233 HTMLElement* element = createCustomElement(document, tagName);
234 if (element && !tryCatch.HasCaught())
235 return element;
236
237 element = HTMLUnknownElement::create(tagName, document);
238 element->setCustomElementState(CustomElementState::Undefined);
239 return element;
240 }
241
155 // https://html.spec.whatwg.org/multipage/scripting.html#upgrades 242 // https://html.spec.whatwg.org/multipage/scripting.html#upgrades
156 bool ScriptCustomElementDefinition::runConstructor(Element* element) 243 bool ScriptCustomElementDefinition::runConstructor(Element* element)
157 { 244 {
158 if (!m_scriptState->contextIsValid()) 245 if (!m_scriptState->contextIsValid())
159 return false; 246 return false;
160 ScriptState::Scope scope(m_scriptState.get());
161 v8::Isolate* isolate = m_scriptState->isolate(); 247 v8::Isolate* isolate = m_scriptState->isolate();
162 248
163 // Step 5 says to rethrow the exception; but there is no one to 249 // Step 5 says to rethrow the exception; but there is no one to
164 // catch it. The side effect is to report the error. 250 // catch it. The side effect is to report the error.
165 v8::TryCatch tryCatch(isolate); 251 v8::TryCatch tryCatch(isolate);
166 tryCatch.SetVerbose(true); 252 tryCatch.SetVerbose(true);
167 253
254 Element* result = runConstructor();
255 if (!result)
256 return false;
257
258 if (result != element) {
259 throwDOMException(
260 InvalidStateError,
261 "custom element constructors must call super() first and must "
262 "not return a different object");
263 return false;
264 }
265
266 return true;
267 }
268
269 Element* ScriptCustomElementDefinition::runConstructor()
270 {
271 if (!m_scriptState->contextIsValid())
272 return nullptr;
273 ScriptState::Scope scope(m_scriptState.get());
274 v8::Isolate* isolate = m_scriptState->isolate();
168 ExecutionContext* executionContext = m_scriptState->getExecutionContext(); 275 ExecutionContext* executionContext = m_scriptState->getExecutionContext();
169 v8::Local<v8::Value> result; 276 v8::Local<v8::Value> result;
170 if (!v8Call(V8ScriptRunner::callAsConstructor( 277 if (!v8Call(V8ScriptRunner::callAsConstructor(
171 isolate, 278 isolate,
172 constructor(), 279 constructor(),
173 executionContext, 280 executionContext,
174 0, 281 0,
175 nullptr), 282 nullptr),
176 result)) 283 result)) {
177 return false; 284 return nullptr;
178
179 if (V8Element::toImplWithTypeCheck(isolate, result) != element) {
180 V8ThrowException::throwException(
181 V8ThrowException::createDOMException(
182 m_scriptState->isolate(),
183 InvalidStateError,
184 "custom element constructors must call super() first and must "
185 "not return a different object",
186 constructor()),
187 m_scriptState->isolate());
188 return false;
189 } 285 }
190 286 return V8Element::toImplWithTypeCheck(isolate, result);
191 return true;
192 } 287 }
193 288
194 v8::Local<v8::Object> ScriptCustomElementDefinition::constructor() const 289 v8::Local<v8::Object> ScriptCustomElementDefinition::constructor() const
195 { 290 {
196 DCHECK(!m_constructor.isEmpty()); 291 DCHECK(!m_constructor.isEmpty());
197 return m_constructor.newLocal(m_scriptState->isolate()); 292 return m_constructor.newLocal(m_scriptState->isolate());
198 } 293 }
199 294
200 v8::Local<v8::Object> ScriptCustomElementDefinition::prototype() const 295 v8::Local<v8::Object> ScriptCustomElementDefinition::prototype() const
201 { 296 {
202 DCHECK(!m_prototype.isEmpty()); 297 DCHECK(!m_prototype.isEmpty());
203 return m_prototype.newLocal(m_scriptState->isolate()); 298 return m_prototype.newLocal(m_scriptState->isolate());
204 } 299 }
205 300
206 // CustomElementDefinition 301 // CustomElementDefinition
207 ScriptValue ScriptCustomElementDefinition::getConstructorForScript() 302 ScriptValue ScriptCustomElementDefinition::getConstructorForScript()
208 { 303 {
209 return ScriptValue(m_scriptState.get(), constructor()); 304 return ScriptValue(m_scriptState.get(), constructor());
210 } 305 }
211 306
307 void ScriptCustomElementDefinition::throwDOMException(int exceptionCode, const S tring& message)
308 {
309 V8ThrowException::throwException(
310 V8ThrowException::createDOMException(
311 m_scriptState->isolate(),
312 exceptionCode,
313 message,
314 constructor()),
315 m_scriptState->isolate());
316 }
317
318 void ScriptCustomElementDefinition::throwTypeError(const String& message)
319 {
320 V8ThrowException::throwTypeError(m_scriptState->isolate(), message);
321 }
322
212 } // namespace blink 323 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698