Skip to content

Commit

Permalink
Nested template contents are not cloned by document.importNode
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=137619

Reviewed by Andreas Kling.

Source/WebCore:

The bug was caused by Document.importNode not cloning HTMLTemplateElement's content.

Fixed the bug by sharing code between Document::importNode and Node::cloneNode by
generalizing Node::cloneNodeInternal, added in r177314, by taking the owner document
as an argument. The most of code changes are the result of adding this argument.

Document::importNode is the only function in which the actual logic changes.
Note that the code to import TEXT_NODE, CDATA_SECTION_NODE, ENTITY_REFERENCE_NODE,
PROCESSING_INSTRUCTION_NODE and COMMENT_NODE nodes are identical to that of cloneNode.

This patch removes the call to hasValidNamespaceForElements in ELEMENT_NODE but this
should not introduce an observable behavior change since all instantiated elements
should have a valid namespace in the first place.

Because DOCUMENT_NODE and DOCUMENT_TYPE_NODE cannot be imported and DOCUMENT_TYPE_NODE
can only appear as a direct child of DOCUMENT_NODE, neither nodes nor unimplemented
XPATH_NAMESPACE_NODE and XPATH_NAMESPACE_NODE can appear inside the recursive calls
for ELEMENT_NODE and DOCUMENT_FRAGMENT_NODE nodes.

While importNode behaves differently from cloneNode for ATTRIBUTE_NODE, namely that
it merges all of its child nodes, this behavior isn't present when recursing inside
ELEMENT_NODE and DOCUMENT_FRAGMENT_NODE since we are using cloneDataFromElement.

Thus there should be no observable behavior changes for DOCUMENT_FRAGMENT_NODE and
ELEMENT_NODE nodes either.

Test: fast/dom/HTMLTemplateElement/importNode-nested-templates.html

* dom/Attr.cpp:
(WebCore::Attr::cloneNodeInternal):
* dom/Attr.h:
* dom/CDATASection.cpp:
(WebCore::CDATASection::cloneNodeInternal):
* dom/CDATASection.h:
* dom/Comment.cpp:
(WebCore::Comment::cloneNodeInternal):
* dom/Comment.h:
* dom/ContainerNode.cpp:
(WebCore::ContainerNode::cloneChildNodes):
* dom/Document.cpp:
(WebCore::Document::importNode):
(WebCore::Document::cloneNodeInternal):
* dom/Document.h:
* dom/DocumentFragment.cpp:
(WebCore::DocumentFragment::cloneNodeInternal):
* dom/DocumentFragment.h:
* dom/DocumentType.cpp:
(WebCore::DocumentType::cloneNodeInternal):
* dom/DocumentType.h:
* dom/Element.cpp:
(WebCore::Element::cloneNodeInternal):
(WebCore::Element::cloneElementWithChildren):
(WebCore::Element::cloneElementWithoutChildren):
(WebCore::Element::cloneElementWithoutAttributesAndChildren):
* dom/Element.h:
* dom/EntityReference.cpp:
(WebCore::EntityReference::cloneNodeInternal):
* dom/EntityReference.h:
* dom/Node.h:
(WebCore::Node::cloneNode):
* dom/ProcessingInstruction.cpp:
(WebCore::ProcessingInstruction::cloneNodeInternal):
* dom/ProcessingInstruction.h:
* dom/ShadowRoot.cpp:
(WebCore::ShadowRoot::cloneNodeInternal):
* dom/ShadowRoot.h:
* dom/Text.cpp:
(WebCore::Text::cloneNodeInternal):
* dom/Text.h:
* editing/ApplyStyleCommand.cpp:
(WebCore::ApplyStyleCommand::pushDownInlineStyleAroundNode):
(WebCore::ApplyStyleCommand::applyInlineStyleChange):
* editing/BreakBlockquoteCommand.cpp:
(WebCore::BreakBlockquoteCommand::doApply):
* editing/InsertParagraphSeparatorCommand.cpp:
(WebCore::InsertParagraphSeparatorCommand::cloneHierarchyUnderNewBlock):
(WebCore::InsertParagraphSeparatorCommand::doApply):
* editing/ModifySelectionListLevel.cpp:
(WebCore::IncreaseSelectionListLevelCommand::doApply):
* editing/SplitElementCommand.cpp:
(WebCore::SplitElementCommand::doApply):
* editing/markup.cpp:
(WebCore::createFragmentFromText):
* html/HTMLKeygenElement.cpp:
* html/HTMLScriptElement.cpp:
(WebCore::HTMLScriptElement::cloneElementWithoutAttributesAndChildren):
* html/HTMLScriptElement.h:
* html/HTMLTemplateElement.cpp:
(WebCore::HTMLTemplateElement::cloneNodeInternal):
* html/HTMLTemplateElement.h:
* html/shadow/SliderThumbElement.cpp:
(WebCore::SliderThumbElement::cloneElementWithoutAttributesAndChildren):
* html/shadow/SliderThumbElement.h:
* html/track/WebVTTElement.cpp:
(WebCore::WebVTTElement::cloneElementWithoutAttributesAndChildren):
* html/track/WebVTTElement.h:
* svg/SVGScriptElement.cpp:
(WebCore::SVGScriptElement::cloneElementWithoutAttributesAndChildren):
* svg/SVGScriptElement.h:
* svg/SVGUseElement.cpp:
(WebCore::SVGUseElement::buildShadowTree):
(WebCore::SVGUseElement::expandUseElementsInShadowTree):

