Chromium Code Reviews| Index: third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp |
| diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp |
| index de725ff62ad418e8ad81b48123a14d602e1e0ba3..fdb53c0f5112a385d8077453834f804e591e5ee0 100644 |
| --- a/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp |
| +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp |
| @@ -13,6 +13,8 @@ |
| #include "bindings/core/v8/V8ScriptRunner.h" |
| #include "bindings/core/v8/V8ThrowException.h" |
| #include "core/dom/ExceptionCode.h" |
| +#include "core/html/HTMLElement.h" |
| +#include "core/html/HTMLUnknownElement.h" |
| #include "v8.h" |
| #include "wtf/Allocator.h" |
| @@ -152,12 +154,96 @@ ScriptCustomElementDefinition::ScriptCustomElementDefinition( |
| { |
| } |
| +static String errorForConstructorResult(Element* element, |
| + Document& document, const QualifiedName& tagName) |
| +{ |
| + // https://dom.spec.whatwg.org/#concept-create-element |
| + // 6.1.4. If result's attribute list is not empty, then throw a NotSupportedError. |
| + if (element->hasAttributes()) |
| + return "The result must not have attributes"; |
| + // 6.1.5. If result has children, then throw a NotSupportedError. |
| + if (element->hasChildren()) |
| + return "The result must not have children"; |
| + // 6.1.6. If result's parent is not null, then throw a NotSupportedError. |
| + if (element->parentNode()) |
| + return "The result must not have a parent"; |
| + // 6.1.7. If result's node document is not document, then throw a NotSupportedError. |
| + if (&element->document() != &document) |
| + return "The result must be in the same document"; |
| + // 6.1.8. If result's namespace is not the HTML namespace, then throw a NotSupportedError. |
| + if (element->namespaceURI() != HTMLNames::xhtmlNamespaceURI) |
| + return "The result must have HTML namespace"; |
| + // 6.1.9. If result's local name is not equal to localName, then throw a NotSupportedError. |
| + if (element->localName() != tagName.localName()) |
| + return "The result must have the same localName"; |
| + return String(); |
| +} |
| + |
| +HTMLElement* ScriptCustomElementDefinition::createCustomElement( |
| + Document& document, const QualifiedName& tagName) |
| +{ |
| + // Create an element |
| + // https://dom.spec.whatwg.org/#concept-create-element |
| + // 6. If definition is non-null |
| + // 6.1. If the synchronous custom elements flag is set: |
| + // 6.1.2. Set result to Construct(C). Rethrow any exceptions. |
| + Element* element; |
| + { |
| + v8::TryCatch tryCatch(m_scriptState->isolate()); |
| + element = runConstructor(); |
| + if (tryCatch.HasCaught()) { |
| + tryCatch.ReThrow(); |
| + return nullptr; |
| + } |
| + } |
| + |
| + // 6.1.3. If result does not implement the HTMLElement interface, throw a TypeError. |
|
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
|
| + // TODO(kojii): how to check interface? Is this correct way to do this? This |
| + // can check HTMLXxxElement classes, but not duck-typing. |
| + // https://github.com/whatwg/html/issues/1402 |
| + if (!element || !element->isHTMLElement()) { |
| + 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.
|
| + return nullptr; |
| + } |
| + |
| + // 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.
|
| + const String message = errorForConstructorResult(element, document, tagName); |
| + if (!message.isEmpty()) { |
| + throwDOMException(NotSupportedError, message); |
| + return nullptr; |
| + } |
| + |
| + DCHECK_EQ(element->getCustomElementState(), CustomElementState::Custom); |
| + return toHTMLElement(element); |
| +} |
| + |
| +HTMLElement* ScriptCustomElementDefinition::createCustomElementIgnoringErrors( |
| + Document& document, const QualifiedName& tagName) |
| +{ |
| + // When invoked from "create an element for a token": |
| + // https://html.spec.whatwg.org/multipage/syntax.html#create-an-element-for-the-token |
| + // 7. If this step throws an exception, then report the exception, and |
| + // let element be instead a new element that implements HTMLUnknownElement, |
| + // with no attributes, namespace set to given namespace, namespace prefix |
| + // set to null, custom element state "undefined", and node document set to |
| + // document. |
| + v8::TryCatch tryCatch(m_scriptState->isolate()); |
| + tryCatch.SetVerbose(true); |
| + |
| + HTMLElement* element = createCustomElement(document, tagName); |
| + if (element && !tryCatch.HasCaught()) |
| + return element; |
| + |
| + element = HTMLUnknownElement::create(tagName, document); |
| + element->setCustomElementState(CustomElementState::Undefined); |
| + return element; |
| +} |
| + |
| // https://html.spec.whatwg.org/multipage/scripting.html#upgrades |
| bool ScriptCustomElementDefinition::runConstructor(Element* element) |
| { |
| if (!m_scriptState->contextIsValid()) |
| return false; |
| - ScriptState::Scope scope(m_scriptState.get()); |
| v8::Isolate* isolate = m_scriptState->isolate(); |
| // Step 5 says to rethrow the exception; but there is no one to |
| @@ -165,6 +251,27 @@ bool ScriptCustomElementDefinition::runConstructor(Element* element) |
| v8::TryCatch tryCatch(isolate); |
| tryCatch.SetVerbose(true); |
| + Element* result = runConstructor(); |
| + if (!result) |
| + return false; |
| + |
| + if (result != element) { |
| + throwDOMException( |
| + InvalidStateError, |
| + "custom element constructors must call super() first and must " |
| + "not return a different object"); |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +Element* ScriptCustomElementDefinition::runConstructor() |
| +{ |
| + if (!m_scriptState->contextIsValid()) |
| + return nullptr; |
| + ScriptState::Scope scope(m_scriptState.get()); |
| + v8::Isolate* isolate = m_scriptState->isolate(); |
| ExecutionContext* executionContext = m_scriptState->getExecutionContext(); |
| v8::Local<v8::Value> result; |
| if (!v8Call(V8ScriptRunner::callAsConstructor( |
| @@ -173,22 +280,10 @@ bool ScriptCustomElementDefinition::runConstructor(Element* element) |
| executionContext, |
| 0, |
| nullptr), |
| - result)) |
| - return false; |
| - |
| - if (V8Element::toImplWithTypeCheck(isolate, result) != element) { |
| - V8ThrowException::throwException( |
| - V8ThrowException::createDOMException( |
| - m_scriptState->isolate(), |
| - InvalidStateError, |
| - "custom element constructors must call super() first and must " |
| - "not return a different object", |
| - constructor()), |
| - m_scriptState->isolate()); |
| - return false; |
| + result)) { |
| + return nullptr; |
| } |
| - |
| - return true; |
| + return V8Element::toImplWithTypeCheck(isolate, result); |
| } |
| v8::Local<v8::Object> ScriptCustomElementDefinition::constructor() const |
| @@ -209,4 +304,20 @@ ScriptValue ScriptCustomElementDefinition::getConstructorForScript() |
| return ScriptValue(m_scriptState.get(), constructor()); |
| } |
| +void ScriptCustomElementDefinition::throwDOMException(int exceptionCode, const String& message) |
| +{ |
| + V8ThrowException::throwException( |
| + V8ThrowException::createDOMException( |
| + m_scriptState->isolate(), |
| + exceptionCode, |
| + message, |
| + constructor()), |
| + m_scriptState->isolate()); |
| +} |
| + |
| +void ScriptCustomElementDefinition::throwTypeError(const String& message) |
| +{ |
| + V8ThrowException::throwTypeError(m_scriptState->isolate(), message); |
| +} |
| + |
| } // namespace blink |