Index: third_party/WebKit/Source/core/dom/Document.cpp |
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp |
index 116247e4c2fc00350ce0e72da6c5148563fbbfff..6883ecda343db3801a519d57bd1cf05bf7b577a8 100644 |
--- a/third_party/WebKit/Source/core/dom/Document.cpp |
+++ b/third_party/WebKit/Source/core/dom/Document.cpp |
@@ -44,6 +44,7 @@ |
#include "bindings/core/v8/V8PerIsolateData.h" |
#include "bindings/core/v8/WindowProxy.h" |
#include "core/HTMLElementFactory.h" |
+#include "core/HTMLElementTypeHelpers.h" |
#include "core/HTMLNames.h" |
#include "core/SVGElementFactory.h" |
#include "core/SVGNames.h" |
@@ -112,6 +113,8 @@ |
#include "core/dom/VisitedLinkState.h" |
#include "core/dom/XMLDocument.h" |
#include "core/dom/custom/CustomElement.h" |
+#include "core/dom/custom/CustomElementDefinition.h" |
+#include "core/dom/custom/CustomElementDescriptor.h" |
#include "core/dom/custom/CustomElementRegistry.h" |
#include "core/dom/custom/V0CustomElementMicrotaskRunQueue.h" |
#include "core/dom/custom/V0CustomElementRegistrationContext.h" |
@@ -710,9 +713,12 @@ String getTypeExtension(Document* document, |
return emptyString(); |
} |
+// https://dom.spec.whatwg.org/#dom-document-createelement |
Element* Document::createElement(const AtomicString& localName, |
const StringOrDictionary& stringOrOptions, |
ExceptionState& exceptionState) { |
+ bool isV1 = stringOrOptions.isDictionary() || !registrationContext(); |
dominicc (has gone to gerrit)
2016/11/15 07:39:53
This v0, v1 split thing is very tricky.
The way y
|
+ // 1. If localName does not match Name production, throw InvalidCharacterError |
if (!isValidName(localName)) { |
exceptionState.throwDOMException( |
InvalidCharacterError, |
@@ -720,26 +726,54 @@ Element* Document::createElement(const AtomicString& localName, |
return nullptr; |
} |
+ // 2. localName converted to ASCII lowercase |
+ const AtomicString& convertedLocalName = convertLocalName(localName); |
+ |
+ // 3. |
+ const AtomicString& is = convertLocalName( |
+ AtomicString(getTypeExtension(this, stringOrOptions, exceptionState))); |
+ const AtomicString& name = is.isNull() ? convertedLocalName : is; |
+ |
+ // 4. Let definition be result of lookup up custom element definition |
+ CustomElementDefinition* definition = nullptr; |
+ if (isV1) { |
+ // Is the runtime flag enabled for customized builtin elements? |
+ const CustomElementDescriptor desc = |
+ RuntimeEnabledFeatures::customElementsBuiltinEnabled() |
+ ? CustomElementDescriptor(name, convertedLocalName) |
+ : CustomElementDescriptor(convertedLocalName, convertedLocalName); |
+ definition = CustomElement::registry(*this)->definitionFor(desc); |
+ // 5. If 'is' is non-null and definition is null, throw NotFoundError |
+ if (!definition && !is.isNull() && stringOrOptions.isDictionary()) { |
+ exceptionState.throwDOMException(NotFoundError, |
+ "Custom element definition not found."); |
+ return nullptr; |
+ } |
+ } |
+ |
+ // 7. Let element be the result of creating an element |
Element* element; |
- if (CustomElement::shouldCreateCustomElement(convertLocalName(localName))) { |
- element = CustomElement::createCustomElementSync( |
- *this, convertLocalName(localName)); |
+ if (definition) { |
+ element = |
+ CustomElement::createCustomElementSync(*this, convertedLocalName, name); |
} else if (V0CustomElement::isValidName(localName) && registrationContext()) { |
element = registrationContext()->createCustomTagElement( |
- *this, QualifiedName(nullAtom, convertLocalName(localName), |
- xhtmlNamespaceURI)); |
+ *this, QualifiedName(nullAtom, convertedLocalName, xhtmlNamespaceURI)); |
} else { |
element = createElement(localName, exceptionState); |
if (exceptionState.hadException()) |
return nullptr; |
} |
- String typeExtention = |
- getTypeExtension(this, stringOrOptions, exceptionState); |
- if (!typeExtention.isEmpty()) { |
- V0CustomElementRegistrationContext::setIsAttributeAndTypeExtension( |
- element, AtomicString(typeExtention)); |
+ // 8. If 'is' is non-null, set 'is' attribute |
+ if (!is.isEmpty()) { |
+ if (stringOrOptions.isString()) { |
+ V0CustomElementRegistrationContext::setIsAttributeAndTypeExtension( |
+ element, is); |
+ } else if (stringOrOptions.isDictionary()) { |
+ element->setAttribute(HTMLNames::isAttr, is); |
+ } |
} |
return element; |
@@ -780,29 +814,71 @@ Element* Document::createElementNS(const AtomicString& namespaceURI, |
return createElement(qName, CreatedByCreateElement); |
} |
+// https://dom.spec.whatwg.org/#internal-createelementns-steps |
Element* Document::createElementNS(const AtomicString& namespaceURI, |
const AtomicString& qualifiedName, |
const StringOrDictionary& stringOrOptions, |
ExceptionState& exceptionState) { |
+ bool isV1 = stringOrOptions.isDictionary() || !registrationContext(); |
+ // 1. Validate and extract |
dominicc (has gone to gerrit)
2016/11/15 07:39:54
These comments seem incomplete?
|
+ |
+ // 2. |
+ const AtomicString& is = |
+ AtomicString(getTypeExtension(this, stringOrOptions, exceptionState)); |
+ const AtomicString& name = is.isNull() ? qualifiedName : is; |
+ |
+ if (!isValidName(qualifiedName)) { |
+ exceptionState.throwDOMException( |
+ InvalidCharacterError, |
+ "The tag name provided ('" + qualifiedName + "') is not a valid name."); |
+ return nullptr; |
+ } |
+ |
QualifiedName qName( |
createQualifiedName(namespaceURI, qualifiedName, exceptionState)); |
if (qName == QualifiedName::null()) |
return nullptr; |
+ // 3. Let definition be result of lookup up custom element definition |
dominicc (has gone to gerrit)
2016/11/15 07:39:54
Transcribe these carefully.
|
+ CustomElementDefinition* definition = nullptr; |
+ if (isV1) { |
+ const CustomElementDescriptor desc = |
+ RuntimeEnabledFeatures::customElementsBuiltinEnabled() |
+ ? CustomElementDescriptor(name, qualifiedName) |
+ : CustomElementDescriptor(qualifiedName, qualifiedName); |
+ definition = CustomElement::registry(*this)->definitionFor(desc); |
+ |
+ // 4. If 'is' is non-null and definition is null, throw NotFoundError |
+ if (!definition && !is.isNull()) { |
+ exceptionState.throwDOMException(NotFoundError, |
+ "Custom element definition not found."); |
+ return nullptr; |
+ } |
+ } |
+ |
+ // 5. Let element be the result of creating an element |
Element* element; |
- if (CustomElement::shouldCreateCustomElement(qName)) |
- element = CustomElement::createCustomElementSync(*this, qName); |
- else if (V0CustomElement::isValidName(qName.localName()) && |
- registrationContext()) |
+ |
+ bool shouldCreateBuiltin = |
+ isV1 && RuntimeEnabledFeatures::customElementsBuiltinEnabled(); |
+ |
+ if (CustomElement::shouldCreateCustomElement(qName) || shouldCreateBuiltin) { |
+ element = CustomElement::createCustomElementSync(*this, qName, is); |
+ } else if (V0CustomElement::isValidName(qName.localName()) && |
+ registrationContext()) { |
element = registrationContext()->createCustomTagElement(*this, qName); |
- else |
+ } else { |
element = createElement(qName, CreatedByCreateElement); |
+ } |
- String typeExtention = |
- getTypeExtension(this, stringOrOptions, exceptionState); |
- if (!typeExtention.isEmpty()) { |
- V0CustomElementRegistrationContext::setIsAttributeAndTypeExtension( |
- element, AtomicString(typeExtention)); |
+ // 6. If 'is' is non-null, set 'is' attribute |
+ if (!is.isEmpty()) { |
+ if (element->getCustomElementState() != CustomElementState::Custom) { |
+ V0CustomElementRegistrationContext::setIsAttributeAndTypeExtension( |
+ element, is); |
+ } else if (stringOrOptions.isDictionary()) { |
+ element->setAttribute(HTMLNames::isAttr, is); |
+ } |
} |
return element; |