LayoutTests:

Added a regression test.

* fast/dom/HTMLTemplateElement/importNode-nested-templates-expected.txt: Added.
* fast/dom/HTMLTemplateElement/importNode-nested-templates.html: Added.


Canonical link: https://commits.webkit.org/157579@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@177372 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
rniwa committed Dec 16, 2014
1 parent 79ceb2f commit a52625e
Show file tree
Hide file tree
Showing 46 changed files with 266 additions and 131 deletions.
12 changes: 12 additions & 0 deletions LayoutTests/ChangeLog
@@ -1,3 +1,15 @@
2014-12-16 Ryosuke Niwa <rniwa@webkit.org>

Nested template contents are not cloned by document.importNode
https://bugs.webkit.org/show_bug.cgi?id=137619

Reviewed by Andreas Kling.

Added a regression test.

* fast/dom/HTMLTemplateElement/importNode-nested-templates-expected.txt: Added.
* fast/dom/HTMLTemplateElement/importNode-nested-templates.html: Added.

2014-12-16 Alexey Proskuryakov <ap@apple.com>

WebKit2 test expectations gardening.
Expand Down
@@ -0,0 +1,22 @@
Test that template contents are cloned when the template element is imported via importNode

On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".


importedOuterTemplate = anotherDocument.importNode(outerTemplate, true)
PASS outerTemplate.ownerDocument is document
PASS importedOuterTemplate.ownerDocument is anotherDocument
PASS importedOuterTemplate.content is not outerTemplate.content
PASS importedOuterTemplate.content.childNodes.length is 1
innerTemplate = outerTemplate.content.firstChild
importedInnerTemplate = importedOuterTemplate.content.firstChild
PASS importedInnerTemplate.outerHTML is innerTemplate.outerHTML
PASS innerTemplate.ownerDocument is not importedInnerTemplate.ownerDocument
PASS importedInnerTemplate.content is not innerTemplate.content
PASS innerTemplate.content.childNodes.length is 1
PASS importedInnerTemplate.content.childNodes.length is 1
PASS innerTemplate.content.firstChild.outerHTML is importedInnerTemplate.content.firstChild.outerHTML
PASS successfullyParsed is true

TEST COMPLETE

@@ -0,0 +1,36 @@
<!DOCTYPE html>
<html>
<body>
<template id="outerTemplate"><template id="innerTemplate"><span>Contents</span></template></template>
<iframe></iframe>
<script src="../../../resources/js-test-pre.js"></script>
<script>

description('Test that template contents are cloned when the template element is imported via importNode');

if (!window.HTMLTemplateElement)
testFailed('This test requires ENABLE(TEMPLATE_ELEMENT)');

var anotherDocument = document.querySelector('iframe').contentDocument;

