Diff
Modified: trunk/LayoutTests/ChangeLog (197462 => 197463)
--- trunk/LayoutTests/ChangeLog 2016-03-02 21:42:22 UTC (rev 197462)
+++ trunk/LayoutTests/ChangeLog 2016-03-02 21:56:47 UTC (rev 197463)
@@ -1,3 +1,22 @@
+2016-03-01 Ryosuke Niwa <[email protected]>
+
+ Make HTML parser construct custom elements
+ https://bugs.webkit.org/show_bug.cgi?id=154908
+
+ Reviewed by Antti Koivisto.
+
+ Added W3C testharness.js based tests for instantiating custom elements inside the HTML parser.
+
+ * fast/custom-elements/parser: Added.
+ * fast/custom-elements/parser/parser-constructs-custom-elements-expected.txt: Added.
+ * fast/custom-elements/parser/parser-constructs-custom-elements.html: Added.
+ * fast/custom-elements/parser/parser-fallsback-to-unknown-element-expected.txt: Added.
+ * fast/custom-elements/parser/parser-fallsback-to-unknown-element.html: Added.
+ * fast/custom-elements/parser/parser-sets-attributes-and-children-expected.txt: Added.
+ * fast/custom-elements/parser/parser-sets-attributes-and-children.html: Added.
+ * fast/custom-elements/parser/parser-uses-constructed-element-expected.txt: Added.
+ * fast/custom-elements/parser/parser-uses-constructed-element.html: Added.
+
2016-03-02 Chris Dumez <[email protected]>
Align HTMLInputElement.maxLength with the specification
Added: trunk/LayoutTests/fast/custom-elements/parser/parser-constructs-custom-elements-expected.txt (0 => 197463)
--- trunk/LayoutTests/fast/custom-elements/parser/parser-constructs-custom-elements-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/custom-elements/parser/parser-constructs-custom-elements-expected.txt 2016-03-02 21:56:47 UTC (rev 197463)
@@ -0,0 +1,4 @@
+
+PASS HTML parser must NOT create a custom element before defineElement is called
+PASS HTML parser must create a defined custom element before executing inline scripts
+
Added: trunk/LayoutTests/fast/custom-elements/parser/parser-constructs-custom-elements.html (0 => 197463)
--- trunk/LayoutTests/fast/custom-elements/parser/parser-constructs-custom-elements.html (rev 0)
+++ trunk/LayoutTests/fast/custom-elements/parser/parser-constructs-custom-elements.html 2016-03-02 21:56:47 UTC (rev 197463)
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Custom Elements: Changes to the HTML parser</title>
+<meta name="author" title="Ryosuke Niwa" href=""
+<meta name="assert" content="HTML parser creates a custom element">
+<script src=""
+<script src=""
+<link rel='stylesheet' href=''>
+</head>
+<body>
+<div id="log"></div>
+<my-custom-element id="instance1"></my-custom-element>
+<script>
+
+class MyCustomElement extends HTMLElement { };
+
+test(function () {
+ var customElement = document.getElementById('instance1');
+
+ assert_true(customElement instanceof HTMLElement, 'An unresolved custom element must be an instance of HTMLElement');
+ assert_false(customElement instanceof MyCustomElement, 'An unresolved custom element must NOT be an instance of that custom element');
+ assert_equals(customElement.localName, 'my-custom-element');
+ assert_equals(customElement.namespaceURI, 'http://www.w3.org/1999/xhtml', 'A custom element HTML must use HTML namespace');
+
+}, 'HTML parser must NOT create a custom element before defineElement is called');
+
+document.defineCustomElement('my-custom-element', MyCustomElement);
+
+</script>
+<my-custom-element id="instance2"></my-custom-element>
+<script>
+
+test(function () {
+ var customElement = document.getElementById('instance2');
+
+ assert_true(customElement instanceof HTMLElement, 'A resolved custom element must be an instance of HTMLElement');
+ assert_false(customElement instanceof HTMLUnknownElement, 'A resolved custom element must NOT be an instance of HTMLUnknownElement');
+ assert_true(customElement instanceof MyCustomElement, 'A resolved custom element must be an instance of that custom element');
+ assert_equals(customElement.localName, 'my-custom-element');
+ assert_equals(customElement.namespaceURI, 'http://www.w3.org/1999/xhtml', 'A custom element HTML must use HTML namespace');
+
+}, 'HTML parser must create a defined custom element before executing inline scripts');
+
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/fast/custom-elements/parser/parser-fallsback-to-unknown-element-expected.txt (0 => 197463)
--- trunk/LayoutTests/fast/custom-elements/parser/parser-fallsback-to-unknown-element-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/custom-elements/parser/parser-fallsback-to-unknown-element-expected.txt 2016-03-02 21:56:47 UTC (rev 197463)
@@ -0,0 +1,6 @@
+
+PASS HTML parser must create a fallback HTMLUnknownElement when a custom element constructor returns a Text node
+PASS HTML parser must create a fallback HTMLUnknownElement when a custom element constructor returns non-Element object
+PASS HTML parser must create a fallback HTMLUnknownElement when a custom element constructor does not call super()
+PASS HTML parser must create a fallback HTMLUnknownElement when a custom element constructor throws an exception
+
Added: trunk/LayoutTests/fast/custom-elements/parser/parser-fallsback-to-unknown-element.html (0 => 197463)
--- trunk/LayoutTests/fast/custom-elements/parser/parser-fallsback-to-unknown-element.html (rev 0)
+++ trunk/LayoutTests/fast/custom-elements/parser/parser-fallsback-to-unknown-element.html 2016-03-02 21:56:47 UTC (rev 197463)
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Custom Elements: Changes to the HTML parser</title>
+<meta name="author" title="Ryosuke Niwa" href=""
+<meta name="assert" content="HTML parser must fallback to creating a HTMLUnknownElement when a custom element construction fails">
+<script src=""
+<script src=""
+<link rel='stylesheet' href=''>
+</head>
+<body>
+<div id="log"></div>
+<script>
+
+class ReturnsTextNode extends HTMLElement {
+ constructor() {
+ super();
+ return document.createTextNode('some text');
+ }
+};
+document.defineCustomElement('returns-text', ReturnsTextNode);
+
+class ReturnsNonElementObject extends HTMLElement {
+ constructor() {
+ super();
+ return {};
+ }
+};
+document.defineCustomElement('returns-non-element-object', ReturnsNonElementObject);
+
+class LacksSuperCall extends HTMLElement {
+ constructor() { }
+};
+document.defineCustomElement('lacks-super-call', LacksSuperCall);
+
+class ThrowsException extends HTMLElement {
+ constructor() {
+ throw 'Bad';
+ }
+};
+document.defineCustomElement('throws-exception', ThrowsException);
+
+</script>
+<returns-text></returns-text>
+<returns-non-element-object></returns-non-element-object>
+<lacks-super-call></lacks-super-call>
+<throws-exception></throws-exception>
+<script>
+
+test(function () {
+ var instance = document.querySelector('returns-text');
+
+ assert_false(instance instanceof ReturnsTextNode, 'HTML parser must NOT instantiate a custom element when the constructor returns a Text node');
+ assert_true(instance instanceof HTMLElement, 'The fallback element created by HTML parser must be an instance of HTMLElement');
+ assert_true(instance instanceof HTMLUnknownElement, 'The fallback element created by HTML parser must be an instance of HTMLUnknownElement');
+
+}, 'HTML parser must create a fallback HTMLUnknownElement when a custom element constructor returns a Text node');
+
+test(function () {
+ var instance = document.querySelector('returns-non-element-object');
+
+ assert_false(instance instanceof ReturnsNonElementObject, 'HTML parser must NOT instantiate a custom element when the constructor returns a non-Element object');
+ assert_true(instance instanceof HTMLElement, 'The fallback element created by HTML parser must be an instance of HTMLElement');
+ assert_true(instance instanceof HTMLUnknownElement, 'The fallback element created by HTML parser must be an instance of HTMLUnknownElement');
+
+}, 'HTML parser must create a fallback HTMLUnknownElement when a custom element constructor returns non-Element object');
+
+test(function () {
+ var instance = document.querySelector('lacks-super-call');
+
+ assert_false(instance instanceof LacksSuperCall, 'HTML parser must NOT instantiate a custom element when the constructor does not call super()');
+ assert_true(instance instanceof HTMLElement, 'The fallback element created by HTML parser must be an instance of HTMLElement');
+ assert_true(instance instanceof HTMLUnknownElement, 'The fallback element created by HTML parser must be an instance of HTMLUnknownElement');
+
+}, 'HTML parser must create a fallback HTMLUnknownElement when a custom element constructor does not call super()');
+
+test(function () {
+ var instance = document.querySelector('throws-exception');
+
+ assert_false(instance instanceof ThrowsException, 'HTML parser must NOT instantiate a custom element when the constructor throws an exception');
+ assert_true(instance instanceof HTMLElement, 'The fallback element created by HTML parser must be an instance of HTMLElement');
+ assert_true(instance instanceof HTMLUnknownElement, 'The fallback element created by HTML parser must be an instance of HTMLUnknownElement');
+
+}, 'HTML parser must create a fallback HTMLUnknownElement when a custom element constructor throws an exception');
+
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/fast/custom-elements/parser/parser-sets-attributes-and-children-expected.txt (0 => 197463)
--- trunk/LayoutTests/fast/custom-elements/parser/parser-sets-attributes-and-children-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/custom-elements/parser/parser-sets-attributes-and-children-expected.txt 2016-03-02 21:56:47 UTC (rev 197463)
@@ -0,0 +1,6 @@
+hello world
+
+PASS HTML parser must set the attributes
+PASS HTML parser must append child nodes
+PASS HTML parser must set the attributes or append children before calling constructor
+
Added: trunk/LayoutTests/fast/custom-elements/parser/parser-sets-attributes-and-children.html (0 => 197463)
--- trunk/LayoutTests/fast/custom-elements/parser/parser-sets-attributes-and-children.html (rev 0)
+++ trunk/LayoutTests/fast/custom-elements/parser/parser-sets-attributes-and-children.html 2016-03-02 21:56:47 UTC (rev 197463)
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Custom Elements: Changes to the HTML parser</title>
+<meta name="author" title="Ryosuke Niwa" href=""
+<meta name="assert" content="HTML parser must set the attributes and append the children on a custom element">
+<script src=""
+<script src=""
+<link rel='stylesheet' href=''>
+</head>
+<body>
+<div id="log"></div>
+<script>
+
+var numberOfAttributesInConstructor;
+var numberOfChildNodesInConstructor;
+
+class MyCustomElement extends HTMLElement {
+ constructor(...args) {
+ super(...args);
+ numberOfAttributesInConstructor = this.attributes.length;
+ numberOfChildNodesInConstructor = this.childNodes.length;
+ }
+};
+document.defineCustomElement('my-custom-element', MyCustomElement);
+
+</script>
+<my-custom-element id="custom-element-id" class="class1 class2">hello <b>world</b></my-custom-element>
+<script>
+
+var customElement = document.querySelector('my-custom-element');
+
+test(function () {
+ assert_equals(customElement.getAttribute('id'), 'custom-element-id', 'HTML parser must preserve the id attribute');
+ assert_equals(customElement.id, 'custom-element-id', 'HTML parser must preserve the semantics of reflect for the id attribute');
+ assert_equals(customElement.getAttribute('class'), 'class1 class2', 'HTML parser must preserve the class attribute');
+ assert_equals(customElement.classList.length, 2, 'HTML parser must initialize classList on custom elements');
+ assert_equals(customElement.classList[0], 'class1', 'HTML parser must initialize classList on custom elements');
+ assert_equals(customElement.classList[1], 'class2', 'HTML parser must initialize classList on custom elements');
+
+ assert_equals(customElement.childNodes.length, 2, 'HTML parser must append child nodes');
+ assert_equals(customElement.classList[0], 'class1', 'HTML parser must initialize classList on custom elements');
+ assert_equals(customElement.classList[1], 'class2', 'HTML parser must initialize classList on custom elements');
+
+}, 'HTML parser must set the attributes');
+
+test(function () {
+ assert_equals(customElement.childNodes.length, 2, 'HTML parser must append child nodes');
+ assert_true(customElement.firstChild instanceof Text, 'HTML parser must append Text node child to a custom element');
+ assert_equals(customElement.firstChild.data, 'hello ', 'HTML parser must append Text node child to a custom element');
+ assert_true(customElement.lastChild instanceof HTMLElement, 'HTML parser must append a builtin element child to a custom element');
+ assert_true(customElement.lastChild.firstChild instanceof Text, 'HTML parser must preserve grandchild nodes of a custom element');
+ assert_equals(customElement.lastChild.firstChild.data, 'world', 'HTML parser must preserve grandchild nodes of a custom element');
+}, 'HTML parser must append child nodes');
+
+test(function () {
+ assert_equals(numberOfAttributesInConstructor, 0, 'HTML parser must not set attributes on a custom element before invoking the constructor');
+ assert_equals(numberOfChildNodesInConstructor, 0, 'HTML parser must not append child nodes to a custom element before invoking the constructor');
+}, 'HTML parser must set the attributes or append children before calling constructor');
+
+</script>
+</body>
+</html>
Added: trunk/LayoutTests/fast/custom-elements/parser/parser-uses-constructed-element-expected.txt (0 => 197463)
--- trunk/LayoutTests/fast/custom-elements/parser/parser-uses-constructed-element-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/custom-elements/parser/parser-uses-constructed-element-expected.txt 2016-03-02 21:56:47 UTC (rev 197463)
@@ -0,0 +1,4 @@
+
+PASS HTML parser must use the returned value of the custom element constructor instead of the one created before super() call
+PASS HTML parser must use the returned value of the custom element constructor instead using the one created in super() call
+
Added: trunk/LayoutTests/fast/custom-elements/parser/parser-uses-constructed-element.html (0 => 197463)
--- trunk/LayoutTests/fast/custom-elements/parser/parser-uses-constructed-element.html (rev 0)
+++ trunk/LayoutTests/fast/custom-elements/parser/parser-uses-constructed-element.html 2016-03-02 21:56:47 UTC (rev 197463)
@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Custom Elements: Changes to the HTML parser</title>
+<meta name="author" title="Ryosuke Niwa" href=""
+<meta name="assert" content="HTML parser must construct a custom element instead of upgrading">
+<script src=""
+<script src=""
+<link rel='stylesheet' href=''>
+</head>
+<body>
+<div id="log"></div>
+<script>
+
+let anotherElementCreatedBeforeSuperCall = undefined;
+let elementCreatedBySuperCall = undefined;
+let shouldCreateElementBeforeSuperCall = true;
+class InstantiatesItselfBeforeSuper extends HTMLElement {
+ constructor() {
+ if (shouldCreateElementBeforeSuperCall) {
+ shouldCreateElementBeforeSuperCall = false;
+ anotherElementCreatedBeforeSuperCall = new InstantiatesItselfBeforeSuper();
+ }
+ super();
+ elementCreatedBySuperCall = this;
+ }
+};
+document.defineCustomElement('instantiates-itself-before-super', InstantiatesItselfBeforeSuper);
+
+let shouldCreateAnotherInstance = true;
+let anotherInstance = undefined;
+let firstInstance = undefined;
+class ReturnsAnotherInstance extends HTMLElement {
+ constructor() {
+ super();
+ if (shouldCreateAnotherInstance) {
+ shouldCreateAnotherInstance = false;
+ firstInstance = this;
+ anotherInstance = new ReturnsAnotherInstance;
+ return anotherInstance;
+ } else
+ return this;
+ }
+};
+document.defineCustomElement('returns-another-instance', ReturnsAnotherInstance);
+
+</script>
+<instantiates-itself-before-super></instantiates-itself-before-super>
+<returns-another-instance></returns-another-instance>
+<script>
+
+test(function () {
+ var instance = document.querySelector('instantiates-itself-before-super');
+
+ assert_equals(instance, elementCreatedBySuperCall, 'HTML parser must insert the element returned by the custom element constructor');
+ assert_not_equals(instance, anotherElementCreatedBeforeSuperCall, 'HTML parser must not insert another instance of the custom element created before super() call');
+ assert_equals(anotherElementCreatedBeforeSuperCall.parentNode, null, 'HTML parser must not insert another instance of the custom element created before super() call');
+
+}, 'HTML parser must use the returned value of the custom element constructor instead of the one created before super() call');
+
+test(function () {
+ var instance = document.querySelector('returns-another-instance');
+
+ assert_equals(instance, anotherInstance, 'HTML parser must insert the element returned by the custom element constructor');
+ assert_not_equals(instance, firstInstance, 'HTML parser must not insert the element created by super() call if the constructor returned another element');
+ assert_equals(firstInstance.parentNode, null, 'HTML parser must not insert the element created by super() call if the constructor returned another element');
+
+}, 'HTML parser must use the returned value of the custom element constructor instead using the one created in super() call');
+
+</script>
+</body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (197462 => 197463)
--- trunk/Source/WebCore/ChangeLog 2016-03-02 21:42:22 UTC (rev 197462)
+++ trunk/Source/WebCore/ChangeLog 2016-03-02 21:56:47 UTC (rev 197463)
@@ -1,3 +1,80 @@
+2016-03-01 Ryosuke Niwa <[email protected]>
+
+ Make HTML parser construct custom elements
+ https://bugs.webkit.org/show_bug.cgi?id=154908
+ <rdar://problem/24923735>
+
+ Reviewed by Antti Koivisto.
+
+ Added the support for instantiating custom elements inside the parser. Based on Jan F2F discussion,
+ the HTML parser is going to synchronously construct custom elements. When a custom element constructor
+ throws, the HTML parser creates a HTMLUnknownElement instead.
+
+ In our implementation, we pause the parser completely and construct custom elements using the same
+ mechanism used to run author scripts. It's possible that we may want to apply some optimizations to
+ to make custom element construction but it's probably a good idea to get semantics right first.
+
+ Tests: fast/custom-elements/parser/parser-constructs-custom-elements.html
+ fast/custom-elements/parser/parser-fallsback-to-unknown-element.html
+ fast/custom-elements/parser/parser-sets-attributes-and-children.html
+ fast/custom-elements/parser/parser-uses-constructed-element.html
+
+ * bindings/js/JSCustomElementInterface.cpp:
+ (WebCore::JSCustomElementInterface::constructElement): Added ShouldClearException as an argument
+ to be used by the HTML parser since the parser can't re-throw to anywhere or fail parsing.
+
+ * bindings/js/JSCustomElementInterface.h:
+ (WebCore::JSCustomElementInterface::ShouldClearException): Added.
+
+ * dom/Document.cpp:
+ (WebCore::createHTMLElementWithNameValidation): Do not clear the exception here since createElement
+ must re-throw the exception thrown by a custom element constructor.
+ (WebCore::Document::createElementForBindings):
+
+ * dom/make_names.pl:
+ (printFactoryCppFile): Added ConstructorFunctionMapEntry which contains the constructor function
+ as well as the qualified name.
+ (printFactoryHeaderFile): Added a variant of createKnownElement and createElement that takes
+ AtomicString instead of QualifiedName.
+
+ * html/parser/HTMLConstructionSite.cpp:
+ (WebCore::setAttributes): Added a variant that takes Vector<Attribute>.
+ (WebCore::HTMLConstructionSite::insertHTMLElementOrFindCustomElementInterface): Added. Returns a
+ custom element interface when the element doesn't match any builtin element and there is a custom
+ element definition that matches the specified name.
+ (WebCore::HTMLConstructionSite::insertCustomElement): Added. Like insertElement but also sets the
+ attributes on the newly created custom element.
+ (WebCore::HTMLConstructionSite::createHTMLElementOrFindCustomElementInterface): Extracted from
+ createHTMLElement. When customElementInterface is not nullptr, we optionally find the custom
+ element interface and return nullptr.
+ (WebCore::HTMLConstructionSite::createHTMLElement):
+ * html/parser/HTMLConstructionSite.h:
+
+ * html/parser/HTMLDocumentParser.cpp:
+ (WebCore::HTMLDocumentParser::runScriptsForPausedTreeBuilder): Create a custom element when there
+ is a pending custom element to create (i.e. m_customElementToConstruct is not empty).
+ (WebCore::HTMLDocumentParser::isWaitingForScripts):
+
+ * html/parser/HTMLStackItem.h:
+ (WebCore::HTMLStackItem::create): Added a variant used for custom elements.
+ (WebCore::HTMLStackItem::HTMLStackItem): Ditto.
+
+ * html/parser/HTMLTreeBuilder.cpp:
+ (WebCore::CustomElementConstructionData::CustomElementConstructionData): Added. It needs to be in
+ the cpp file to avoid introducing more header dependencies in HTMLTreeBuilder.h.
+ (WebCore::CustomElementConstructionData::~CustomElementConstructionData): Ditto.
+ (WebCore::HTMLTreeBuilder::processStartTagForInBody): Use insertGenericHTMLElement when creating
+ a generic element that could be custom elements.
+ (WebCore::HTMLTreeBuilder::insertGenericHTMLElement): Added. Create and insert a new element
+ or set m_customElementToConstruct so that the HTMLDocumentParser will create a custom element later.
+ (WebCore::HTMLTreeBuilder::didCreateCustomOrCallbackElement): Added. Called by HTMLDocumentParser
+ when it finishes creating a new custom element.
+
+ * html/parser/HTMLTreeBuilder.h:
+ (WebCore::HTMLTreeBuilder::takeCustomElementConstructionData): Added.
+ (WebCore::HTMLTreeBuilder::hasParserBlockingScriptWork): Renamed from hasParserBlockingScript.
+ Checks the existence of m_customElementToConstruct as well as m_scriptToProcess.
+
2016-03-02 Zalan Bujtas <[email protected]>
Use IndentTextOrNot instead of passing isFirstLine/shouldIndentText as bool.
Modified: trunk/Source/WebCore/bindings/js/JSCustomElementInterface.cpp (197462 => 197463)
--- trunk/Source/WebCore/bindings/js/JSCustomElementInterface.cpp 2016-03-02 21:42:22 UTC (rev 197462)
+++ trunk/Source/WebCore/bindings/js/JSCustomElementInterface.cpp 2016-03-02 21:56:47 UTC (rev 197463)
@@ -55,7 +55,7 @@
{
}
-RefPtr<Element> JSCustomElementInterface::constructElement(const AtomicString& tagName)
+RefPtr<Element> JSCustomElementInterface::constructElement(const AtomicString& tagName, ShouldClearException shouldClearException)
{
if (!canInvokeCallback())
return nullptr;
@@ -88,6 +88,9 @@
JSValue newElement = construct(state, m_constructor.get(), constructType, constructData, args);
InspectorInstrumentation::didCallFunction(cookie, context);
+ if (shouldClearException == ShouldClearException::Clear && state->hadException())
+ state->clearException();
+
if (newElement.isEmpty())
return nullptr;
Modified: trunk/Source/WebCore/bindings/js/JSCustomElementInterface.h (197462 => 197463)
--- trunk/Source/WebCore/bindings/js/JSCustomElementInterface.h 2016-03-02 21:42:22 UTC (rev 197462)
+++ trunk/Source/WebCore/bindings/js/JSCustomElementInterface.h 2016-03-02 21:56:47 UTC (rev 197463)
@@ -59,7 +59,8 @@
return adoptRef(*new JSCustomElementInterface(callback, globalObject));
}
- RefPtr<Element> constructElement(const AtomicString&);
+ enum class ShouldClearException { Clear, DoNotClear };
+ RefPtr<Element> constructElement(const AtomicString&, ShouldClearException);
ScriptExecutionContext* scriptExecutionContext() const { return ContextDestructionObserver::scriptExecutionContext(); }
JSC::JSObject* constructor() { return m_constructor.get(); }
Modified: trunk/Source/WebCore/dom/Document.cpp (197462 => 197463)
--- trunk/Source/WebCore/dom/Document.cpp 2016-03-02 21:42:22 UTC (rev 197462)
+++ trunk/Source/WebCore/dom/Document.cpp 2016-03-02 21:56:47 UTC (rev 197463)
@@ -879,35 +879,35 @@
clearStyleResolver();
}
-static RefPtr<Element> createHTMLElementWithNameValidation(Document& document, const QualifiedName qualifiedName, ExceptionCode& ec)
+static RefPtr<Element> createHTMLElementWithNameValidation(Document& document, const AtomicString& localName, ExceptionCode& ec)
{
- RefPtr<HTMLElement> element = HTMLElementFactory::createKnownElement(qualifiedName, document);
+ RefPtr<HTMLElement> element = HTMLElementFactory::createKnownElement(localName, document);
if (LIKELY(element))
return element;
#if ENABLE(CUSTOM_ELEMENTS)
auto* definitions = document.customElementDefinitions();
if (UNLIKELY(definitions)) {
- if (auto* interface = definitions->findInterface(qualifiedName))
- return interface->constructElement(qualifiedName.localName());
+ if (auto* interface = definitions->findInterface(localName))
+ return interface->constructElement(localName, JSCustomElementInterface::ShouldClearException::DoNotClear);
}
#endif
- if (UNLIKELY(!Document::isValidName(qualifiedName.localName()))) {
+ if (UNLIKELY(!Document::isValidName(localName))) {
ec = INVALID_CHARACTER_ERR;
return nullptr;
}
- return HTMLUnknownElement::create(qualifiedName, document);
+ return HTMLUnknownElement::create(QualifiedName(nullAtom, localName, xhtmlNamespaceURI), document);
}
RefPtr<Element> Document::createElementForBindings(const AtomicString& name, ExceptionCode& ec)
{
if (isHTMLDocument())
- return createHTMLElementWithNameValidation(*this, QualifiedName(nullAtom, name.convertToASCIILowercase(), xhtmlNamespaceURI), ec);
+ return createHTMLElementWithNameValidation(*this, name.convertToASCIILowercase(), ec);
if (isXHTMLDocument())
- return createHTMLElementWithNameValidation(*this, QualifiedName(nullAtom, name, xhtmlNamespaceURI), ec);
+ return createHTMLElementWithNameValidation(*this, name, ec);
if (!isValidName(name)) {
ec = INVALID_CHARACTER_ERR;
Modified: trunk/Source/WebCore/dom/make_names.pl (197462 => 197463)
--- trunk/Source/WebCore/dom/make_names.pl 2016-03-02 21:42:22 UTC (rev 197462)
+++ trunk/Source/WebCore/dom/make_names.pl 2016-03-02 21:56:47 UTC (rev 197463)
@@ -986,10 +986,28 @@
$argumentList = "name, document, createdByParser";
}
+ my $lowercaseNamespacePrefix = lc($parameters{namespacePrefix});
+
printConstructors($F, \%tagConstructorMap);
print F <<END
-static NEVER_INLINE void populate$parameters{namespace}FactoryMap(HashMap<AtomicStringImpl*, $parameters{namespace}ConstructorFunction>& map)
+
+struct ConstructorFunctionMapEntry {
+ ConstructorFunctionMapEntry($parameters{namespace}ConstructorFunction function, const QualifiedName& name)
+ : function(function)
+ , qualifiedName(&name)
+ { }
+
+ ConstructorFunctionMapEntry()
+ : function(nullptr)
+ , qualifiedName(nullptr)
+ { }
+
+ $parameters{namespace}ConstructorFunction function;
+ const QualifiedName* qualifiedName; // Use pointer instead of reference so that emptyValue() in HashMap is cheap to create.
+};
+
+static NEVER_INLINE void populate$parameters{namespace}FactoryMap(HashMap<AtomicStringImpl*, ConstructorFunctionMapEntry>& map)
{
struct TableEntry {
const QualifiedName& name;
@@ -1006,25 +1024,42 @@
};
for (unsigned i = 0; i < WTF_ARRAY_LENGTH(table); ++i)
- map.add(table[i].name.localName().impl(), table[i].function);
+ map.add(table[i].name.localName().impl(), ConstructorFunctionMapEntry(table[i].function, table[i].name));
}
-RefPtr<$parameters{namespace}Element> $parameters{namespace}ElementFactory::createKnownElement(const QualifiedName& name, Document& document$formElementArgumentForDefinition, bool createdByParser)
+
+static ConstructorFunctionMapEntry find$parameters{namespace}ElementConstructorFunction(const AtomicString& localName)
{
- static NeverDestroyed<HashMap<AtomicStringImpl*, $parameters{namespace}ConstructorFunction>> functions;
- if (functions.get().isEmpty())
- populate$parameters{namespace}FactoryMap(functions);
- $parameters{namespace}ConstructorFunction function = functions.get().get(name.localName().impl());
- if (LIKELY(function))
- return function($argumentList);
+ static NeverDestroyed<HashMap<AtomicStringImpl*, ConstructorFunctionMapEntry>> map;
+ if (map.get().isEmpty())
+ populate$parameters{namespace}FactoryMap(map);
+ return map.get().get(localName.impl());
+}
+
+RefPtr<$parameters{namespace}Element> $parameters{namespace}ElementFactory::createKnownElement(const AtomicString& localName, Document& document$formElementArgumentForDefinition, bool createdByParser)
+{
+ const ConstructorFunctionMapEntry& entry = find$parameters{namespace}ElementConstructorFunction(localName);
+ if (LIKELY(entry.function)) {
+ ASSERT(entry.qualifiedName);
+ const auto& name = *entry.qualifiedName;
+ return entry.function($argumentList);
+ }
return nullptr;
}
-Ref<$parameters{namespace}Element> $parameters{namespace}ElementFactory::createElement(const QualifiedName& name, Document& document$formElementArgumentForDefinition, bool createdByParser)
+Ref<$parameters{namespace}Element> $parameters{namespace}ElementFactory::createElement(const AtomicString& name, Document& document$formElementArgumentForDefinition, bool createdByParser)
{
RefPtr<$parameters{namespace}Element> element = $parameters{namespace}ElementFactory::createKnownElement($argumentList);
if (LIKELY(element))
return element.releaseNonNull();
+ return $parameters{fallbackInterfaceName}::create(QualifiedName(nullAtom, name, ${lowercaseNamespacePrefix}NamespaceURI), document);
+}
+
+Ref<$parameters{namespace}Element> $parameters{namespace}ElementFactory::createElement(const QualifiedName& name, Document& document$formElementArgumentForDefinition, bool createdByParser)
+{
+ const ConstructorFunctionMapEntry& entry = find$parameters{namespace}ElementConstructorFunction(name.localName());
+ if (LIKELY(entry.function))
+ return entry.function($argumentList);
return $parameters{fallbackInterfaceName}::create(name, document);
}
@@ -1065,12 +1100,15 @@
END
;
-print F " static RefPtr<$parameters{namespace}Element> createKnownElement(const QualifiedName&, Document&";
+print F " static RefPtr<$parameters{namespace}Element> createKnownElement(const AtomicString& localName, Document&";
print F ", HTMLFormElement* = nullptr" if $parameters{namespace} eq "HTML";
print F ", bool createdByParser = false);\n\n";
-print F " static Ref<$parameters{namespace}Element> createElement(const QualifiedName&, Document&";
+print F " static Ref<$parameters{namespace}Element> createElement(const AtomicString& localName, Document&";
print F ", HTMLFormElement* = nullptr" if $parameters{namespace} eq "HTML";
print F ", bool createdByParser = false);\n";
+print F " static Ref<$parameters{namespace}Element> createElement(const QualifiedName& localName, Document&";
+print F ", HTMLFormElement* = nullptr" if $parameters{namespace} eq "HTML";
+print F ", bool createdByParser = false);\n";
printf F<<END
};
Modified: trunk/Source/WebCore/html/parser/HTMLConstructionSite.cpp (197462 => 197463)
--- trunk/Source/WebCore/html/parser/HTMLConstructionSite.cpp 2016-03-02 21:42:22 UTC (rev 197462)
+++ trunk/Source/WebCore/html/parser/HTMLConstructionSite.cpp 2016-03-02 21:56:47 UTC (rev 197463)
@@ -28,6 +28,7 @@
#include "HTMLTreeBuilder.h"
#include "Comment.h"
+#include "CustomElementDefinitions.h"
#include "DocumentFragment.h"
#include "DocumentType.h"
#include "Frame.h"
@@ -43,6 +44,7 @@
#include "HTMLPictureElement.h"
#include "HTMLScriptElement.h"
#include "HTMLTemplateElement.h"
+#include "HTMLUnknownElement.h"
#include "NotImplemented.h"
#include "SVGElement.h"
#include "Text.h"
@@ -51,13 +53,18 @@
using namespace HTMLNames;
-static inline void setAttributes(Element& element, AtomicHTMLToken* token, ParserContentPolicy parserContentPolicy)
+static inline void setAttributes(Element& element, Vector<Attribute>& attributes, ParserContentPolicy parserContentPolicy)
{
if (!scriptingContentIsAllowed(parserContentPolicy))
- element.stripScriptingAttributes(token->attributes());
- element.parserSetAttributes(token->attributes());
+ element.stripScriptingAttributes(attributes);
+ element.parserSetAttributes(attributes);
}
+static inline void setAttributes(Element& element, AtomicHTMLToken* token, ParserContentPolicy parserContentPolicy)
+{
+ setAttributes(element, token->attributes(), parserContentPolicy);
+}
+
static bool hasImpliedEndTag(const HTMLStackItem& item)
{
return item.hasTagName(ddTag)
@@ -482,6 +489,26 @@
m_openElements.push(HTMLStackItem::create(element.releaseNonNull(), *token));
}
+#if ENABLE(CUSTOM_ELEMENTS)
+JSCustomElementInterface* HTMLConstructionSite::insertHTMLElementOrFindCustomElementInterface(AtomicHTMLToken* token)
+{
+ JSCustomElementInterface* interface = nullptr;
+ RefPtr<Element> element = createHTMLElementOrFindCustomElementInterface(token, &interface);
+ if (UNLIKELY(interface))
+ return interface;
+ attachLater(¤tNode(), element);
+ m_openElements.push(HTMLStackItem::create(element.releaseNonNull(), *token));
+ return nullptr;
+}
+
+void HTMLConstructionSite::insertCustomElement(Ref<Element>&& element, const AtomicString& localName, Vector<Attribute>& attributes)
+{
+ setAttributes(element.get(), attributes, m_parserContentPolicy);
+ attachLater(¤tNode(), element.ptr());
+ m_openElements.push(HTMLStackItem::create(WTFMove(element), localName, attributes));
+}
+#endif
+
void HTMLConstructionSite::insertSelfClosingHTMLElement(AtomicHTMLToken* token)
{
ASSERT(token->type() == HTMLToken::StartTag);
@@ -633,28 +660,53 @@
return currentNode().document();
}
-Ref<Element> HTMLConstructionSite::createHTMLElement(AtomicHTMLToken* token)
+RefPtr<Element> HTMLConstructionSite::createHTMLElementOrFindCustomElementInterface(
+ AtomicHTMLToken* token, JSCustomElementInterface** customElementInterface)
{
- QualifiedName tagName(nullAtom, token->name(), xhtmlNamespaceURI);
+ auto& localName = token->name();
// 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.
// http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#create-an-element-for-the-token
Document& ownerDocument = ownerDocumentForCurrentNode();
bool insideTemplateElement = !ownerDocument.frame();
- Ref<Element> element = HTMLElementFactory::createElement(tagName, ownerDocument, insideTemplateElement ? nullptr : form(), true);
-
+ RefPtr<Element> element = HTMLElementFactory::createKnownElement(localName, ownerDocument, insideTemplateElement ? nullptr : form(), true);
+ if (UNLIKELY(!element)) {
+
+#if ENABLE(CUSTOM_ELEMENTS)
+ auto* definitions = ownerDocumentForCurrentNode().customElementDefinitions();
+ if (customElementInterface && UNLIKELY(definitions)) {
+ if (auto* interface = definitions->findInterface(localName)) {
+ *customElementInterface = interface;
+ return nullptr;
+ }
+ }
+#else
+ UNUSED_PARAM(customElementInterface);
+#endif
+
+ element = HTMLUnknownElement::create(QualifiedName(nullAtom, localName, xhtmlNamespaceURI), ownerDocumentForCurrentNode());
+ }
+ ASSERT(element);
+
// FIXME: This is a hack to connect images to pictures before the image has
// been inserted into the document. It can be removed once asynchronous image
// loading is working.
- if (is<HTMLPictureElement>(currentNode()) && is<HTMLImageElement>(element))
- downcast<HTMLImageElement>(element.get()).setPictureElement(&downcast<HTMLPictureElement>(currentNode()));
+ if (is<HTMLPictureElement>(currentNode()) && is<HTMLImageElement>(*element))
+ downcast<HTMLImageElement>(*element).setPictureElement(&downcast<HTMLPictureElement>(currentNode()));
- setAttributes(element.get(), token, m_parserContentPolicy);
+ setAttributes(*element, token, m_parserContentPolicy);
ASSERT(element->isHTMLElement());
return element;
}
+Ref<Element> HTMLConstructionSite::createHTMLElement(AtomicHTMLToken* token)
+{
+ RefPtr<Element> element = createHTMLElementOrFindCustomElementInterface(token, nullptr);
+ ASSERT(element);
+ return element.releaseNonNull();
+}
+
Ref<HTMLStackItem> HTMLConstructionSite::createElementFromSavedToken(HTMLStackItem* item)
{
// NOTE: Moving from item -> token -> item copies the Attribute vector twice!
Modified: trunk/Source/WebCore/html/parser/HTMLConstructionSite.h (197462 => 197463)
--- trunk/Source/WebCore/html/parser/HTMLConstructionSite.h 2016-03-02 21:42:22 UTC (rev 197462)
+++ trunk/Source/WebCore/html/parser/HTMLConstructionSite.h 2016-03-02 21:56:47 UTC (rev 197463)
@@ -84,6 +84,7 @@
class Document;
class Element;
class HTMLFormElement;
+class JSCustomElementInterface;
class HTMLConstructionSite {
WTF_MAKE_NONCOPYABLE(HTMLConstructionSite);
@@ -103,6 +104,10 @@
void insertCommentOnDocument(AtomicHTMLToken*);
void insertCommentOnHTMLHtmlElement(AtomicHTMLToken*);
void insertHTMLElement(AtomicHTMLToken*);
+#if ENABLE(CUSTOM_ELEMENTS)
+ JSCustomElementInterface* insertHTMLElementOrFindCustomElementInterface(AtomicHTMLToken*);
+ void insertCustomElement(Ref<Element>&&, const AtomicString& localName, Vector<Attribute>&);
+#endif
void insertSelfClosingHTMLElement(AtomicHTMLToken*);
void insertFormattingElement(AtomicHTMLToken*);
void insertHTMLHeadElement(AtomicHTMLToken*);
@@ -194,6 +199,7 @@
void findFosterSite(HTMLConstructionSiteTask&);
+ RefPtr<Element> createHTMLElementOrFindCustomElementInterface(AtomicHTMLToken*, JSCustomElementInterface**);
Ref<Element> createHTMLElement(AtomicHTMLToken*);
Ref<Element> createElement(AtomicHTMLToken*, const AtomicString& namespaceURI);
Modified: trunk/Source/WebCore/html/parser/HTMLDocumentParser.cpp (197462 => 197463)
--- trunk/Source/WebCore/html/parser/HTMLDocumentParser.cpp 2016-03-02 21:42:22 UTC (rev 197462)
+++ trunk/Source/WebCore/html/parser/HTMLDocumentParser.cpp 2016-03-02 21:56:47 UTC (rev 197463)
@@ -34,6 +34,8 @@
#include "HTMLPreloadScanner.h"
#include "HTMLScriptRunner.h"
#include "HTMLTreeBuilder.h"
+#include "HTMLUnknownElement.h"
+#include "JSCustomElementInterface.h"
namespace WebCore {
@@ -188,8 +190,24 @@
{
ASSERT(scriptingContentIsAllowed(parserContentPolicy()));
+#if ENABLE(CUSTOM_ELEMENTS)
+ if (std::unique_ptr<CustomElementConstructionData> constructionData = m_treeBuilder->takeCustomElementConstructionData()) {
+ ASSERT(!m_treeBuilder->hasParserBlockingScriptWork());
+
+ RefPtr<Element> newElement = constructionData->interface->constructElement(constructionData->name, JSCustomElementInterface::ShouldClearException::Clear);
+ if (!newElement) {
+ // FIXME: This call to docuemnt() is wrong for elements inside a template element.
+ newElement = HTMLUnknownElement::create(QualifiedName(nullAtom, constructionData->name, xhtmlNamespaceURI), *document());
+ }
+
+ m_treeBuilder->didCreateCustomOrCallbackElement(newElement.releaseNonNull(), *constructionData);
+ return;
+ }
+#endif
+
TextPosition scriptStartPosition = TextPosition::belowRangePosition();
if (auto scriptElement = m_treeBuilder->takeScriptToProcess(scriptStartPosition)) {
+ ASSERT(!m_treeBuilder->hasParserBlockingScriptWork());
// We will not have a scriptRunner when parsing a DocumentFragment.
if (m_scriptRunner)
m_scriptRunner->execute(scriptElement.release(), scriptStartPosition);
@@ -459,7 +477,7 @@
// The script runner will hold the script until its loaded and run. During
// any of this time, we want to count ourselves as "waiting for a script" and thus
// run the preload scanner, as well as delay completion of parsing.
- bool treeBuilderHasBlockingScript = m_treeBuilder->hasParserBlockingScript();
+ bool treeBuilderHasBlockingScript = m_treeBuilder->hasParserBlockingScriptWork();
bool scriptRunnerHasBlockingScript = m_scriptRunner && m_scriptRunner->hasParserBlockingScript();
// Since the parser is paused while a script runner has a blocking script, it should
// never be possible to end up with both objects holding a blocking script.
Modified: trunk/Source/WebCore/html/parser/HTMLStackItem.h (197462 => 197463)
--- trunk/Source/WebCore/html/parser/HTMLStackItem.h 2016-03-02 21:42:22 UTC (rev 197462)
+++ trunk/Source/WebCore/html/parser/HTMLStackItem.h 2016-03-02 21:56:47 UTC (rev 197463)
@@ -40,6 +40,7 @@
public:
// Normal HTMLElementStack and HTMLFormattingElementList items.
static Ref<HTMLStackItem> create(Ref<Element>&&, AtomicHTMLToken&, const AtomicString& namespaceURI = HTMLNames::xhtmlNamespaceURI);
+ static Ref<HTMLStackItem> create(Ref<Element>&&, const AtomicString&, const Vector<Attribute>&);
// Document fragment or element for parsing context.
static Ref<HTMLStackItem> create(Element&);
@@ -62,6 +63,7 @@
private:
HTMLStackItem(Ref<Element>&&, AtomicHTMLToken&, const AtomicString& namespaceURI);
+ HTMLStackItem(Ref<Element>&&, const AtomicString& localName, const AtomicString& namespaceURI, const Vector<Attribute>&);
explicit HTMLStackItem(Element&);
explicit HTMLStackItem(DocumentFragment&);
@@ -89,6 +91,21 @@
return adoptRef(*new HTMLStackItem(WTFMove(element), token, namespaceURI));
}
+inline HTMLStackItem::HTMLStackItem(Ref<Element>&& element, const AtomicString& localName, const AtomicString& namespaceURI, const Vector<Attribute>& attributes)
+ : m_node(WTFMove(element))
+ , m_namespaceURI(namespaceURI)
+ , m_localName(localName)
+ , m_attributes(attributes)
+{
+ // FIXME: We should find a way to move the attributes vector in the normal code path instead of copying it.
+}
+
+inline Ref<HTMLStackItem> HTMLStackItem::create(Ref<Element>&& element, const AtomicString& localName, const Vector<Attribute>& attributes)
+{
+ auto& namespaceURI = element.get().namespaceURI();
+ return adoptRef(*new HTMLStackItem(WTFMove(element), localName, namespaceURI, attributes));
+}
+
inline HTMLStackItem::HTMLStackItem(Element& element)
: m_node(element)
, m_namespaceURI(element.namespaceURI())
Modified: trunk/Source/WebCore/html/parser/HTMLTreeBuilder.cpp (197462 => 197463)
--- trunk/Source/WebCore/html/parser/HTMLTreeBuilder.cpp 2016-03-02 21:42:22 UTC (rev 197462)
+++ trunk/Source/WebCore/html/parser/HTMLTreeBuilder.cpp 2016-03-02 21:56:47 UTC (rev 197463)
@@ -34,6 +34,7 @@
#include "HTMLFormElement.h"
#include "HTMLOptGroupElement.h"
#include "HTMLParserIdioms.h"
+#include "JSCustomElementInterface.h"
#include "LocalizedStrings.h"
#include "NotImplemented.h"
#include "XLinkNames.h"
@@ -50,6 +51,19 @@
using namespace HTMLNames;
+#if ENABLE(CUSTOM_ELEMENTS)
+
+CustomElementConstructionData::CustomElementConstructionData(Ref<JSCustomElementInterface>&& interface, const AtomicString& name, const Vector<Attribute>& attributes)
+ : interface(WTFMove(interface))
+ , name(name)
+ , attributes(attributes) // FIXME: Avoid copying attributes.
+{ }
+
+CustomElementConstructionData::~CustomElementConstructionData()
+{ }
+
+#endif
+
namespace {
inline bool isHTMLSpaceOrReplacementCharacter(UChar character)
@@ -896,9 +910,27 @@
}
#endif
m_tree.reconstructTheActiveFormattingElements();
+ insertGenericHTMLElement(token);
+}
+
+inline void HTMLTreeBuilder::insertGenericHTMLElement(AtomicHTMLToken& token)
+{
+#if ENABLE(CUSTOM_ELEMENTS)
+ auto* interface = m_tree.insertHTMLElementOrFindCustomElementInterface(&token);
+ if (UNLIKELY(interface))
+ m_customElementToConstruct = std::make_unique<CustomElementConstructionData>(*interface, token.name(), token.attributes());
+#else
m_tree.insertHTMLElement(&token);
+#endif
}
+#if ENABLE(CUSTOM_ELEMENTS)
+void HTMLTreeBuilder::didCreateCustomOrCallbackElement(Ref<Element>&& element, CustomElementConstructionData& data)
+{
+ m_tree.insertCustomElement(WTFMove(element), data.name, data.attributes);
+}
+#endif
+
#if ENABLE(TEMPLATE_ELEMENT)
void HTMLTreeBuilder::processTemplateStartTag(AtomicHTMLToken& token)
Modified: trunk/Source/WebCore/html/parser/HTMLTreeBuilder.h (197462 => 197463)
--- trunk/Source/WebCore/html/parser/HTMLTreeBuilder.h 2016-03-02 21:42:22 UTC (rev 197462)
+++ trunk/Source/WebCore/html/parser/HTMLTreeBuilder.h 2016-03-02 21:56:47 UTC (rev 197463)
@@ -34,8 +34,20 @@
namespace WebCore {
+class JSCustomElementInterface;
class HTMLDocumentParser;
+#if ENABLE(CUSTOM_ELEMENTS)
+struct CustomElementConstructionData {
+ CustomElementConstructionData(Ref<JSCustomElementInterface>&&, const AtomicString& name, const Vector<Attribute>&);
+ ~CustomElementConstructionData();
+
+ Ref<JSCustomElementInterface> interface;
+ AtomicString name;
+ Vector<Attribute> attributes;
+};
+#endif
+
class HTMLTreeBuilder {
WTF_MAKE_FAST_ALLOCATED;
public:
@@ -49,11 +61,16 @@
void constructTree(AtomicHTMLToken&);
- bool hasParserBlockingScript() const;
+ bool hasParserBlockingScriptWork() const;
// Must be called to take the parser-blocking script before calling the parser again.
RefPtr<Element> takeScriptToProcess(TextPosition& scriptStartPosition);
+#if ENABLE(CUSTOM_ELEMENTS)
+ std::unique_ptr<CustomElementConstructionData> takeCustomElementConstructionData() { return WTFMove(m_customElementToConstruct); }
+ void didCreateCustomOrCallbackElement(Ref<Element>&&, CustomElementConstructionData&);
+#endif
+
// Done, close any open tags, etc.
void finished();
@@ -165,6 +182,8 @@
void resetInsertionModeAppropriately();
+ void insertGenericHTMLElement(AtomicHTMLToken&);
+
#if ENABLE(TEMPLATE_ELEMENT)
void processTemplateStartTag(AtomicHTMLToken&);
bool processTemplateEndTag(AtomicHTMLToken&);
@@ -204,6 +223,10 @@
RefPtr<Element> m_scriptToProcess; // <script> tag which needs processing before resuming the parser.
TextPosition m_scriptToProcessStartPosition; // Starting line number of the script tag needing processing.
+#if ENABLE(CUSTOM_ELEMENTS)
+ std::unique_ptr<CustomElementConstructionData> m_customElementToConstruct;
+#endif
+
bool m_shouldSkipLeadingNewline { false };
bool m_framesetOk { true };
@@ -235,10 +258,15 @@
return !!m_fragmentContext.fragment();
}
-inline bool HTMLTreeBuilder::hasParserBlockingScript() const
+inline bool HTMLTreeBuilder::hasParserBlockingScriptWork() const
{
ASSERT(!m_destroyed);
- return !!m_scriptToProcess;
+#if ENABLE(CUSTOM_ELEMENTS)
+ ASSERT(!(m_scriptToProcess && m_customElementToConstruct));
+ return m_scriptToProcess || m_customElementToConstruct;
+#else
+ return m_scriptToProcess;
+#endif
}
inline DocumentFragment* HTMLTreeBuilder::FragmentParsingContext::fragment() const