Added two layout tests for regression testing.
- fixed <rdar://problem/
4097849> REGRESSION (162-163): importNode creates non-HTML elements, thus style attributes (and some others) don't work
* khtml/xml/dom_docimpl.cpp:
(DocumentImpl::importNode): Reorganized and partly rewrote this. The change that fixes the bug at
hand is to explicitly use XHTML_NAMESPACE for HTML elements, since the old way of getting the namespace
will return the null string for HTML elements, and createElementNS will not create an HTML element
if passed a null string for the namespace.
(DocumentImpl::processHttpEquiv): Removed some bogus getDocument() calls -- no need to call getDocument()
in a document object.
(DocumentImpl::attrName): Ditto.
(DocumentImpl::tagName): Ditto.
(DocumentImpl::setFocusNode): Ditto.
* khtml/html/html_elementimpl.cpp: (HTMLElementImpl::cloneNode): Moved the actual cloning here
from ElementImpl::cloneNode, because XMLElementImpl already had its own version, and in here
we can use createHTMLElement, which will work properly even in an XML document, and is also slightly
more efficient.
* khtml/xml/dom_nodeimpl.h: Added a namespaceURI method function to go along with localName.
* khtml/xml/dom_nodeimpl.cpp: (NodeImpl::namespaceURI): Added. Returns null string to be consistent
with localName (only works on certain types of elements as documented).
* khtml/xml/dom_elementimpl.h: Removed ElementImpl::cloneNode (see above). Added an override of
namespaceURI for XMLElementImpl.
* khtml/xml/dom_elementimpl.cpp: (XMLElementImpl::namespaceURI): Added. Returns the namespace
(consistent with localName).
* layout-tests/fast/dom/importNodeHTML.html: Added. Tests both importNode and cloneNode (for comparison).
* layout-tests/fast/dom/importNodeHTML-expected.txt: Added.
* layout-tests/fast/dom/importNodeXML.xhtml: Added. XML version of the same test as above. Tests a different
code path, so useful to have.
* layout-tests/fast/dom/importNodeXML-expected.txt: Added.
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@9081
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
--- /dev/null
+layer at (0,0) size 800x600
+ RenderCanvas at (0,0) size 800x600
+layer at (0,0) size 800x600
+ RenderBlock {HTML} at (0,0) size 800x600
+ RenderBody {BODY} at (8,8) size 784x584
+ RenderBlock {DIV} at (0,0) size 784x232
+ RenderBlock {P} at (0,0) size 784x18
+ RenderText {TEXT} at (0,0) size 769x18
+ text run at (0,0) width 769: "This is a simple test of both importNode and cloneNode, created from an example that demonstrated a bug in importNode."
+ RenderBlock {DIV} at (0,34) size 784x18 [bgcolor=#FFFF00]
+ RenderText {TEXT} at (0,0) size 116x18
+ text run at (0,0) width 116: "The original node:"
+ RenderBlock {DIV} at (0,52) size 784x48 [bgcolor=#7F7FFF]
+ RenderBlock (anonymous) at (3,3) size 778x18
+ RenderText {TEXT} at (0,0) size 56x18
+ text run at (0,0) width 56: "Outer bit"
+ RenderBlock {DIV} at (6,24) size 772x18 [color=#FFFF00] [bgcolor=#0000FF]
+ RenderText {TEXT} at (0,0) size 57x18
+ text run at (0,0) width 57: "Inner bit."
+ RenderBlock {DIV} at (0,100) size 784x18 [bgcolor=#FFFF00]
+ RenderText {TEXT} at (0,0) size 172x18
+ text run at (0,0) width 172: "Copied with importNode():"
+ RenderBlock {DIV} at (0,118) size 784x48 [bgcolor=#7F7FFF]
+ RenderBlock (anonymous) at (3,3) size 778x18
+ RenderText {TEXT} at (0,0) size 56x18
+ text run at (0,0) width 56: "Outer bit"
+ RenderBlock {DIV} at (6,24) size 772x18 [color=#FFFF00] [bgcolor=#0000FF]
+ RenderText {TEXT} at (0,0) size 57x18
+ text run at (0,0) width 57: "Inner bit."
+ RenderBlock {DIV} at (0,166) size 784x18 [bgcolor=#FFFF00]
+ RenderText {TEXT} at (0,0) size 165x18
+ text run at (0,0) width 165: "Copied with cloneNode():"
+ RenderBlock {DIV} at (0,184) size 784x48 [bgcolor=#7F7FFF]
+ RenderBlock (anonymous) at (3,3) size 778x18
+ RenderText {TEXT} at (0,0) size 56x18
+ text run at (0,0) width 56: "Outer bit"
+ RenderBlock {DIV} at (6,24) size 772x18 [color=#FFFF00] [bgcolor=#0000FF]
+ RenderText {TEXT} at (0,0) size 57x18
+ text run at (0,0) width 57: "Inner bit."
--- /dev/null
+<html>
+ <head>
+ <title>importNode</title>
+ </head>
+ <body>
+ <div id="container">
+ <p>This is a simple test of both importNode and cloneNode, created from an example that demonstrated a bug in importNode.</p>
+ <div style="background: yellow;">The original node:</div>
+ <div id="original" style="background: #7F7FFF; padding: 3px">Outer bit<div style="color: yellow; background: blue; margin: 3px;">Inner bit.</div></div>
+ <div style="background: yellow;">Copied with importNode():</div>
+ <div id="cloneTitle" style="background: yellow;">Copied with cloneNode():</div>
+ <script type="text/javascript">
+ document.getElementById('container').insertBefore(document.importNode(document.getElementById('original'), true), document.getElementById('cloneTitle'));
+ document.getElementById('container').appendChild(document.getElementById('original').cloneNode(true));
+ </script>
+ </div>
+ </body>
+</html>
+
--- /dev/null
+layer at (0,0) size 800x600
+ RenderCanvas at (0,0) size 800x600
+layer at (0,0) size 800x256
+ RenderBlock {HTML} at (0,0) size 800x256
+ RenderBody {BODY} at (8,16) size 784x232
+ RenderBlock {DIV} at (0,0) size 784x232
+ RenderBlock {P} at (0,0) size 784x18
+ RenderText {TEXT} at (0,0) size 769x18
+ text run at (0,0) width 769: "This is a simple test of both importNode and cloneNode, created from an example that demonstrated a bug in importNode."
+ RenderBlock {DIV} at (0,34) size 784x18 [bgcolor=#FFFF00]
+ RenderText {TEXT} at (0,0) size 116x18
+ text run at (0,0) width 116: "The original node:"
+ RenderBlock {DIV} at (0,52) size 784x48 [bgcolor=#7F7FFF]
+ RenderBlock (anonymous) at (3,3) size 778x18
+ RenderText {TEXT} at (0,0) size 56x18
+ text run at (0,0) width 56: "Outer bit"
+ RenderBlock {DIV} at (6,24) size 772x18 [color=#FFFF00] [bgcolor=#0000FF]
+ RenderText {TEXT} at (0,0) size 57x18
+ text run at (0,0) width 57: "Inner bit."
+ RenderBlock {DIV} at (0,100) size 784x18 [bgcolor=#FFFF00]
+ RenderText {TEXT} at (0,0) size 172x18
+ text run at (0,0) width 172: "Copied with importNode():"
+ RenderBlock {DIV} at (0,118) size 784x48 [bgcolor=#7F7FFF]
+ RenderBlock (anonymous) at (3,3) size 778x18
+ RenderText {TEXT} at (0,0) size 56x18
+ text run at (0,0) width 56: "Outer bit"
+ RenderBlock {DIV} at (6,24) size 772x18 [color=#FFFF00] [bgcolor=#0000FF]
+ RenderText {TEXT} at (0,0) size 57x18
+ text run at (0,0) width 57: "Inner bit."
+ RenderBlock {DIV} at (0,166) size 784x18 [bgcolor=#FFFF00]
+ RenderText {TEXT} at (0,0) size 165x18
+ text run at (0,0) width 165: "Copied with cloneNode():"
+ RenderBlock {DIV} at (0,184) size 784x48 [bgcolor=#7F7FFF]
+ RenderBlock (anonymous) at (3,3) size 778x18
+ RenderText {TEXT} at (0,0) size 56x18
+ text run at (0,0) width 56: "Outer bit"
+ RenderBlock {DIV} at (6,24) size 772x18 [color=#FFFF00] [bgcolor=#0000FF]
+ RenderText {TEXT} at (0,0) size 57x18
+ text run at (0,0) width 57: "Inner bit."
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+ <head>
+ <title>importNode</title>
+ </head>
+ <body>
+ <div id="container">
+ <p>This is a simple test of both importNode and cloneNode, created from an example that demonstrated a bug in importNode.</p>
+ <div style="background: yellow;">The original node:</div>
+ <div id="original" style="background: #7F7FFF; padding: 3px">Outer bit<div style="color: yellow; background: blue; margin: 3px;">Inner bit.</div></div>
+ <div style="background: yellow;">Copied with importNode():</div>
+ <div id="cloneTitle" style="background: yellow;">Copied with cloneNode():</div>
+ <script type="text/javascript">
+ document.getElementById('container').insertBefore(document.importNode(document.getElementById('original'), true), document.getElementById('cloneTitle'));
+ document.getElementById('container').appendChild(document.getElementById('original').cloneNode(true));
+ </script>
+ </div>
+ </body>
+</html>
+
+2005-04-29 Darin Adler <darin@apple.com>
+
+ Reviewed by Chris Blumenberg.
+ Added two layout tests for regression testing.
+
+ - fixed <rdar://problem/4097849> REGRESSION (162-163): importNode creates non-HTML elements, thus style attributes (and some others) don't work
+
+ * khtml/xml/dom_docimpl.cpp:
+ (DocumentImpl::importNode): Reorganized and partly rewrote this. The change that fixes the bug at
+ hand is to explicitly use XHTML_NAMESPACE for HTML elements, since the old way of getting the namespace
+ will return the null string for HTML elements, and createElementNS will not create an HTML element
+ if passed a null string for the namespace.
+ (DocumentImpl::processHttpEquiv): Removed some bogus getDocument() calls -- no need to call getDocument()
+ in a document object.
+ (DocumentImpl::attrName): Ditto.
+ (DocumentImpl::tagName): Ditto.
+ (DocumentImpl::setFocusNode): Ditto.
+
+ * khtml/html/html_elementimpl.cpp: (HTMLElementImpl::cloneNode): Moved the actual cloning here
+ from ElementImpl::cloneNode, because XMLElementImpl already had its own version, and in here
+ we can use createHTMLElement, which will work properly even in an XML document, and is also slightly
+ more efficient.
+
+ * khtml/xml/dom_nodeimpl.h: Added a namespaceURI method function to go along with localName.
+ * khtml/xml/dom_nodeimpl.cpp: (NodeImpl::namespaceURI): Added. Returns null string to be consistent
+ with localName (only works on certain types of elements as documented).
+ * khtml/xml/dom_elementimpl.h: Removed ElementImpl::cloneNode (see above). Added an override of
+ namespaceURI for XMLElementImpl.
+ * khtml/xml/dom_elementimpl.cpp: (XMLElementImpl::namespaceURI): Added. Returns the namespace
+ (consistent with localName).
+
+ * layout-tests/fast/dom/importNodeHTML.html: Added. Tests both importNode and cloneNode (for comparison).
+ * layout-tests/fast/dom/importNodeHTML-expected.txt: Added.
+ * layout-tests/fast/dom/importNodeXML.xhtml: Added. XML version of the same test as above. Tests a different
+ code path, so useful to have.
+ * layout-tests/fast/dom/importNodeXML-expected.txt: Added.
+
2005-04-28 Darin Adler <darin@apple.com>
Reviewed by Dave Harrison.
NodeImpl *HTMLElementImpl::cloneNode(bool deep)
{
- HTMLElementImpl *n = static_cast<HTMLElementImpl *>(ElementImpl::cloneNode(deep));
- if (n && m_inlineStyleDecl) {
- *n->getInlineStyleDecl() = *m_inlineStyleDecl;
- }
- return n;
+ HTMLElementImpl *clone = static_cast<HTMLElementImpl *>(getDocument()->createHTMLElement(localNamePart(id())));
+ if (!clone)
+ return 0;
+
+ if (namedAttrMap)
+ *clone->attributes() = *namedAttrMap;
+
+ if (m_inlineStyleDecl)
+ *clone->getInlineStyleDecl() = *m_inlineStyleDecl;
+
+ if (deep)
+ cloneChildNodes(clone);
+
+ return clone;
}
void HTMLElementImpl::attributeChanged(AttributeImpl* attr, bool preserveDecls)
NodeImpl *DocumentImpl::importNode(NodeImpl *importedNode, bool deep, int &exceptioncode)
{
- NodeImpl *result = 0;
-
- if(importedNode->nodeType() == Node::ELEMENT_NODE)
- {
- ElementImpl *tempElementImpl = createElementNS(getDocument()->namespaceURI(id()), importedNode->nodeName(), exceptioncode);
- if (exceptioncode)
- return 0;
- result = tempElementImpl;
-
- if(static_cast<ElementImpl *>(importedNode)->attributes(true) && static_cast<ElementImpl *>(importedNode)->attributes(true)->length())
- {
- NamedNodeMapImpl *attr = static_cast<ElementImpl *>(importedNode)->attributes();
-
- for(unsigned int i = 0; i < attr->length(); i++)
- {
- DOMString qualifiedName = attr->item(i)->nodeName();
- DOMString value = attr->item(i)->nodeValue();
-
- int colonpos = qualifiedName.find(':');
- DOMString localName = qualifiedName;
- if(colonpos >= 0)
- {
- localName.remove(0, colonpos + 1);
- // ### extract and set new prefix
- }
-
- NodeImpl::Id nodeId = getDocument()->attrId(getDocument()->namespaceURI(id()), localName.implementation(), false /* allocate */);
- tempElementImpl->setAttribute(nodeId, value.implementation(), exceptioncode);
-
- if(exceptioncode != 0)
- break;
- }
- }
- }
- else if(importedNode->nodeType() == Node::TEXT_NODE)
- {
- result = createTextNode(importedNode->nodeValue());
- deep = false;
- }
- else if(importedNode->nodeType() == Node::CDATA_SECTION_NODE)
- {
- result = createCDATASection(importedNode->nodeValue());
- deep = false;
- }
- else if(importedNode->nodeType() == Node::ENTITY_REFERENCE_NODE)
- result = createEntityReference(importedNode->nodeName());
- else if(importedNode->nodeType() == Node::PROCESSING_INSTRUCTION_NODE)
- {
- result = createProcessingInstruction(importedNode->nodeName(), importedNode->nodeValue());
- deep = false;
- }
- else if(importedNode->nodeType() == Node::COMMENT_NODE)
- {
- result = createComment(importedNode->nodeValue());
- deep = false;
- }
- else
- exceptioncode = DOMException::NOT_SUPPORTED_ERR;
+ exceptioncode = 0;
- if(deep)
- {
- for(Node n = importedNode->firstChild(); !n.isNull(); n = n.nextSibling())
- result->appendChild(importNode(n.handle(), true, exceptioncode), exceptioncode);
- }
+ switch (importedNode->nodeType()) {
+ case Node::TEXT_NODE:
+ return createTextNode(importedNode->nodeValue());
+ case Node::CDATA_SECTION_NODE:
+ return createCDATASection(importedNode->nodeValue());
+ case Node::ENTITY_REFERENCE_NODE:
+ return createEntityReference(importedNode->nodeName());
+ case Node::PROCESSING_INSTRUCTION_NODE:
+ return createProcessingInstruction(importedNode->nodeName(), importedNode->nodeValue());
+ case Node::COMMENT_NODE:
+ return createComment(importedNode->nodeValue());
+ case Node::ELEMENT_NODE: {
+ ElementImpl *oldElement = static_cast<ElementImpl *>(importedNode);
+ DocumentImpl *oldDoc = oldElement->getDocument();
+ static DOMString HTMLNamespace(XHTML_NAMESPACE);
+ DOMString elementNamespace = oldElement->isHTMLElement() ? HTMLNamespace : oldElement->namespaceURI();
+ ElementImpl *newElement = createElementNS(elementNamespace.implementation(), oldElement->tagName(), exceptioncode);
+ if (exceptioncode != 0)
+ return 0;
+
+ newElement->ref();
+
+ NamedAttrMapImpl *attrs = oldElement->attributes(true);
+ if (attrs) {
+ unsigned length = attrs->length();
+ for (unsigned i = 0; i < length; i++) {
+ AttrImpl *attr = attrs->item(i);
+ DOMString qualifiedName = attr->nodeName();
+ DOMString value = attr->nodeValue();
+
+ int colonpos = qualifiedName.find(':');
+ DOMString localName = qualifiedName;
+ if (colonpos >= 0) {
+ localName.remove(0, colonpos + 1);
+ // ### extract and set new prefix
+ }
+
+ NodeImpl::Id nodeId = attrId(oldDoc->namespaceURI(attr->attrImpl()->id()), localName.implementation(), false /* allocate */);
+ newElement->setAttribute(nodeId, value.implementation(), exceptioncode);
+ if (exceptioncode != 0) {
+ newElement->deref();
+ return 0;
+ }
+ }
+ }
- return result;
+ if (deep) {
+ for (NodeImpl *oldChild = oldElement->firstChild(); oldChild; oldChild = oldChild->nextSibling()) {
+ NodeImpl *newChild = importNode(oldChild, true, exceptioncode);
+ if (exceptioncode != 0) {
+ newElement->deref();
+ return 0;
+ }
+ newElement->appendChild(newChild, exceptioncode);
+ if (exceptioncode != 0) {
+ newElement->deref();
+ return 0;
+ }
+ }
+ }
+
+ // Trick to get the result back to the floating state, with 0 refs but not destroyed.
+ newElement->setParent(this);
+ newElement->deref();
+ newElement->setParent(0);
+
+ return newElement;
+ }
+ }
+
+ exceptioncode = DOMException::NOT_SUPPORTED_ERR;
+ return 0;
}
ElementImpl *DocumentImpl::createElementNS( const DOMString &_namespaceURI, const DOMString &_qualifiedName, int &exceptioncode)
{
assert(!equiv.isNull() && !content.isNull());
- KHTMLPart *part = getDocument()->part();
+ KHTMLPart *part = this->part();
if (strcasecmp(equiv, "default-style") == 0) {
// The preferred style set has been overridden as per section
if ( ok && part )
#if APPLE_CHANGES
// We want a new history item if the refresh timeout > 1 second
- part->scheduleRedirection(delay, getDocument()->completeURL( str ), delay <= 1);
+ part->scheduleRedirection(delay, completeURL( str ), delay <= 1);
#else
- part->scheduleRedirection(delay, getDocument()->completeURL( str ));
+ part->scheduleRedirection(delay, completeURL( str ));
#endif
}
}
// Attribute names are always lowercase in the DOM for both
// HTML and XHTML.
- if (getDocument()->isHTMLDocument() ||
- getDocument()->htmlMode() == DocumentImpl::XHtml)
+ if (isHTMLDocument() || htmlMode() == XHtml)
return result.lower();
return result;
return m_elementNames[localNamePart(_id) - (ID_LAST_TAG + 1)];
else {
// ### put them in a cache
- if (getDocument()->htmlMode() == DocumentImpl::XHtml)
+ if (htmlMode() == XHtml)
return getTagName(_id).lower();
else
return getTagName(_id);
return m_styleSheets;
}
-DOMString
-DocumentImpl::preferredStylesheetSet()
+DOMString DocumentImpl::preferredStylesheetSet()
{
return m_preferredStylesheetSet;
}
-DOMString
-DocumentImpl::selectedStylesheetSet()
+DOMString DocumentImpl::selectedStylesheetSet()
{
return view() ? view()->part()->d->m_sheetUsed : DOMString();
}
// Remove focus from the existing focus node (if any)
if (oldFocusNode) {
// This goes hand in hand with the Qt focus setting below.
- if (!newFocusNode && getDocument()->view()) {
- getDocument()->view()->setFocus();
+ if (!newFocusNode && view()) {
+ view()->setFocus();
}
if (oldFocusNode->active())
m_focusNode->setFocus();
// eww, I suck. set the qt focus correctly
// ### find a better place in the code for this
- if (getDocument()->view()) {
+ if (view()) {
QWidget *focusWidget = widgetForNode(m_focusNode);
if (focusWidget) {
// Make sure a widget has the right size before giving it focus.
// Otherwise, we are testing edge cases of the QWidget code.
// Specifically, in WebCore this does not work well for text fields.
- getDocument()->updateLayout();
+ updateLayout();
// Re-get the widget in case updating the layout changed things.
focusWidget = widgetForNode(m_focusNode);
}
if (focusWidget)
focusWidget->setFocus();
else
- getDocument()->view()->setFocus();
+ view()->setFocus();
}
}
return namedAttrMap && namedAttrMap->length() > 0;
}
-NodeImpl *ElementImpl::cloneNode(bool deep)
-{
- // ### we lose the namespace here ... FIXME
- int exceptioncode;
- ElementImpl *clone = getDocument()->createElement(tagName(), exceptioncode);
- if (!clone) return 0;
-
- // clone attributes
- if (namedAttrMap)
- *clone->attributes() = *namedAttrMap;
-
- if (deep)
- cloneChildNodes(clone);
- return clone;
-}
-
DOMString ElementImpl::nodeName() const
{
return tagName();
return getDocument()->tagName(m_id);
}
+DOMString XMLElementImpl::namespaceURI() const
+{
+ return getDocument()->namespaceURI(m_id);
+}
NodeImpl *XMLElementImpl::cloneNode ( bool deep )
{
// DOM methods overridden from parent classes
virtual DOMString tagName() const;
virtual unsigned short nodeType() const;
- virtual NodeImpl *cloneNode ( bool deep );
+ virtual NodeImpl *cloneNode ( bool deep ) = 0;
virtual DOMString nodeName() const;
virtual bool isElementNode() const { return true; }
virtual void insertedIntoDocument();
~XMLElementImpl();
// DOM methods overridden from parent classes
-
+ virtual DOMString namespaceURI() const;
virtual DOMString localName() const;
virtual NodeImpl *cloneNode ( bool deep );
return DOMString();
}
+DOMString NodeImpl::namespaceURI() const
+{
+ return DOMString();
+}
+
void NodeImpl::setFirstChild(NodeImpl *)
{
}
virtual bool hasChildNodes ( ) const;
virtual NodeImpl *cloneNode ( bool deep ) = 0;
virtual DOMString localName() const;
+ virtual DOMString namespaceURI() const;
virtual DOMString prefix() const;
virtual void setPrefix(const DOMString &_prefix, int &exceptioncode );
void normalize ();