var outerTemplate = document.getElementById('outerTemplate');
evalAndLog('importedOuterTemplate = anotherDocument.importNode(outerTemplate, true)');
shouldBe('outerTemplate.ownerDocument', 'document');
shouldBe('importedOuterTemplate.ownerDocument', 'anotherDocument');
shouldNotBe('importedOuterTemplate.content', 'outerTemplate.content');
shouldBe('importedOuterTemplate.content.childNodes.length', '1');
evalAndLog('innerTemplate = outerTemplate.content.firstChild');
evalAndLog('importedInnerTemplate = importedOuterTemplate.content.firstChild');
shouldBe('importedInnerTemplate.outerHTML', 'innerTemplate.outerHTML');
shouldNotBe('innerTemplate.ownerDocument', 'importedInnerTemplate.ownerDocument');
shouldNotBe('importedInnerTemplate.content', 'innerTemplate.content');
shouldBe('innerTemplate.content.childNodes.length', '1');
shouldBe('importedInnerTemplate.content.childNodes.length', '1');
shouldBe('innerTemplate.content.firstChild.outerHTML', 'importedInnerTemplate.content.firstChild.outerHTML');

var successfullyParsed = true;

</script>
<script src="../../../resources/js-test-post.js"></script>
</body>
</html>
110 changes: 110 additions & 0 deletions Source/WebCore/ChangeLog
@@ -1,3 +1,113 @@
2014-12-16 Ryosuke Niwa <rniwa@webkit.org>

Nested template contents are not cloned by document.importNode
https://bugs.webkit.org/show_bug.cgi?id=137619

Reviewed by Andreas Kling.

The bug was caused by Document.importNode not cloning HTMLTemplateElement's content.

Fixed the bug by sharing code between Document::importNode and Node::cloneNode by
generalizing Node::cloneNodeInternal, added in r177314, by taking the owner document
as an argument. The most of code changes are the result of adding this argument.

Document::importNode is the only function in which the actual logic changes.
Note that the code to import TEXT_NODE, CDATA_SECTION_NODE, ENTITY_REFERENCE_NODE,
PROCESSING_INSTRUCTION_NODE and COMMENT_NODE nodes are identical to that of cloneNode.

This patch removes the call to hasValidNamespaceForElements in ELEMENT_NODE but this
should not introduce an observable behavior change since all instantiated elements
should have a valid namespace in the first place.

Because DOCUMENT_NODE and DOCUMENT_TYPE_NODE cannot be imported and DOCUMENT_TYPE_NODE
can only appear as a direct child of DOCUMENT_NODE, neither nodes nor unimplemented
XPATH_NAMESPACE_NODE and XPATH_NAMESPACE_NODE can appear inside the recursive calls
for ELEMENT_NODE and DOCUMENT_FRAGMENT_NODE nodes.

While importNode behaves differently from cloneNode for ATTRIBUTE_NODE, namely that
it merges all of its child nodes, this behavior isn't present when recursing inside
ELEMENT_NODE and DOCUMENT_FRAGMENT_NODE since we are using cloneDataFromElement.

Thus there should be no observable behavior changes for DOCUMENT_FRAGMENT_NODE and
ELEMENT_NODE nodes either.

Test: fast/dom/HTMLTemplateElement/importNode-nested-templates.html

