https://bugs.webkit.org/show_bug.cgi?id=105066
Reviewed by Ojan Vafai.
Source/WebCore:
Cycles in <template> content aren't quite as bad as cycles in normal
DOM trees, but they can easily cause crashes, e.g. in cloneNode and
innerHTML.
Shadow DOM has an analagous issue, and this patch tackles that problem
at the same time by creating a new method, Node::containsIncludingHostElements.
In order to disallow cycles, the HTMLTemplateElement.content
DocumentFragment needs a pointer to its host. The approach here
creates a new subclass with a host pointer and a new virtual method
to DocumentFragment to identify the subclass.
To avoid unnecessary virtual function calls, also changed how
Document::templateContentsOwnerDocument works to allow fast inlined
access and avoid lazy creation when not needed.
Tests: fast/dom/HTMLTemplateElement/cycles-in-shadow.html
fast/dom/HTMLTemplateElement/cycles.html
fast/dom/shadow/shadow-hierarchy-exception.html
* GNUmakefile.list.am:
* Target.pri:
* WebCore.vcproj/WebCore.vcproj:
* WebCore.xcodeproj/project.pbxproj:
* dom/ContainerNode.cpp:
(WebCore::isInTemplateContent):
(WebCore::containsConsideringHostElements):
(WebCore::checkAcceptChild):
* dom/Document.cpp:
(WebCore::Document::ensureTemplateContentsOwnerDocument): Renamed to make clear that it lazily creates the Document. Updated all existing callers to call this method.
* dom/Document.h:
(Document):
(WebCore::Document::templateContentsOwnerDocument): Fast, inlined accessor for use in checkAcceptChild().
* dom/DocumentFragment.h:
(WebCore::DocumentFragment::isTemplateContent):
* dom/Node.cpp:
(WebCore::Node::containsIncludingShadowDOM): made const, simplified
(WebCore::Node::containsIncludingHostElements): Specialized version of Node::contains that knows how to jump over template content boundaries.
* dom/Node.h:
(Node):
* dom/TemplateContentDocumentFragment.h: Added.
(TemplateContentDocumentFragment): Subclass of DocumentFragment which stores its host template element.
(WebCore::TemplateContentDocumentFragment::create):
(WebCore::TemplateContentDocumentFragment::host):
(WebCore::TemplateContentDocumentFragment::TemplateContentDocumentFragment):
* editing/markup.cpp:
(WebCore::createFragmentForInnerOuterHTML):
* html/HTMLTemplateElement.cpp:
(WebCore::HTMLTemplateElement::content): Construct the new subclass.
LayoutTests:
* fast/dom/HTMLTemplateElement/cycles-expected.txt: Added.
* fast/dom/HTMLTemplateElement/cycles-in-shadow-expected.txt: Added.
* fast/dom/HTMLTemplateElement/cycles-in-shadow.html: Added.
* fast/dom/HTMLTemplateElement/cycles.html: Added.
* fast/dom/shadow/shadow-hierarchy-exception-expected.txt: Added.
* fast/dom/shadow/shadow-hierarchy-exception.html: Added.
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@138730
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2013-01-03 Adam Klein <adamk@chromium.org>
+
+ [HTMLTemplateElement] Disallow cycles within template content
+ https://bugs.webkit.org/show_bug.cgi?id=105066
+
+ Reviewed by Ojan Vafai.
+
+ * fast/dom/HTMLTemplateElement/cycles-expected.txt: Added.
+ * fast/dom/HTMLTemplateElement/cycles-in-shadow-expected.txt: Added.
+ * fast/dom/HTMLTemplateElement/cycles-in-shadow.html: Added.
+ * fast/dom/HTMLTemplateElement/cycles.html: Added.
+ * fast/dom/shadow/shadow-hierarchy-exception-expected.txt: Added.
+ * fast/dom/shadow/shadow-hierarchy-exception.html: Added.
+
2013-01-03 Alexis Menard <alexis@webkit.org>
Querying transition-timing-function value on the computed style does not return keywords when it should.
--- /dev/null
+Test that cycles are not allowed in template content
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS template.content.appendChild(template) threw exception Error: HierarchyRequestError: DOM Exception 3.
+PASS template.content.appendChild(outerDiv) threw exception Error: HierarchyRequestError: DOM Exception 3.
+PASS innerDiv.appendChild(template) threw exception Error: HierarchyRequestError: DOM Exception 3.
+PASS innerDiv.appendChild(outerDiv) threw exception Error: HierarchyRequestError: DOM Exception 3.
+PASS innerTemplate.appendChild(outerDiv) threw exception Error: HierarchyRequestError: DOM Exception 3.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+Test that cycle detection traverses over both templates and shadow roots
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS shadowDiv.appendChild(outerDiv) threw exception Error: HierarchyRequestError: DOM Exception 3.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE html>
+<body>
+<script src="../../js/resources/js-test-pre.js"></script>
+<div id=container>
+ <template><div></div></template>
+</div>
+<script>
+description('Test that cycle detection traverses over both templates and shadow roots');
+var outerDiv = document.getElementById('container');
+var template = document.querySelector('template');
+var div = template.content.firstChild;
+var shadowRoot = div.webkitCreateShadowRoot();
+var shadowDiv = shadowRoot.appendChild(document.createElement('div'));
+shouldThrow('shadowDiv.appendChild(outerDiv)');
+</script>
+<script src="../../js/resources/js-test-post.js"></script>
+</body>
--- /dev/null
+<!DOCTYPE html>
+<script src="../../js/resources/js-test-pre.js"></script>
+<script>
+description('Test that cycles are not allowed in template content');
+var template = document.createElement('template');
+shouldThrow('template.content.appendChild(template)');
+var outerDiv = document.createElement('div');
+outerDiv.appendChild(template);
+shouldThrow('template.content.appendChild(outerDiv)');
+var innerDiv = template.content.appendChild(document.createElement('div'));
+shouldThrow('innerDiv.appendChild(template)');
+shouldThrow('innerDiv.appendChild(outerDiv)');
+var innerTemplate = innerDiv.appendChild(document.createElement('template'));
+shouldThrow('innerTemplate.appendChild(outerDiv)');
+</script>
+<script src="../../js/resources/js-test-post.js"></script>
--- /dev/null
+Appending an ancestor to a shadow tree should throw an exception
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS shadowDiv.appendChild(container) threw exception Error: HierarchyRequestError: DOM Exception 3.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
--- /dev/null
+<!DOCTYPE html>
+<script src="../../js/resources/js-test-pre.js"></script>
+<div id=container>
+ <div>
+ <span></span>
+ </div>
+</div>
+<script>
+description('Appending an ancestor to a shadow tree should throw an exception');
+var container = document.getElementById('container');
+var span = container.querySelector('span');
+var shadow = span.webkitCreateShadowRoot();
+var shadowDiv = shadow.appendChild(document.createElement('div'));
+shouldThrow('shadowDiv.appendChild(container)');
+</script>
+<script src="../../js/resources/js-test-post.js"></script>
+2013-01-03 Adam Klein <adamk@chromium.org>
+
+ [HTMLTemplateElement] Disallow cycles within template content
+ https://bugs.webkit.org/show_bug.cgi?id=105066
+
+ Reviewed by Ojan Vafai.
+
+ Cycles in <template> content aren't quite as bad as cycles in normal
+ DOM trees, but they can easily cause crashes, e.g. in cloneNode and
+ innerHTML.
+
+ Shadow DOM has an analagous issue, and this patch tackles that problem
+ at the same time by creating a new method, Node::containsIncludingHostElements.
+
+ In order to disallow cycles, the HTMLTemplateElement.content
+ DocumentFragment needs a pointer to its host. The approach here
+ creates a new subclass with a host pointer and a new virtual method
+ to DocumentFragment to identify the subclass.
+
+ To avoid unnecessary virtual function calls, also changed how
+ Document::templateContentsOwnerDocument works to allow fast inlined
+ access and avoid lazy creation when not needed.
+
+ Tests: fast/dom/HTMLTemplateElement/cycles-in-shadow.html
+ fast/dom/HTMLTemplateElement/cycles.html
+ fast/dom/shadow/shadow-hierarchy-exception.html
+
+ * GNUmakefile.list.am:
+ * Target.pri:
+ * WebCore.vcproj/WebCore.vcproj:
+ * WebCore.xcodeproj/project.pbxproj:
+ * dom/ContainerNode.cpp:
+ (WebCore::isInTemplateContent):
+ (WebCore::containsConsideringHostElements):
+ (WebCore::checkAcceptChild):
+ * dom/Document.cpp:
+ (WebCore::Document::ensureTemplateContentsOwnerDocument): Renamed to make clear that it lazily creates the Document. Updated all existing callers to call this method.
+ * dom/Document.h:
+ (Document):
+ (WebCore::Document::templateContentsOwnerDocument): Fast, inlined accessor for use in checkAcceptChild().
+ * dom/DocumentFragment.h:
+ (WebCore::DocumentFragment::isTemplateContent):
+ * dom/Node.cpp:
+ (WebCore::Node::containsIncludingShadowDOM): made const, simplified
+ (WebCore::Node::containsIncludingHostElements): Specialized version of Node::contains that knows how to jump over template content boundaries.
+ * dom/Node.h:
+ (Node):
+ * dom/TemplateContentDocumentFragment.h: Added.
+ (TemplateContentDocumentFragment): Subclass of DocumentFragment which stores its host template element.
+ (WebCore::TemplateContentDocumentFragment::create):
+ (WebCore::TemplateContentDocumentFragment::host):
+ (WebCore::TemplateContentDocumentFragment::TemplateContentDocumentFragment):
+ * editing/markup.cpp:
+ (WebCore::createFragmentForInnerOuterHTML):
+ * html/HTMLTemplateElement.cpp:
+ (WebCore::HTMLTemplateElement::content): Construct the new subclass.
+
2013-01-02 Jon Lee <jonlee@apple.com>
Revert auto-start plugins to snapshotted plugins after a period of inactivity
Source/WebCore/dom/StyleElement.h \
Source/WebCore/dom/TagNodeList.cpp \
Source/WebCore/dom/TagNodeList.h \
+ Source/WebCore/dom/TemplateContentDocumentFragment.h \
Source/WebCore/dom/Text.cpp \
Source/WebCore/dom/TextEvent.cpp \
Source/WebCore/dom/TextEvent.h \
dom/StyledElement.h \
dom/StyleElement.h \
dom/TagNodeList.h \
+ dom/TemplateContentDocumentFragment.h \
dom/TextEvent.h \
dom/TextEventInputType.h \
dom/Text.h \
RelativePath="..\dom\TagNodeList.h"
>
</File>
+ <File
+ RelativePath="..\dom\TemplateContentDocumentFragment.h"
+ >
+ </File>
<File
RelativePath="..\dom\Text.cpp"
>
C5D4AA7A116BAFB60069CA93 /* GlyphMetricsMap.h in Headers */ = {isa = PBXBuildFile; fileRef = C5D4AA78116BAFB60069CA93 /* GlyphMetricsMap.h */; settings = {ATTRIBUTES = (Private, ); }; };
C5E9B67710697E1300C7BB1A /* StorageEventDispatcher.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C5E9B67610697E1300C7BB1A /* StorageEventDispatcher.cpp */; };
C5EBDD84105EDDEC0056816F /* StorageEventDispatcher.h in Headers */ = {isa = PBXBuildFile; fileRef = C5EBDD81105EDDEC0056816F /* StorageEventDispatcher.h */; };
+ C65046A9167BFB5500CC2A4D /* TemplateContentDocumentFragment.h in Headers */ = {isa = PBXBuildFile; fileRef = C65046A8167BFB5500CC2A4D /* TemplateContentDocumentFragment.h */; };
C6A703325C9D0B6CDCBC4D77 /* JSEventTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C6A703325C9D0B6CDCBC4D78 /* JSEventTarget.cpp */; };
C6B31B2E14F841FB0089F23F /* ScrollbarThemeClient.h in Headers */ = {isa = PBXBuildFile; fileRef = C691614714F6EBA70046375C /* ScrollbarThemeClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
C6D74AD509AA282E000B0A52 /* ModifySelectionListLevel.h in Headers */ = {isa = PBXBuildFile; fileRef = C6D74AD309AA282E000B0A52 /* ModifySelectionListLevel.h */; };
C5EBDD81105EDDEC0056816F /* StorageEventDispatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StorageEventDispatcher.h; sourceTree = "<group>"; };
C5F765B414E1D414006C899B /* PasteboardStrategy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PasteboardStrategy.h; sourceTree = "<group>"; };
C5F765BA14E1ECF4006C899B /* PlatformPasteboardMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PlatformPasteboardMac.mm; sourceTree = "<group>"; };
+ C65046A8167BFB5500CC2A4D /* TemplateContentDocumentFragment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TemplateContentDocumentFragment.h; sourceTree = "<group>"; };
C691614714F6EBA70046375C /* ScrollbarThemeClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScrollbarThemeClient.h; sourceTree = "<group>"; };
C6A703325C9D0B6CDCBC4D78 /* JSEventTarget.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = JSEventTarget.cpp; sourceTree = "<group>"; };
C6D74AD309AA282E000B0A52 /* ModifySelectionListLevel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModifySelectionListLevel.h; sourceTree = "<group>"; };
AA4C3A750B2B1679002334A2 /* StyleElement.h */,
BCE3BEC00D222B1D007E06E4 /* TagNodeList.cpp */,
BCE3BEC10D222B1D007E06E4 /* TagNodeList.h */,
+ C65046A8167BFB5500CC2A4D /* TemplateContentDocumentFragment.h */,
6550B69B099DF0270090D781 /* Text.cpp */,
6550B69C099DF0270090D781 /* Text.h */,
93EEC1F609C2877700C515D1 /* Text.idl */,
A8CFF0510A154F09000A4234 /* TableLayout.h in Headers */,
BCE3BEC30D222B1D007E06E4 /* TagNodeList.h in Headers */,
F55B3DD61251F12D003EF269 /* TelephoneInputType.h in Headers */,
+ C65046A9167BFB5500CC2A4D /* TemplateContentDocumentFragment.h in Headers */,
6550B6A6099DF0270090D781 /* Text.h in Headers */,
93309E17099E64920056E581 /* TextAffinity.h in Headers */,
CE7B2DB51586ABAD0098B3FA /* TextAlternativeWithRange.h in Headers */,
#include "RenderTheme.h"
#include "RenderWidget.h"
#include "RootInlineBox.h"
+#include "TemplateContentDocumentFragment.h"
#include <wtf/CurrentTime.h>
#include <wtf/Vector.h>
return true;
}
+static inline bool isInTemplateContent(const Node* node)
+{
+#if ENABLE(TEMPLATE_ELEMENT)
+ Document* document = node->document();
+ return document && document == document->templateContentsOwnerDocument();
+#else
+ UNUSED(node);
+ return false;
+#endif
+}
+
+static inline bool containsConsideringHostElements(const Node* newChild, const Node* newParent)
+{
+ return (newParent->isInShadowTree() || isInTemplateContent(newParent))
+ ? newChild->containsIncludingHostElements(newParent)
+ : newChild->contains(newParent);
+}
+
static inline ExceptionCode checkAcceptChild(ContainerNode* newParent, Node* newChild, Node* oldChild)
{
// Not mentioned in spec: throw NOT_FOUND_ERR if newChild is null
ASSERT(!newParent->isReadOnlyNode());
ASSERT(!newParent->isDocumentTypeNode());
ASSERT(isChildTypeAllowed(newParent, newChild));
- if (newChild->contains(newParent))
+ if (containsConsideringHostElements(newChild, newParent))
return HIERARCHY_REQUEST_ERR;
return 0;
}
return NO_MODIFICATION_ALLOWED_ERR;
if (newChild->inDocument() && newChild->isDocumentTypeNode())
return HIERARCHY_REQUEST_ERR;
- if (newChild->contains(newParent))
+ if (containsConsideringHostElements(newChild, newParent))
return HIERARCHY_REQUEST_ERR;
if (oldChild && newParent->isDocumentNode()) {
}
#if ENABLE(TEMPLATE_ELEMENT)
-Document* Document::templateContentsOwnerDocument()
+Document* Document::ensureTemplateContentsOwnerDocument()
{
- // If DOCUMENT does not have a browsing context, Let TEMPLATE CONTENTS OWNER be DOCUMENT and abort these steps.
- if (!m_frame)
- return this;
+ if (const Document* document = templateContentsOwnerDocument())
+ return const_cast<Document*>(document);
- if (!m_templateContentsOwnerDocument) {
- if (isHTMLDocument())
- m_templateContentsOwnerDocument = HTMLDocument::create(0, blankURL());
- else
- m_templateContentsOwnerDocument = Document::create(0, blankURL());
- }
+ if (isHTMLDocument())
+ m_templateContentsOwnerDocument = HTMLDocument::create(0, blankURL());
+ else
+ m_templateContentsOwnerDocument = Document::create(0, blankURL());
return m_templateContentsOwnerDocument.get();
}
#endif
#if ENABLE(TEMPLATE_ELEMENT)
- Document* templateContentsOwnerDocument();
+ const Document* templateContentsOwnerDocument() const;
+ Document* ensureTemplateContentsOwnerDocument();
#endif
virtual void addConsoleMessage(MessageSource, MessageLevel, const String& message, unsigned long requestIdentifier = 0);
didRemoveAllPendingStylesheet();
}
+#if ENABLE(TEMPLATE_ELEMENT)
+inline const Document* Document::templateContentsOwnerDocument() const
+{
+ // If DOCUMENT does not have a browsing context, Let TEMPLATE CONTENTS OWNER be DOCUMENT and abort these steps.
+ if (!m_frame)
+ return this;
+
+ return m_templateContentsOwnerDocument.get();
+}
+#endif
+
// Put these methods here, because they require the Document definition, but we really want to inline them.
inline bool Node::isDocumentNode() const
bool parseXML(const String&, Element* contextElement, FragmentScriptingPermission = AllowScriptingContent);
virtual bool canContainRangeEndPoint() const { return true; }
+ virtual bool isTemplateContent() const { return false; }
protected:
DocumentFragment(Document*, ConstructionType = CreateContainer);
#include "DOMImplementation.h"
#include "DOMSettableTokenList.h"
#include "Document.h"
+#include "DocumentFragment.h"
#include "DocumentType.h"
#include "Element.h"
#include "ElementRareData.h"
#include "StorageEvent.h"
#include "StyleResolver.h"
#include "TagNodeList.h"
+#include "TemplateContentDocumentFragment.h"
#include "Text.h"
#include "TextEvent.h"
#include "TreeScopeAdopter.h"
return this == node || node->isDescendantOf(this);
}
-bool Node::containsIncludingShadowDOM(Node* node)
+bool Node::containsIncludingShadowDOM(const Node* node) const
{
- if (!node)
- return false;
- for (Node* n = node; n; n = n->parentOrHostNode()) {
- if (n == this)
+ for (; node; node = node->parentOrHostNode()) {
+ if (node == this)
return true;
}
return false;
}
+bool Node::containsIncludingHostElements(const Node* node) const
+{
+#if ENABLE(TEMPLATE_ELEMENT)
+ while (node) {
+ if (node == this)
+ return true;
+ if (node->isDocumentFragment() && static_cast<const DocumentFragment*>(node)->isTemplateContent())
+ node = static_cast<const TemplateContentDocumentFragment*>(node)->host();
+ else
+ node = node->parentOrHostNode();
+ }
+ return false;
+#else
+ return containsIncludingShadowDOM(node);
+#endif
+}
+
void Node::attach()
{
ASSERT(!attached());
Node* nonBoundaryShadowTreeRootNode();
// Node's parent, shadow tree host.
+ // FIXME: These methods should be renamed parentOrShadowHost*
ContainerNode* parentOrHostNode() const;
Element* parentOrHostElement() const;
void setParentOrHostNode(ContainerNode*);
void checkSetPrefix(const AtomicString& prefix, ExceptionCode&);
bool isDescendantOf(const Node*) const;
bool contains(const Node*) const;
- bool containsIncludingShadowDOM(Node*);
+ bool containsIncludingShadowDOM(const Node*) const;
+ bool containsIncludingHostElements(const Node*) const;
// Used to determine whether range offsets use characters or node indices.
virtual bool offsetInCharacters() const;
--- /dev/null
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TemplateContentDocumentFragment_h
+#define TemplateContentDocumentFragment_h
+
+#if ENABLE(TEMPLATE_ELEMENT)
+
+#include "DocumentFragment.h"
+
+namespace WebCore {
+
+class TemplateContentDocumentFragment : public DocumentFragment {
+public:
+ static PassRefPtr<TemplateContentDocumentFragment> create(Document* document, const Element* host)
+ {
+ return adoptRef(new TemplateContentDocumentFragment(document, host));
+ }
+
+ const Element* host() const { return m_host; }
+
+private:
+ TemplateContentDocumentFragment(Document* document, const Element* host)
+ : DocumentFragment(document, CreateDocumentFragment)
+ , m_host(host)
+ {
+ }
+
+ virtual bool isTemplateContent() const OVERRIDE { return true; }
+
+ const Element* m_host;
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(TEMPLATE_ELEMENT)
+
+#endif // TemplateContentDocumentFragment_h
Document* document = contextElement->document();
#if ENABLE(TEMPLATE_ELEMENT)
if (contextElement->hasTagName(templateTag))
- document = document->templateContentsOwnerDocument();
+ document = document->ensureTemplateContentsOwnerDocument();
#endif
RefPtr<DocumentFragment> fragment = DocumentFragment::create(document);
#include "DOMImplementation.h"
#include "DocumentFragment.h"
#include "HTMLDocument.h"
+#include "TemplateContentDocumentFragment.h"
#include "markup.h"
namespace WebCore {
DocumentFragment* HTMLTemplateElement::content() const
{
if (!m_content)
- m_content = DocumentFragment::create(ownerDocument()->templateContentsOwnerDocument());
+ m_content = TemplateContentDocumentFragment::create(document()->ensureTemplateContentsOwnerDocument(), this);
return m_content.get();
}