Index: third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.cpp |
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.cpp b/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.cpp |
index 33ce143691dd2ac4856f5e2383c97d4e3ffe9a29..cf1b5684335d66c54e55d1be5fd07342eb66e361 100644 |
--- a/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.cpp |
+++ b/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.cpp |
@@ -26,6 +26,8 @@ |
#include "core/html/parser/HTMLConstructionSite.h" |
+#include "bindings/core/v8/Microtask.h" |
+#include "bindings/core/v8/V8PerIsolateData.h" |
#include "core/HTMLElementFactory.h" |
#include "core/HTMLNames.h" |
#include "core/dom/Comment.h" |
@@ -33,9 +35,15 @@ |
#include "core/dom/DocumentType.h" |
#include "core/dom/Element.h" |
#include "core/dom/ElementTraversal.h" |
+#include "core/dom/IgnoreDestructiveWriteCountIncrementer.h" |
#include "core/dom/ScriptLoader.h" |
#include "core/dom/TemplateContentDocumentFragment.h" |
#include "core/dom/Text.h" |
+#include "core/dom/custom/CEReactionsScope.h" |
+#include "core/dom/custom/CustomElementDefinition.h" |
+#include "core/dom/custom/CustomElementDescriptor.h" |
+#include "core/dom/custom/CustomElementsRegistry.h" |
+#include "core/frame/LocalDOMWindow.h" |
#include "core/frame/LocalFrame.h" |
#include "core/html/HTMLFormElement.h" |
#include "core/html/HTMLHtmlElement.h" |
@@ -44,6 +52,7 @@ |
#include "core/html/HTMLTemplateElement.h" |
#include "core/html/parser/AtomicHTMLToken.h" |
#include "core/html/parser/HTMLParserIdioms.h" |
+#include "core/html/parser/HTMLParserReentryPermit.h" |
#include "core/html/parser/HTMLStackItem.h" |
#include "core/html/parser/HTMLToken.h" |
#include "core/loader/FrameLoader.h" |
@@ -314,8 +323,9 @@ void HTMLConstructionSite::executeQueuedTasks() |
// We might be detached now. |
} |
-HTMLConstructionSite::HTMLConstructionSite(Document& document, ParserContentPolicy parserContentPolicy) |
- : m_document(&document) |
+HTMLConstructionSite::HTMLConstructionSite(HTMLParserReentryPermit* reentryPermit, Document& document, ParserContentPolicy parserContentPolicy) |
+ : m_reentryPermit(reentryPermit) |
+ , m_document(&document) |
, m_attachmentRoot(document) |
, m_parserContentPolicy(parserContentPolicy) |
, m_isParsingFragment(false) |
@@ -747,17 +757,111 @@ inline Document& HTMLConstructionSite::ownerDocumentForCurrentNode() |
return currentNode()->document(); |
} |
+// "look up a custom element definition" for a token |
+// https://html.spec.whatwg.org/#look-up-a-custom-element-definition |
+CustomElementDefinition* HTMLConstructionSite::lookUpCustomElementDefinition(Document& document, AtomicHTMLToken* token) |
+{ |
+ // "2. If document does not have a browsing context, return null." |
+ LocalDOMWindow* window = document.domWindow(); |
+ if (!window) |
+ return nullptr; |
+ |
+ // "3. Let registry be document's browsing context's Window's |
+ // CustomElementsRegistry object." |
+ CustomElementsRegistry* registry = window->maybeCustomElements(); |
+ if (!registry) |
+ return nullptr; |
+ |
+ const AtomicString& localName = token->name(); |
+ const Attribute* isAttribute = token->getAttributeItem(HTMLNames::isAttr); |
+ const AtomicString& name = isAttribute ? isAttribute->value() : localName; |
+ CustomElementDescriptor descriptor(name, localName); |
+ |
+ // 4.-6. |
+ return registry->definitionFor(descriptor); |
+} |
+ |
+// "create an element for a token" |
+// https://html.spec.whatwg.org/#create-an-element-for-the-token |
+// TODO(dominicc): When form association is separate from creation, |
+// unify this with foreign element creation. Add a namespace parameter |
+// and check for HTML namespace to lookupCustomElementDefinition. |
HTMLElement* HTMLConstructionSite::createHTMLElement(AtomicHTMLToken* token) |
{ |
+ // "1. Let document be intended parent's node document." |
Document& document = ownerDocumentForCurrentNode(); |
+ |
// Only associate the element with the current form if we're creating the new element |
// in a document with a browsing context (rather than in <template> contents). |
+ // TODO(dominicc): Change form to happen after element creation when |
+ // implementing customized built-in elements. |
HTMLFormElement* form = document.frame() ? m_form.get() : nullptr; |
- // FIXME: This can't use HTMLConstructionSite::createElement because we |
- // have to pass the current form element. We should rework form association |
- // to occur after construction to allow better code sharing here. |
- HTMLElement* element = HTMLElementFactory::createHTMLElement(token->name(), document, form, getCreateElementFlags()); |
- setAttributes(element, token, m_parserContentPolicy); |
+ |
+ // "2. Let local name be the tag name of the token." |
+ // "3. Let is be the value of the "is" attribute in the giev token ..." etc. |
+ // "4. Let definition be the result of looking up a custom element ..." etc. |
+ CustomElementDefinition* definition = m_isParsingFragment ? nullptr : lookUpCustomElementDefinition(document, token); |
+ // "5. If definition is non-null and the parser was not originally created |
+ // for the HTML fragment parsing algorithm, then let will execute script |
+ // be true." |
+ bool willExecuteScript = definition && !m_isParsingFragment; |
+ |
+ HTMLElement* element; |
+ |
+ if (willExecuteScript) { |
+ // "6.1 Increment the parser's script nesting level." |
+ HTMLParserReentryPermit::ScriptNestingLevelIncrementer incrementScriptNestingLevel = m_reentryPermit->incrementScriptNestingLevel(); |
+ |
+ // "6.2 Set the parser pause flag to true." |
+ m_reentryPermit->pause(); |
+ |
+ // TODO(dominicc): Change this once resolved: |
+ // https://github.com/whatwg/html/issues/1630 |
+ IgnoreDestructiveWriteCountIncrementer ignoreDestructiveWrites( |
+ &document); |
+ |
+ // "6.3 If the JavaScript execution context stack is empty, |
+ // then perform a microtask checkpoint." |
+ |
+ // TODO(dominicc): This is the way the Blink HTML parser |
+ // performs checkpoints, but note the spec is different--it |
+ // talks about the JavaScript stack, not the script nesting |
+ // level. |
+ if (1u == m_reentryPermit->scriptNestingLevel()) |
+ Microtask::performCheckpoint(V8PerIsolateData::mainThreadIsolate()); |
+ |
+ // "6.4 Push a new element queue onto the custom element |
+ // reactions stack." |
+ CEReactionsScope reactions; |
+ |
+ // 7. |
+ QualifiedName elementQName(nullAtom, token->name(), HTMLNames::xhtmlNamespaceURI); |
+ element = definition->createElementSync(document, elementQName); |
+ |
+ // "8. Append each attribute in the given token to element." |
+ // We don't use setAttributes here because the custom element |
+ // constructor may have manipulated attributes. |
+ for (const auto& attribute : token->attributes()) |
+ element->setAttribute(attribute.name(), attribute.value()); |
+ |
+ // "9. If will execute script is true, then ..." etc. The |
+ // CEReactionsScope and ScriptNestingLevelIncrementer |
+ // destructors implement steps 9.1-4. |
+ } else { |
+ // FIXME: This can't use |
+ // HTMLConstructionSite::createElement because we have to |
+ // pass the current form element. We should rework form |
+ // association to occur after construction to allow better |
+ // code sharing here. |
+ element = HTMLElementFactory::createHTMLElement(token->name(), document, form, getCreateElementFlags()); |
+ |
+ // "8. Append each attribute in the given token to element." |
+ setAttributes(element, token, m_parserContentPolicy); |
+ } |
+ |
+ // TODO(dominicc): Implement steps 10-12 when customized built-in |
+ // elements are implemented. |
+ |
return element; |
} |