* dom/Attr.cpp:
(WebCore::Attr::cloneNodeInternal):
* dom/Attr.h:
* dom/CDATASection.cpp:
(WebCore::CDATASection::cloneNodeInternal):
* dom/CDATASection.h:
* dom/Comment.cpp:
(WebCore::Comment::cloneNodeInternal):
* dom/Comment.h:
* dom/ContainerNode.cpp:
(WebCore::ContainerNode::cloneChildNodes):
* dom/Document.cpp:
(WebCore::Document::importNode):
(WebCore::Document::cloneNodeInternal):
* dom/Document.h:
* dom/DocumentFragment.cpp:
(WebCore::DocumentFragment::cloneNodeInternal):
* dom/DocumentFragment.h:
* dom/DocumentType.cpp:
(WebCore::DocumentType::cloneNodeInternal):
* dom/DocumentType.h:
* dom/Element.cpp:
(WebCore::Element::cloneNodeInternal):
(WebCore::Element::cloneElementWithChildren):
(WebCore::Element::cloneElementWithoutChildren):
(WebCore::Element::cloneElementWithoutAttributesAndChildren):
* dom/Element.h:
* dom/EntityReference.cpp:
(WebCore::EntityReference::cloneNodeInternal):
* dom/EntityReference.h:
* dom/Node.h:
(WebCore::Node::cloneNode):
* dom/ProcessingInstruction.cpp:
(WebCore::ProcessingInstruction::cloneNodeInternal):
* dom/ProcessingInstruction.h:
* dom/ShadowRoot.cpp:
(WebCore::ShadowRoot::cloneNodeInternal):
* dom/ShadowRoot.h:
* dom/Text.cpp:
(WebCore::Text::cloneNodeInternal):
* dom/Text.h:
* editing/ApplyStyleCommand.cpp:
(WebCore::ApplyStyleCommand::pushDownInlineStyleAroundNode):
(WebCore::ApplyStyleCommand::applyInlineStyleChange):
* editing/BreakBlockquoteCommand.cpp:
(WebCore::BreakBlockquoteCommand::doApply):
* editing/InsertParagraphSeparatorCommand.cpp:
(WebCore::InsertParagraphSeparatorCommand::cloneHierarchyUnderNewBlock):
(WebCore::InsertParagraphSeparatorCommand::doApply):
* editing/ModifySelectionListLevel.cpp:
(WebCore::IncreaseSelectionListLevelCommand::doApply):
* editing/SplitElementCommand.cpp:
(WebCore::SplitElementCommand::doApply):
* editing/markup.cpp:
(WebCore::createFragmentFromText):
* html/HTMLKeygenElement.cpp:
* html/HTMLScriptElement.cpp:
(WebCore::HTMLScriptElement::cloneElementWithoutAttributesAndChildren):
* html/HTMLScriptElement.h:
* html/HTMLTemplateElement.cpp:
(WebCore::HTMLTemplateElement::cloneNodeInternal):
* html/HTMLTemplateElement.h:
* html/shadow/SliderThumbElement.cpp:
(WebCore::SliderThumbElement::cloneElementWithoutAttributesAndChildren):
* html/shadow/SliderThumbElement.h:
* html/track/WebVTTElement.cpp:
(WebCore::WebVTTElement::cloneElementWithoutAttributesAndChildren):
* html/track/WebVTTElement.h:
* svg/SVGScriptElement.cpp:
(WebCore::SVGScriptElement::cloneElementWithoutAttributesAndChildren):
* svg/SVGScriptElement.h:
* svg/SVGUseElement.cpp:
(WebCore::SVGUseElement::buildShadowTree):
(WebCore::SVGUseElement::expandUseElementsInShadowTree):

2014-12-16 Tibor Meszaros <tmeszaros.u-szeged@partner.samsung.com>

Document.contentType implementation
Expand Down
4 changes: 2 additions & 2 deletions Source/WebCore/dom/Attr.cpp
Expand Up @@ -137,9 +137,9 @@ void Attr::setNodeValue(const String& v, ExceptionCode& ec)
setValue(v, ec);
}

RefPtr<Node> Attr::cloneNodeInternal(CloningOperation)
RefPtr<Node> Attr::cloneNodeInternal(Document& targetDocument, CloningOperation)
{
RefPtr<Attr> clone = adoptRef(new Attr(document(), qualifiedName(), value()));
RefPtr<Attr> clone = adoptRef(new Attr(targetDocument, qualifiedName(), value()));
cloneChildNodes(clone.get());
return clone.release();
}
Expand Down
2 changes: 1 addition & 1 deletion Source/WebCore/dom/Attr.h
Expand Up @@ -80,7 +80,7 @@ class Attr final : public ContainerNode {

virtual String nodeValue() const override { return value(); }
virtual void setNodeValue(const String&, ExceptionCode&) override;
virtual RefPtr<Node> cloneNodeInternal(CloningOperation) override;
virtual RefPtr<Node> cloneNodeInternal(Document&, CloningOperation) override;

virtual bool isAttributeNode() const override { return true; }
virtual bool childTypeAllowed(NodeType) const override;
Expand Down
4 changes: 2 additions & 2 deletions Source/WebCore/dom/CDATASection.cpp
Expand Up @@ -46,9 +46,9 @@ Node::NodeType CDATASection::nodeType() const
return CDATA_SECTION_NODE;
}

RefPtr<Node> CDATASection::cloneNodeInternal(CloningOperation)
RefPtr<Node> CDATASection::cloneNodeInternal(Document& targetDocument, CloningOperation)
{
return create(document(), data());
return create(targetDocument, data());
}

bool CDATASection::childTypeAllowed(NodeType) const
Expand Down
2 changes: 1 addition & 1 deletion Source/WebCore/dom/CDATASection.h
Expand Up @@ -36,7 +36,7 @@ class CDATASection final : public Text {

virtual String nodeName() const override;
virtual NodeType nodeType() const override;
virtual RefPtr<Node> cloneNodeInternal(CloningOperation) override;
virtual RefPtr<Node> cloneNodeInternal(Document&, CloningOperation) override;
virtual bool childTypeAllowed(NodeType) const override;
virtual RefPtr<Text> virtualCreate(const String&) override;
};
Expand Down
4 changes: 2 additions & 2 deletions Source/WebCore/dom/Comment.cpp
Expand Up @@ -51,9 +51,9 @@ Node::NodeType Comment::nodeType() const
return COMMENT_NODE;
}

RefPtr<Node> Comment::cloneNodeInternal(CloningOperation)
RefPtr<Node> Comment::cloneNodeInternal(Document& targetDocument, CloningOperation)
{
return create(document(), data());
return create(targetDocument, data());
}

bool Comment::childTypeAllowed(NodeType) const
Expand Down
2 changes: 1 addition & 1 deletion Source/WebCore/dom/Comment.h
Expand Up @@ -37,7 +37,7 @@ class Comment final : public CharacterData {

virtual String nodeName() const override;
virtual NodeType nodeType() const override;
virtual RefPtr<Node> cloneNodeInternal(CloningOperation) override;
virtual RefPtr<Node> cloneNodeInternal(Document&, CloningOperation) override;
virtual bool childTypeAllowed(NodeType) const override;
};

Expand Down
5 changes: 3 additions & 2 deletions Source/WebCore/dom/ContainerNode.cpp
Expand Up @@ -765,11 +765,12 @@ void ContainerNode::childrenChanged(const ChildChange& change)
invalidateNodeListAndCollectionCachesInAncestors();
}

void ContainerNode::cloneChildNodes(ContainerNode *clone)
void ContainerNode::cloneChildNodes(ContainerNode* clone)
{
ExceptionCode ec = 0;
Document& targetDocument = clone->document();
for (Node* child = firstChild(); child && !ec; child = child->nextSibling()) {
RefPtr<Node> clonedChild = child->cloneNodeInternal(CloningOperation::SelfWithTemplateContent);
RefPtr<Node> clonedChild = child->cloneNodeInternal(targetDocument, CloningOperation::SelfWithTemplateContent);
clone->appendChild(clonedChild, ec);

if (!ec && is<ContainerNode>(child))
Expand Down
68 changes: 11 additions & 57 deletions Source/WebCore/dom/Document.cpp
Expand Up @@ -923,78 +923,32 @@ RefPtr<CSSStyleDeclaration> Document::createCSSStyleDeclaration()

RefPtr<Node> Document::importNode(Node* importedNode, bool deep, ExceptionCode& ec)
{
ec = 0;

if (!importedNode) {
ec = NOT_SUPPORTED_ERR;
return nullptr;
}

switch (importedNode->nodeType()) {
case ELEMENT_NODE:
case TEXT_NODE:
return createTextNode(importedNode->nodeValue());
case CDATA_SECTION_NODE:
return createCDATASection(importedNode->nodeValue(), ec);
case ENTITY_REFERENCE_NODE:
return createEntityReference(importedNode->nodeName(), ec);
case PROCESSING_INSTRUCTION_NODE:
return createProcessingInstruction(importedNode->nodeName(), importedNode->nodeValue(), ec);
case COMMENT_NODE:
return createComment(importedNode->nodeValue());
case ELEMENT_NODE: {
Element& oldElement = downcast<Element>(*importedNode);
// FIXME: The following check might be unnecessary. Is it possible that
// oldElement has mismatched prefix/namespace?
if (!hasValidNamespaceForElements(oldElement.tagQName())) {
ec = NAMESPACE_ERR;
return nullptr;
}

RefPtr<Element> newElement = createElement(oldElement.tagQName(), false);
newElement->cloneDataFromElement(oldElement);

if (deep) {
for (Node* oldChild = oldElement.firstChild(); oldChild; oldChild = oldChild->nextSibling()) {
RefPtr<Node> newChild = importNode(oldChild, true, ec);
if (ec)
return nullptr;
newElement->appendChild(newChild.release(), ec);
if (ec)
return nullptr;
}
}
case DOCUMENT_FRAGMENT_NODE:
return importedNode->cloneNodeInternal(document(), deep ? CloningOperation::Everything : CloningOperation::OnlySelf);

return newElement.release();
}
case ATTRIBUTE_NODE:
// FIXME: This will "Attr::normalize" child nodes of Attr.
return Attr::create(*this, QualifiedName(nullAtom, downcast<Attr>(*importedNode).name(), nullAtom), downcast<Attr>(*importedNode).value());
case DOCUMENT_FRAGMENT_NODE: {
if (importedNode->isShadowRoot()) {
// ShadowRoot nodes should not be explicitly importable.
// Either they are imported along with their host node, or created implicitly.
break;
}
DocumentFragment& oldFragment = downcast<DocumentFragment>(*importedNode);
RefPtr<DocumentFragment> newFragment = createDocumentFragment();
if (deep) {
for (Node* oldChild = oldFragment.firstChild(); oldChild; oldChild = oldChild->nextSibling()) {
RefPtr<Node> newChild = importNode(oldChild, true, ec);
if (ec)
return nullptr;
newFragment->appendChild(newChild.release(), ec);
if (ec)
return nullptr;
}
}

return newFragment.release();
}

case DOCUMENT_NODE: // Can't import a document into another document.
case DOCUMENT_TYPE_NODE: // FIXME: Support cloning a DocumentType node per DOM4.
break;

case ENTITY_NODE:
// FIXME: It should be possible to import these node types, however in DOM3 the DocumentType is readonly, so there isn't much sense in doing that.
// Ability to add these imported nodes to a DocumentType will be considered for addition to a future release of the DOM.
case DOCUMENT_NODE:
case DOCUMENT_TYPE_NODE:
case XPATH_NAMESPACE_NODE:
ASSERT_NOT_REACHED(); // These two types of DOM nodes are not implemented.
break;
}
ec = NOT_SUPPORTED_ERR;
Expand Down Expand Up @@ -3207,7 +3161,7 @@ bool Document::canReplaceChild(Node* newChild, Node* oldChild)
return true;
}

RefPtr<Node> Document::cloneNodeInternal(CloningOperation type)
RefPtr<Node> Document::cloneNodeInternal(Document&, CloningOperation type)
{
RefPtr<Document> clone = cloneDocumentWithoutChildren();
clone->cloneDataFromDocument(*this);
Expand Down
2 changes: 1 addition & 1 deletion Source/WebCore/dom/Document.h
Expand Up @@ -1311,7 +1311,7 @@ class Document : public ContainerNode, public TreeScope, public ScriptExecutionC
virtual String nodeName() const override final;
virtual NodeType nodeType() const override final;
virtual bool childTypeAllowed(NodeType) const override final;
virtual RefPtr<Node> cloneNodeInternal(CloningOperation) override final;
virtual RefPtr<Node> cloneNodeInternal(Document&, CloningOperation) override final;
void cloneDataFromDocument(const Document&);

virtual void refScriptExecutionContext() override final { ref(); }
Expand Down
4 changes: 2 additions & 2 deletions Source/WebCore/dom/DocumentFragment.cpp
Expand Up @@ -71,9 +71,9 @@ bool DocumentFragment::childTypeAllowed(NodeType type) const
}
}

RefPtr<Node> DocumentFragment::cloneNodeInternal(CloningOperation type)
RefPtr<Node> DocumentFragment::cloneNodeInternal(Document& targetDocument, CloningOperation type)
{
RefPtr<DocumentFragment> clone = create(document());
RefPtr<DocumentFragment> clone = create(targetDocument);
switch (type) {
case CloningOperation::OnlySelf:
case CloningOperation::SelfWithTemplateContent:
Expand Down
2 changes: 1 addition & 1 deletion Source/WebCore/dom/DocumentFragment.h
Expand Up @@ -48,7 +48,7 @@ class DocumentFragment : public ContainerNode {

private:
virtual NodeType nodeType() const override final;
virtual RefPtr<Node> cloneNodeInternal(CloningOperation) override;
virtual RefPtr<Node> cloneNodeInternal(Document&, CloningOperation) override;
virtual bool childTypeAllowed(NodeType) const override;
};

Expand Down

0 comments on commit a52625e

Please sign in to comment.